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

ALTER TABLE(列存修改列类型)

  • ATExecAlterColumnType 函数
        • 1. 检查和处理列存储表的字符集:
        • 2. 处理自动递增列的数据类型检查:
        • 3. 处理生成列的类型转换检查:
        • 4. 处理生成列的数据类型转换:
    • build_column_default 函数

声明:本文的部分内容参考了他人的文章。在编写过程中,我们尊重他人的知识产权和学术成果,力求遵循合理使用原则,并在适用的情况下注明引用来源。
本文主要参考了 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;// 定义目标数据类型的OIDOid targettype = InvalidOid;// 定义目标类型的修饰符int32 targettypmod = -1;// 定义目标类型的排序规则OIDOid 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 TYPEif (!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))));}}}}} elsedefaultexpr = 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和objectSubIdfoundObject.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);}// 如果仍然没有找到默认值,则返回NULLif (expr == NULL)return NULL;// 如果是自动递增列,将表达式设为常量0if (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;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/31727.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

复杂风控场景(反洗钱)下,一些sql解决方案

前言&#xff1a; 在工作中遇到的一些比较复杂的场景&#xff0c;一直觉得很有记录的价值&#xff0c;但是就是嫌麻烦懒得写&#xff0c;拖延症比较厉害&#xff0c;主要是怕以后忘了&#xff0c;这些问题如果做面试题的话&#xff0c;也很考验人&#xff0c;算是给自己留个备忘…

几种常见的滤波器样式

IIR Peaking Filter IIR LowShelf Filter IIR HighShelf Filter 4. IIR LowPassFilter 5. IIR HighPass Filter FIR PeakingFilter FIR LowShelf Filter 8. FIR HighShelf Filter 8. FIR LowPass Filter 10. FIR HighPass Filter

命令行中,常见mysql命令

打开终端。 连接到 MySQL 服务器&#xff08;假设你的mysql叫root&#xff09;&#xff1a; mysql -u root -p 输入密码&#xff1a; Enter password: ******** 查看所有数据库&#xff1a; mysql> SHOW DATABASES; ERROR 4031 (HY000): The client was disconnected …

操作系统入门 -- 进程的通信方式

操作系统入门 – 进程的通信方式 1.什么是进程通信 1.1 定义 进程通信就是在不同进程之间交换信息。在之前文章中可以了解到&#xff0c;进程之间相互独立&#xff0c;一般不可能互相访问。因此进程之间若需要通信&#xff0c;则需要一个所有进程都认可的共享空间&#xff0…

OpenHarmony-HDF驱动框架介绍及加载过程分析

前言 HarmonyOS面向万物互联时代&#xff0c;而万物互联涉及到了大量的硬件设备&#xff0c;这些硬件的离散度很高&#xff0c;它们的性能差异与配置差异都很大&#xff0c;所以这要求使用一个更灵活、功能更强大、能耗更低的驱动框架。OpenHarmony系统HDF驱动框架采用C语言面…

【Kafka】Kafka Broker工作流程、节点服役与退役、副本、文件存储、高效读写数据-08

【Kafka】Kafka Broker工作流程、节点服役与退役、副本、文件存储、高效读写数据 1. Kafka Broker 工作流程1.1 Zookeeper 存储的 Kafka 信息1.2 Kafka Broker总体工作流程1.2.1 Controller介绍 1.3 Broker 重要参数 2. 节点服役与退役3. Kafka副本 1. Kafka Broker 工作流程 …

GUI Guider(V1.7.2) 设计UI在嵌入式系统上的应用(N32G45XVL-STB)

目录 概述 1 使用GUI Guider 设计UI 1.1 创建页面 1.2 页面切换事件实现 1.3 生成代码和仿真 1.3.1 生成和编译代码 1.3.2 仿真UI 2 GUI Guider生成的代码结构 2.1 代码结构介绍 2.2 Project目录下的文件 3 板卡上移植UI 3.1 加载代码至工程目录 3.2 主函数中调…

【环境变量问题:计算机删除环境变量的恢复方法;此环境变量太大。此对话框允许将值设置为最长2047个字符】

不小心误删了win10系统环境变量可以试试下文方法恢复。 本方法针对修改环境变量未重启的用户可以使用&#xff0c;如果修改环境变量&#xff0c;然后还重启了&#xff0c;只能说重新来。 方法一&#xff1a;使用命令提示符恢复 被修改的系统Path只是同步到了注册表中&#x…

2024软考系规考前复习20问!看看你能答上来多少

今天给大家整理了——2024系统规划与管理师考前20问&#xff0c;这是一份很重要的软考备考必看干货&#xff0c;包含很多核心知识点。有PDF版&#xff0c;可打印下来&#xff0c;过完一遍教材后&#xff0c;来刷一刷、背一背&#xff0c;说不定可以帮你拿下不少分。 第1问- 信息…

python-录音文件转换成文字

大多数语音转文字工具都是要收费的&#xff0c;免费的很少&#xff0c;而且质量也不太高&#xff0c;python有自己的语音识别库&#xff0c;因此尝试使用一下。 先安装库&#xff1a; pip install pydub speechrecognition pip install pydub 安装 ffmpeg brew install ff…

2024.6.23周报

目录 摘要 ABSTRACT 一、文献阅读 一、题目 二、摘要 三、网络架构 四、创新点 五、文章解读 1、Introduction 2、Method 3、实验 4、结论 二、代码实验 总结 摘要 本周阅读了一篇题目为NAS-PINN: NEURAL ARCHITECTURE SEARCH-GUIDED PHYSICS-INFORMED NEURAL N…

解决电脑关机难题:电脑关不了机的原因以及方法

在使用电脑的日常生活中&#xff0c;有时会遇到一些烦人的问题&#xff0c;其中之一就是电脑关不了机。当您尝试关闭电脑时&#xff0c;它可能会停留在某个界面&#xff0c;或者根本不响应关机指令。这种情况不仅令人困惑&#xff0c;还可能导致数据丢失或系统损坏。 在本文中…

DS:堆的应用——两种算法和TOP-K问题

欢迎来到Harper.Lee的学习世界&#xff01;博主主页传送门&#xff1a;Harper.Lee的博客主页想要一起进步的uu可以来后台找我哦&#xff01; 一、堆的排序 1.1 向上调整——建小堆 1.1.1 代码实现 //时间复杂度&#xff1a;O(N*logN) //空间复杂度&#xff1a;O(logN) for (…

计算机网络知识点汇总

计算机网络知识点汇总 第1章计算机网络体系结构 1.1 计算机网络概述 1.1.1 计算机网络的概念 ​ 计算机网络是由若干个结点(node)和连接这些结点的链路(link)组成。网络中的结点可以是就三级、集线器、交换机、或者路由器等&#xff0c;网络之间通过路由器进行互联&#xf…

Nodejs 第七十九章(Kafka进阶)

kafka前置知识在上一章讲过了 不再复述 kafka进阶 1. server.properties配置文件 server.properties是Kafka服务器的配置文件&#xff0c;它用于配置Kafka服务的各个方面&#xff0c;包括网络设置、日志存储、消息保留策略、安全认证 #broker的全局唯一编号&#xff0c;不能…

MySQL数据库初体验+数据库管理(其一)

【1】 操作系统介绍&#xff1a; Linux操作系统有 RedHat CentOS Debian Ubuntu OpenSUSE 信创标准 国产系统 &#xff1a; 华为&#xff08;欧拉&#xff09; 阿里&#xff08;龙蜥&#xff09; 腾讯 &#xff08;tencentOS&#xff09; 麒麟&#xf…

【日记】梦到兄长要给鳄鱼换牙齿……(421 字)

正文 今天中午睡了一个小时多一点&#xff0c;做了一个很奇怪的梦。梦见兄长要给一条鳄鱼换牙齿&#xff0c;还说早上不好操作&#xff0c;要三天之后的中午或晚上&#xff0c;颇有一种翻黄历寻个良辰吉日之感。但我没那样大的耐性&#xff0c;便捏住鳄鱼的嘴&#xff0c;左摔右…

实战18:基于tkinter+jupyter notebook开发的情感分析系统

项目演示: 完整代码: import pandas as pd import numpy as np from collections import Counter import re import jieba from tqdm import tqdm from sklearn.metrics import roc_curve, auc import joblib import gensim from sklearn.svm import SVC from gensim.mode…

STM32小项目———感应垃圾桶

文章目录 前言一、超声波测距1.超声波简介2.超声波测距原理2.超声波测距步骤 二、舵机的控制三、硬件搭建及功能展示总结 前言 一个学习STM32的小白~ 有问题请评论区或私信指出 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、超声波测距 1.超声波…

Studying-代码随想录训练营day16| 513找到左下角的值、112.路径总和、106从中序与后序遍历序列构造二叉树

第十六天&#xff0c;二叉树part03&#x1f4aa;&#x1f4aa;&#x1f4aa;&#xff0c;编程语言&#xff1a;C 目录 513找到左下角的值 112.路径总和 113.路径总和II 106从中序与后序遍历序列构造二叉树 105.从前序与中序遍历序列构造二叉树 总结 513找到左下角的值…