【OpenGauss源码学习 —— (ALTER TABLE(列存修改列类型))】

发布于:2024-06-24 ⋅ 阅读:(138) ⋅ 点赞:(0)

声明:本文的部分内容参考了他人的文章。在编写过程中,我们尊重他人的知识产权和学术成果,力求遵循合理使用原则,并在适用的情况下注明引用来源。
本文主要参考了 OpenGauss5.1.0 的开源代码和《OpenGauss数据库源码解析》一书

  在数据库管理中,改变表中列的类型是一个常见的操作。这种操作通常通过ALTER TABLE ALTER COLUMN TYPE语句来实现,它允许数据库管理员在不删除和重新创建表的情况下更改列的数据类型。这种操作需要确保数据的正确性和一致性,并且在某些情况下,还需要重写表中的数据来适应新的数据类型。
  在 OpenGauss 中,函数 ATExecAlterColumnType 用于执行这种列类型的更改。这个函数负责处理列类型变更的所有细节,包括检查新类型的兼容性、处理默认值和约束、以及在必要时重写表的数据。该函数确保在类型更改过程中不会破坏表的完整性和性能。本文将围绕 ATExecAlterColumnType 函数来展开学习列存储修改列类型的过程。

ATExecAlterColumnType 函数

  函数 ATExecAlterColumnTypeOpenGauss 中用于执行 ALTER TABLE ALTER COLUMN TYPE 命令,具体实现了修改表中列的数据类型的操作。该函数首先获取要修改的列和目标数据类型的信息,然后检查是否存在分区键或其他不允许修改的条件。接下来,函数处理该列的默认值和依赖关系(如约束索引等),确保所有相关的依赖关系能够正确更新或重建。随后,函数更新列的数据类型和相关属性(如类型修饰符排序规则等),并在必要时重写列的数据。最后,函数处理新的默认值和约束,并返回该列的新对象地址。这个过程确保了数据类型变更操作的完整性和一致性。

static ObjectAddress ATExecAlterColumnType(AlteredTableInfo* tab, Relation rel, AlterTableCmd* cmd, LOCKMODE lockmode)
{
    // 定义列名称
    char* colName = cmd->name;
    // 定义列的描述信息
    ColumnDef* def = (ColumnDef*)cmd->def;
    // 定义列的数据类型名称
    TypeName* typname = def->typname;
    
    // 定义HeapTuple类型的变量,用于存储系统缓存中检索到的元组
    HeapTuple heapTup;
    // 定义指向列属性结构体的指针,用于存储列的描述信息
    Form_pg_attribute attTup;
    // 定义列号
    AttrNumber attnum;
    
    // 定义HeapTuple类型的变量,用于存储数据类型元组
    HeapTuple typeTuple;
    // 定义指向类型描述结构体的指针
    Form_pg_type tform;
    // 定义目标数据类型的OID
    Oid targettype = InvalidOid;
    // 定义目标类型的修饰符
    int32 targettypmod = -1;
    // 定义目标类型的排序规则OID
    Oid targetcollid = InvalidOid;
    
    // 定义指向默认表达式节点的指针
    Node* defaultexpr = NULL;
    // 定义Relation类型的变量,用于存储属性关系
    Relation attrelation;
    // 定义Relation类型的变量,用于存储依赖关系
    Relation depRel;
    // 定义ScanKeyData数组,用于扫描依赖关系
    ScanKeyData key[3];
    // 定义SysScanDesc类型的变量,用于系统表扫描描述
    SysScanDesc scan;
    // 定义HeapTuple类型的变量,用于存储扫描到的依赖关系元组
    HeapTuple depTup;
    // 定义生成列的标志
    char generatedCol = '\0';
    // 定义指向更新表达式节点的指针
    Node* update_expr = NULL;
    // 定义删除更新时间戳的标志
    bool flagDropOnUpdateTimestamp = false;
    // 定义存在更新时间戳的标志
    bool existOnUpdateTimestamp = false;
    // 定义ObjectAddress类型的变量,用于存储对象地址
    ObjectAddress address;

    // 打开属性表
    attrelation = heap_open(AttributeRelationId, RowExclusiveLock);

    // 查找目标列
    heapTup = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
    if (!HeapTupleIsValid(heapTup)) // 如果找不到列
        ereport(ERROR, (errcode(ERRCODE_UNDEFINED_COLUMN),
                errmsg("column \"%s\" of relation \"%s\" does not exist", colName, RelationGetRelationName(rel))));
    // 获取列的描述信息
    attTup = (Form_pg_attribute)GETSTRUCT(heapTup);
    // 获取列号
    attnum = attTup->attnum;

    // 检查是否为分区表的分区键
    if (RELATION_IS_PARTITIONED(rel) && is_partition_column(rel, attnum)) {
        // 获取分区键
        int2vector* partKey = ((RangePartitionMap*)rel->partMap)->partitionKey;
        int i = 0;

        // 遍历分区键,检查是否为分区列
        for (; i < partKey->dim1; i++) {
            if (attnum == partKey->values[i]) {
                // 如果是分区列,抛出错误,不能修改分区列的数据类型
                ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                        errmsg("cannot alter data type of partitioning column \"%s\"", colName)));
            }
        }

        // 检查是否为子分区表
        if ((rel)->rd_rel->parttype == PARTTYPE_SUBPARTITIONED_RELATION) {
            // 获取父分区的分区列表
            List *partTupleList = searchPgPartitionByParentId(PART_OBJ_TYPE_TABLE_PARTITION, RelationGetRelid(rel));
            if (partTupleList != NIL) {
                bool isnull = false;
                // 获取第一个分区元组
                HeapTuple partTuple = (HeapTuple)linitial(partTupleList);
                // 获取分区键
                Datum datum = SysCacheGetAttr(PARTRELID, partTuple, Anum_pg_partition_partkey, &isnull);
                if (!isnull) {
                    int2vector *subpartkey = (int2vector *)DatumGetPointer(datum);
                    // 遍历子分区键,检查是否为子分区列
                    for (int j = 0; j < subpartkey->dim1; j++) {
                        if (attnum == subpartkey->values[j]) {
                            // 如果是子分区列,抛出错误,不能修改子分区列的数据类型
                            ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                errmsg("cannot alter data type of subpartitioning column \"%s\"", colName)));
                        }
                    }
                }
                // 释放分区列表
                list_free_ext(partTupleList);
            }
        }
    }

    // 检查是否对同一列进行多次ALTER TYPE
    if (!tab->is_first_after) {
        if (attTup->atttypid != tab->oldDesc->attrs[attnum - 1].atttypid ||
            attTup->atttypmod != tab->oldDesc->attrs[attnum - 1].atttypmod)
            ereport(ERROR,
                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot alter type of column \"%s\" twice", colName)));
    }

    // 查找目标类型
    typeTuple = typenameType(NULL, typname, &targettypmod);
    tform = (Form_pg_type)GETSTRUCT(typeTuple);
    targettype = HeapTupleGetOid(typeTuple);
    // 查找目标类型的排序规则
    Oid rel_coll_oid = rel->rd_options == NULL ? InvalidOid : ((StdRdOptions*)(rel)->rd_options)->collate;
    targetcollid = GetColumnDefCollation(NULL, def, targettype, rel_coll_oid);
    if (DB_IS_CMPT(B_FORMAT)) {
        targettype = binary_need_transform_typeid(targettype, &targetcollid);
        if (RelationIsColStore(rel) || RelationIsTsStore(rel)) {
            check_unsupported_charset_for_column(targetcollid, colName);
        }
    }
    if (attnum == RelAutoIncAttrNum(rel)) {
        CheckAutoIncrementDatatype(targettype, colName);
    }
    generatedCol = GetGeneratedCol(rel->rd_att, attnum -1);

    // 检查是否存在默认表达式
    if (attTup->atthasdef) {
        if (RelAutoIncAttrNum(rel) == attnum) {
            defaultexpr = RecookAutoincAttrDefault(rel, attnum, targettype, targettypmod);
            if (defaultexpr == NULL) {
                if (generatedCol == ATTRIBUTE_GENERATED_STORED) {
                    ereport(ERROR, (errmodule(MOD_GEN_COL), errcode(ERRCODE_DATATYPE_MISMATCH),
                        errmsg("generation expression for column \"%s\" cannot be cast automatically to type %s",
                            colName, format_type_be(targettype))));
                } else {
                    ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH),
                        errmsg("default for column \"%s\" cannot be cast automatically to type %s", colName,
                            format_type_be(targettype))));
                }
            }
        } else {
            defaultexpr = build_column_default(rel, attnum);
            if (defaultexpr != NULL) {
                defaultexpr = strip_implicit_coercions(defaultexpr);
                defaultexpr = coerce_to_target_type(NULL,
                    defaultexpr,
                    exprType(defaultexpr),
                    targettype,
                    targettypmod,
                    COERCION_ASSIGNMENT,
                    COERCE_IMPLICIT_CAST,
                    -1);
                if (defaultexpr == NULL) {
                    if (generatedCol == ATTRIBUTE_GENERATED_STORED) {
                        ereport(ERROR, (errmodule(MOD_GEN_COL), errcode(ERRCODE_DATATYPE_MISMATCH),
                            errmsg("generation expression for column \"%s\" cannot be cast automatically to type %s",
                                colName, format_type_be(targettype))));
                    } else {
                        ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH),
                            errmsg("default for column \"%s\" cannot be cast automatically to type %s", colName,
                                format_type_be(targettype))));
                    }
                }
            }
        }
    } else
        defaultexpr = NULL;

    // 查找列的依赖对象(如约束、索引等)
    depRel = heap_open(DependRelationId, RowExclusiveLock);

    // 初始化扫描键,用于查找依赖关系
    ScanKeyInit(
        &key[0], Anum_pg_depend_refclassid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(RelationRelationId));
    ScanKeyInit(
        &key[1], Anum_pg_depend_refobjid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(rel)));
    ScanKeyInit(&key[2], Anum_pg_depend_refobjsubid, BTEqualStrategyNumber, F_INT4EQ, Int32GetDatum((int32)attnum));

    // 开始扫描依赖关系表
    scan = systable_beginscan(depRel, DependReferenceIndexId, true, NULL, 3, key);

    // 循环获取每一个依赖关系元组
    while (HeapTupleIsValid(depTup = systable_getnext(scan))) {
        // 获取依赖关系元组的结构体
        Form_pg_depend foundDep = (Form_pg_depend)GETSTRUCT(depTup);
        ObjectAddress foundObject;

        // 检查依赖类型,如果是固定依赖,则抛出错误
        if (foundDep->deptype == DEPENDENCY_PIN)
            ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot alter type of a pinned column")));

        // 设置找到的对象的classId、objectId和objectSubId
        foundObject.classId = foundDep->classid;
        foundObject.objectId = foundDep->objid;
        foundObject.objectSubId = foundDep->objsubid;

        // 根据对象的类别进行处理
        switch (getObjectClass(&foundObject)) {
            case OCLASS_CLASS: {
                char relKind = get_rel_relkind(foundObject.objectId);

                // 如果是索引或全局索引
                if (relKind == RELKIND_INDEX || relKind == RELKIND_GLOBAL_INDEX) {
                    Assert(foundObject.objectSubId == 0);

                    Oid refobjid;
                    // 如果索引是约束的一部分
                    if (!list_member_oid(tab->changedConstraintOids, foundObject.objectId) &&
                        CheckIndexIsConstraint(depRel, foundObject.objectId, &refobjid)) {
                            tab->changedConstraintOids = lappend_oid(tab->changedConstraintOids, refobjid);
                            tab->changedConstraintDefs =
                                lappend(tab->changedConstraintDefs, pg_get_constraintdef_string(refobjid));
                    // 如果索引不是约束的一部分
                    } else if (!list_member_oid(tab->changedIndexOids, foundObject.objectId)) {
                        LockRelationOid(foundObject.objectId, AccessExclusiveLock);
                        tab->changedIndexOids = lappend_oid(tab->changedIndexOids, foundObject.objectId);
                        tab->changedIndexDefs =
                            lappend(tab->changedIndexDefs, pg_get_indexdef_string(foundObject.objectId));
                    }
                // 如果是序列
                } else if (RELKIND_IS_SEQUENCE(relKind)) {
                    Assert(foundObject.objectSubId == 0);
                // 如果是关系且是生成列
                } else if (relKind == RELKIND_RELATION && foundObject.objectSubId != 0 &&
                    GetGenerated(foundObject.objectId, foundObject.objectSubId)) {
                    ereport(ERROR, (errmodule(MOD_GEN_COL), errcode(ERRCODE_SYNTAX_ERROR),
                        errmsg("cannot alter type of a column used by a generated column"),
                        errdetail("Column \"%s\" is used by generated column \"%s\".", colName,
                        get_attname(foundObject.objectId, foundObject.objectSubId))));
                // 处理其他关系类型
                } else {
                    ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                            errmsg("unexpected object depending on column: %s", getObjectDescription(&foundObject))));
                }
                break;
            }

            // 处理约束
            case OCLASS_CONSTRAINT:
                Assert(foundObject.objectSubId == 0);
                if (!list_member_oid(tab->changedConstraintOids, foundObject.objectId)) {
                    char* defstring = pg_get_constraintdef_string(foundObject.objectId);

                    if (foundDep->deptype == DEPENDENCY_NORMAL) {
                        tab->changedConstraintOids = lcons_oid(foundObject.objectId, tab->changedConstraintOids);
                        tab->changedConstraintDefs = lcons(defstring, tab->changedConstraintDefs);
                    } else {
                        tab->changedConstraintOids = lappend_oid(tab->changedConstraintOids, foundObject.objectId);
                        tab->changedConstraintDefs = lappend(tab->changedConstraintDefs, defstring);
                    }
                }
                break;

            // 处理视图或规则
            case OCLASS_REWRITE:
                ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                        errmsg("cannot alter type of a column used by a view or rule"),
                        errdetail("%s depends on column \"%s\"", getObjectDescription(&foundObject), colName)));
                break;

            // 处理触发器
            case OCLASS_TRIGGER:
                ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                        errmsg("cannot alter type of a column used in a trigger definition"),
                        errdetail("%s depends on column \"%s\"", getObjectDescription(&foundObject), colName)));
                break;

            // 处理默认值
            case OCLASS_DEFAULT:
                break;

            // 处理其他类型
            case OCLASS_PROC:
            case OCLASS_TYPE:
            case OCLASS_CAST:
            case OCLASS_COLLATION:
            case OCLASS_CONVERSION:
            case OCLASS_LANGUAGE:
            case OCLASS_LARGEOBJECT:
            case OCLASS_OPERATOR:
            case OCLASS_OPCLASS:
            case OCLASS_OPFAMILY:
            case OCLASS_AMOP:
            case OCLASS_AMPROC:
            case OCLASS_SCHEMA:
            case OCLASS_TSPARSER:
            case OCLASS_TSDICT:
            case OCLASS_TSTEMPLATE:
            case OCLASS_TSCONFIG:
            case OCLASS_ROLE:
            case OCLASS_DATABASE:
            case OCLASS_TBLSPACE:
            case OCLASS_FDW:
            case OCLASS_FOREIGN_SERVER:
            case OCLASS_USER_MAPPING:
            case OCLASS_DEFACL:
            case OCLASS_EXTENSION:
            case OCLASS_DATA_SOURCE:
            case OCLASS_GLOBAL_SETTING_ARGS:
            case OCLASS_GS_CL_PROC:
                ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                        errmsg("unexpected object depending on column: %s", getObjectDescription(&foundObject))));
                break;

            // 处理未识别的对象类型
            default:
                ereport(ERROR, (errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE),
                        errmsg("unrecognized object class: %u", foundObject.classId)));
        }
    }

    systable_endscan(scan);

    DelDependencONDataType(rel, depRel, attTup);

    heap_close(depRel, RowExclusiveLock);

    // 修改列的类型和排序规则
    attTup->atttypid = targettype;
    attTup->atttypmod = targettypmod;
    attTup->attcollation = targetcollid;
    attTup->attndims = list_length(typname->arrayBounds);
    attTup->attlen = tform->typlen;
    attTup->attbyval = tform->typbyval;
    attTup->attalign = tform->typalign;
    attTup->attstorage = tform->typstorage;

    ReleaseSysCache(typeTuple);

    simple_heap_update(attrelation, &heapTup->t_self, heapTup);

    CatalogUpdateIndexes(attrelation, heapTup);

    heap_close(attrelation, RowExclusiveLock);

    // 为新数据类型和排序规则添加依赖关系
    add_column_datatype_dependency(RelationGetRelid(rel), attnum, targettype);
    add_column_collation_dependency(RelationGetRelid(rel), attnum, targetcollid);

    // 删除统计信息
    if (RELATION_IS_GLOBAL_TEMP(rel)) {
        remove_gtt_att_statistic(RelationGetRelid(rel), attnum);
    } else {
        RemoveStatistics<'c'>(RelationGetRelid(rel), attnum);
    }

    // 处理约束
    if (cmd->subtype == AT_AlterColumnType && def->constraints && def->constraints->head) {
        Constraint* temp_cons = (Constraint*)lfirst(def->constraints->head);
        if (temp_cons->contype == CONSTR_DEFAULT && temp_cons->update_expr != NULL) {
            update_expr = temp_cons->update_expr;
        }
    }

    if (rel->rd_att->constr && rel->rd_att->constr->num_defval > 0) {
        int ndef = rel->rd_att->constr->num_defval -1;
        while (ndef >= 0 && rel->rd_att->constr->defval[ndef].adnum != attnum) {
            --ndef;
        }
        if (ndef >= 0) {
            if (pg_strcasecmp(rel->rd_att->constr->defval[ndef].adbin, "") == 0 &&
                rel->rd_att->constr->defval[ndef].has_on_update) {
                existOnUpdateTimestamp = true;
                if (update_expr == NULL) {
                    CommandCounterIncrement();
                    RemoveAttrDefault(RelationGetRelid(rel), attnum, DROP_RESTRICT, true, true);
                    flagDropOnUpdateTimestamp = true;
                }
            }
        }
    }

    if ((defaultexpr != NULL || update_expr != NULL) && !flagDropOnUpdateTimestamp) {
        CommandCounterIncrement();
        if (defaultexpr != NULL || (update_expr != NULL && existOnUpdateTimestamp)) {
            RemoveAttrDefault(RelationGetRelid(rel), attnum, DROP_RESTRICT, true, true);
        }
        if (update_expr != NULL) {
            ParseState* pstate = make_parsestate(NULL);
            RangeTblEntry*  rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, true);
            addRTEtoQuery(pstate, rte, true, true, true);
            pstate->p_rawdefaultlist = NULL;
            update_expr = cookDefault(pstate, update_expr, attTup->atttypid, attTup->atttypmod,
                attTup->attcollation, NameStr(attTup->attname), def->generatedCol);
        }

        StoreAttrDefault(rel, attnum, defaultexpr, generatedCol, update_expr);
    }
    ObjectAddressSubSet(address, RelationRelationId,
                        RelationGetRelid(rel), attnum);
    tableam_tops_free_tuple(heapTup);
    return address;
}

  在本文中,我们主要关注列存储相关的内容。以上代码中与列存储相关的部分包括以下几处:

1. 检查和处理列存储表的字符集:
// 检查如果表是列存储格式或时间序列存储格式,确保字符集是支持的
if (RelationIsColStore(rel) || RelationIsTsStore(rel)) {
    check_unsupported_charset_for_column(targetcollid, colName);
}
2. 处理自动递增列的数据类型检查:
// 如果列是自动递增列,检查目标数据类型是否兼容
if (attnum == RelAutoIncAttrNum(rel)) {
    CheckAutoIncrementDatatype(targettype, colName);
}
3. 处理生成列的类型转换检查:
// 获取生成列的标志
generatedCol = GetGeneratedCol(rel->rd_att, attnum - 1);

// 检查是否存在默认表达式
if (attTup->atthasdef) {
    // 如果列是自动递增列,重新生成默认表达式
    if (RelAutoIncAttrNum(rel) == attnum) {
        defaultexpr = RecookAutoincAttrDefault(rel, attnum, targettype, targettypmod);
        // 如果生成失败,检查是否是生成列,并报告错误
        if (defaultexpr == NULL) {
            if (generatedCol == ATTRIBUTE_GENERATED_STORED) {
                ereport(ERROR, (errmodule(MOD_GEN_COL), errcode(ERRCODE_DATATYPE_MISMATCH),
                    errmsg("generation expression for column \"%s\" cannot be cast automatically to type %s",
                        colName, format_type_be(targettype))));
            } else {
                ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH),
                    errmsg("default for column \"%s\" cannot be cast automatically to type %s", colName,
                        format_type_be(targettype))));
            }
        }
    }
}
4. 处理生成列的数据类型转换:
// 如果存在默认表达式,处理类型转换
if (attTup->atthasdef) {
    // 构建列的默认表达式
    defaultexpr = build_column_default(rel, attnum);
    if (defaultexpr != NULL) {
        // 去掉隐式转换
        defaultexpr = strip_implicit_coercions(defaultexpr);
        // 将默认表达式转换为目标类型
        defaultexpr = coerce_to_target_type(NULL,
            defaultexpr,
            exprType(defaultexpr),
            targettype,
            targettypmod,
            COERCION_ASSIGNMENT,
            COERCE_IMPLICIT_CAST,
            -1);
        // 如果转换失败,检查是否是生成列,并报告错误
        if (defaultexpr == NULL) {
            if (generatedCol == ATTRIBUTE_GENERATED_STORED) {
                ereport(ERROR, (errmodule(MOD_GEN_COL), errcode(ERRCODE_DATATYPE_MISMATCH),
                    errmsg("generation expression for column \"%s\" cannot be cast automatically to type %s",
                        colName, format_type_be(targettype))));
            } else {
                ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH),
                    errmsg("default for column \"%s\" cannot be cast automatically to type %s", colName,
                        format_type_be(targettype))));
            }
        }
    }
}

build_column_default 函数

  函数 build_column_default 的主要作用是为数据库表中的列创建一个默认值的表达式树。当列没有默认值时,返回 NULL。它首先检查列是否有定义的默认值,如果有,则将字符串形式的默认值转换为节点树。如果列没有默认值且不是生成列,则查找数据类型的默认值。然后,确保默认值被强制转换为目标列的类型。如果启用了自动截断功能且是插入操作,会对默认值进行显式转换。最后,如果表达式中包含 nextval 函数调用,会锁定引用的序列以避免死锁。函数源码如下所示:(路径:gausskernel\optimizer\rewrite\rewriteHandler.cpp

/*
 * 为列的默认值创建表达式树。
 *
 * 如果没有默认值,则返回NULL。
 * 添加一个输入参数isInsertCmd以指示当前语句是否为插入语句。
 * 如果启用了自动截断功能且是插入语句,则使用此参数确定默认值是否需要显式转换。
 */
Node* build_column_default(Relation rel, int attrno, bool isInsertCmd, bool needOnUpdate)
{
    // 获取关系的元组描述信息
    TupleDesc rd_att = rel->rd_att;
    // 获取列的属性元组
    Form_pg_attribute att_tup = &rd_att->attrs[attrno - 1];
    // 获取列的数据类型
    Oid atttype = att_tup->atttypid;
    // 获取列的数据类型修饰符
    int32 atttypmod = att_tup->atttypmod;
    // 定义用于存储表达式的指针
    Node* expr = NULL;
    // 定义表达式的类型
    Oid exprtype;

    /*
     * 查看关系是否有此列的默认值。
     */
    if (rd_att->constr && rd_att->constr->num_defval > 0) {
        // 获取列的默认值数组
        AttrDefault* defval = rd_att->constr->defval;
        // 获取默认值的数量
        int ndef = rd_att->constr->num_defval;

        // 遍历默认值数组
        while (--ndef >= 0) {
            if (attrno == defval[ndef].adnum) {
                /*
                 * 找到默认值,将字符串表示转换为节点树。
                 *
                 * isInsertCmd为false,has_on_update为true且adbin_on_update不为空字符串时,
                 * 将adbin_on_update转换为表达式。
                 * 如果adbin不为空字符串,则将adbin转换为表达式。
                 */
                if (needOnUpdate && (!isInsertCmd) && defval[ndef].adbin_on_update != nullptr &&
                    pg_strcasecmp(defval[ndef].adbin_on_update, "") != 0) {
                    expr = (Node*)stringToNode_skip_extern_fields(defval[ndef].adbin_on_update);
                } else if (defval[ndef].adbin != nullptr && pg_strcasecmp(defval[ndef].adbin, "") != 0) {
                    expr = (Node*)stringToNode_skip_extern_fields(defval[ndef].adbin);
                }
                if (t_thrd.proc->workingVersionNum < LARGE_SEQUENCE_VERSION_NUM) {
                    (void)check_sequence_return_numeric_walker(expr, &(u_sess->opt_cxt.nextval_default_expr_type));
                }
                break;
            }
        }
    }

    // 如果没有找到默认值且不是生成列,则查找数据类型的默认值
    if (expr == NULL && !ISGENERATEDCOL(rd_att, attrno - 1)) {
        expr = get_typdefault(atttype);
    }

    // 如果仍然没有找到默认值,则返回NULL
    if (expr == NULL)
        return NULL;

    // 如果是自动递增列,将表达式设为常量0
    if (IsA(expr, AutoIncrement)) {
        expr = (Node*)makeConst(INT4OID, -1, InvalidOid, sizeof(int32), Int32GetDatum(0), !att_tup->attnotnull, true);
    }

    /*
     * 确保值被强制转换为目标列类型;这通常已经是这样,但在某些涉及域默认值的边缘情况中可能不是真实的。
     * 这应该与解析器对非默认表达式的处理相匹配 --- 参见transformAssignedExpr()。
     */
    exprtype = exprType(expr);

    expr = coerce_to_target_type(NULL, /* 此处没有UNKNOWN参数 */
        expr,
        exprtype,
        atttype,
        atttypmod,
        COERCION_ASSIGNMENT,
        COERCE_IMPLICIT_CAST,
        -1);

    /*
     * 当td_compatible_truncation设置为on时,这部分代码会将列默认值设置为显式转换参数,
     * 以告知bpchar已经对该默认值添加了一个显式转换。
     */
    if (u_sess->attr.attr_sql.td_compatible_truncation && u_sess->attr.attr_sql.sql_compatibility == C_FORMAT &&
        isInsertCmd && (atttype == BPCHAROID || atttype == VARCHAROID) && expr != NULL) {
        AssertEreport(IsA(expr, FuncExpr), MOD_OPT, "");

        FuncExpr* fe = (FuncExpr*)expr;
        Const* const_arg = (Const*)llast(fe->args);
        if (IsA(const_arg, Const) && const_arg->consttype == BOOLOID)
            const_arg->constvalue = (Datum) true;
    }

    // 如果表达式为空,报告错误
    if (expr == NULL)
        ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH),
            errmsg("column \"%s\" is of type %s but %s expression is of type %s", NameStr(att_tup->attname),
            format_type_be(atttype), ISGENERATEDCOL(rd_att, attrno - 1) ? "generated column" : "deault",
            format_type_be(exprtype)), errhint("You will need to rewrite or cast the expression.")));
    
    /*
     * 如果表达式中有nextval函数调用,应该锁定引用的序列以避免死锁,
     * 这在transformFuncExpr中已经完成。详见lockNextvalOnCn。
     */
    (void)lockNextvalWalker(expr, NULL);

    return expr;
}

网站公告

今日签到

点亮在社区的每一天
去签到