一. 前言

        openGauss的alter table操作大体的实现思路为“新建临时表 -> 读取旧表的数据 -> 旧表的数据逐行进行变更计算 -> 变更完后insert到临时表 -> 临时表和变更前的表进行数据文件交换”。 本文走读openGauss的代码了解openGauss中如何实现上述流程的。

二. alter table代码走读

    alter table等DDL操作的入口均为ProcessUtilitySlow,如下的代码走读的核心调用流程:

ProcessUtilitySlow
    lockmode = AlterTableGetLockLevel(atstmt->cmds);
        LOCKMODE lockmode = AccessExclusiveLock;    // 默认8级锁
            GetPartitionLockLevel
                if (PARTITION_DDL_CMD(subType)) {
                    return ShareUpdateExclusiveLock;   // 分区操作为4级锁
                } else {
                    return AccessExclusiveLock;        // 其他操作为8级锁
                }
    rel_id = AlterTableLookupRelation(atstmt, lockmode);   // 原表加8级锁
    stmts = transformAlterTableStmt(rel_id, atstmt, query_string);
        switch (cmd->subtype) {
            ....
            case AT_AlterColumnType:              // 根据alter类型封装成cmd
            ....
        }
    AlterTable(rel_id, lockmode, (AlterTableStmt*)stmt);
        ATController
            ATPrepCmd(&wqueue, rel, cmd, recurse, false, lockmode);   // cmd封装成NewColumnValue
                transform = (Node*)expression_planner((Expr*)transform);  // 类型转换转成expr
                newval->expr = (Expr*)transform
            ATRewriteTables
                ExecRewriteRowTable
                    Oid OIDNewHeap = make_new_heap(tab->relid, NewTableSpace, oldRelLockMode);   // 根据旧表的元数据新建一个临时新表
                    Relation newRel = heap_open(OIDNewHeap, lockmode); // 新表加临时锁
                    ATRewriteTable
                        ATRewriteTableInternal
                            // 逐行读取旧表数据
                            while ((tuple =  (HeapTuple) tableam_scan_getnexttuple(scan, ForwardScanDirection)) != NULL) {
                                tableam_tops_deform_tuple(tuple, oldTupDesc, values, isnull);  // 读取旧的数据
                                // 对于需要重新计算列数据的列进行重新计算,重新计算后的值放在values[x]中
                                foreach (l, tab->newvals) {
                                    // 重新计算列修改后的数据
                                    NewColumnValue *ex = (NewColumnValue*)lfirst(l);
                                    values[ex->attnum - 1] = ExecEvalExpr(ex->exprstate, econtext, &isnull[ex->attnum - 1]);
                                    
                                    // 新的数据写入新的临时表
                                    tableam_tuple_insert(newrel, tuple, mycid, hi_options, bistate);
                                }
                            }
                    finish_heap_swap  // 所有的行完成转换后,将旧表的数据和新临时表的数据做交换
                        swap_relation_files  // 交换新旧表的文件实现数据交换
Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐