• 【数据库内核分析系列】:数据库表的创建过程


    在数据库中,除了DML之外的所有查询都通过ProcessUtility模块来执行,包括了各类DDL语句、事务相关语句、游标相关语句等。上层调用函数为exec_simple_query函数,其中PortalStart函数和PortalDrop函数部分较为简单。核心函数是PortalRun函数下层调用的standard_ProcessUtility函数,该函数通过switch case语句处理了各种类型的查询语句,包括事务相关查询、游标相关查询、schema相关操作、表空间相关操作、表定义相关操作等。
    standard_ProcessUtility函数会根据nodeTag(parsetree)的值来确定sql的操作类型,create table一般都是进入T_CreateStmt分支,调用CreateCommand函数。

    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)
    {
    ……
        errno_t errorno = EOK;
    switch (nodeTag(parse_tree)) { // 根据nodeTag(parsetree)的值来确定sql的操作类型
    ……
            case T_CreateStmt: { // create table
    #ifdef PGXC
                CreateCommand((CreateStmt*)parse_tree, query_string, params, is_top_level, sent_to_remote, isCTAS);
    #else
                CreateCommand((CreateStmt*)parse_tree, query_string, params, is_top_level, isCTAS);
    #endif
            } break;
    ……
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    在这里插入图片描述

    CreateCommand函数先解析parse_tree获取stmt,如果stmt为空则表明表已经存在。如果stmt不为空对stmts进行遍历,如果是 CreateStmt就调用DefineRelation。AlterTableCreateToastTable判断是否需要创建toast表并创建,AlterCStoreCreateTables判断是否需要创建列存表并创建。

    #ifdef PGXC
    void CreateCommand(CreateStmt *parse_tree, const char *query_string, ParamListInfo params, 
                       bool is_top_level, bool sent_to_remote, bool isCTAS)
    #else
    void CreateCommand(CreateStmt *parse_tree, const char *query_string, ParamListInfo params, bool is_top_level,
        bool isCTAS)
    #endif
    {
    ……
        /* Run parse analysis ... */
        if (u_sess->attr.attr_sql.enable_parallel_ddl) // 先解析parse_tree获取stmt
            stmts = transformCreateStmt((CreateStmt*)parse_tree, query_string, NIL, true, &namespace_id, is_first_node);
        else
            stmts = transformCreateStmt((CreateStmt*)parse_tree, query_string, NIL, false, &namespace_id);
    
        /*
         * If stmts is NULL, then the table is exists.
         * we need record that for searching the group of table.
         */
        if (stmts == NIL) { // 如果stmt为空则表明表已经存在
            table_is_exist = true;
    ……
        /* ... and do it */
        foreach (l, stmts) { // 遍历stmts
            Node* stmt = (Node*)lfirst(l);
    
            if (IsA(stmt, CreateStmt)) {  // 如果是 CreateStmt就调用DefineRelation
                Datum toast_options;
                static const char* const validnsps[] = HEAP_RELOPT_NAMESPACES;
    
                /* forbid user to set or change inner options */
                ForbidOutUsersToSetInnerOptions(((CreateStmt*)stmt)->options);
    
                /* Create the table itself */
                rel_oid = DefineRelation((CreateStmt*)stmt,
                                        ((CreateStmt*)stmt)->relkind == RELKIND_MATVIEW ?
                                                                        RELKIND_MATVIEW : RELKIND_RELATION,
                                        InvalidOid, isCTAS);
    ……
                AlterTableCreateToastTable(rel_oid, toast_options, AccessShareLock);
                AlterCStoreCreateTables(rel_oid, toast_options, (CreateStmt*)stmt);
                AlterDfsCreateTables(rel_oid, toast_options, (CreateStmt*)stmt);
                AlterCreateChainTables(rel_oid, toast_options, (CreateStmt *)stmt);
    ……
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    DefineRelation函数获取到表名relname、名字空间relnamespace、表空间reltablespace、表类型relkind和relpersistence等信息后调用heap_create_with_catalog创建relation。

    (gdb) f 0
    #0  heap_create_with_catalog (relname=0x7fb4fa872140 "t100", relnamespace=2200, reltablespace=0, relid=0, reltypeid=0,
        reloftypeid=0, ownerid=10, tupdesc=0x7fb4ff2e2e50, cooked_constraints=0x0, relkind=114 'r', relpersistence=112 'p',
        shared_relation=false, mapped_relation=false, oidislocal=false, oidinhcount=0, oncommit=ONCOMMIT_NOOP,
        reloptions=140415352057720, use_user_acl=true, allow_system_table_mods=false, partTableState=0x0, row_compress=1 '\001',
        bucketinfo=0x0, record_dependce=true, ceLst=0x0, storage_type=HEAP_DISK, partLockMode=1) at heap.cpp:2521
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    heap_create_with_catalog主要完成表物理文件的创建和表元信息注册到系统表中,涉及系统包包括pg_class,pg_attribute,pg_depend,pg_object,pg_type,pg_index和pg_partition。
    在这里插入图片描述

    其中heap_create内部首先调用了RelationBuildLocalRelation创建RelationData,并加入到relCache,RelationData表示一个表的元信息,这些信息都可以由系统表元组中的信息构造得到。然后根据这些信息通过调用RelalionCreateStorage函数创建物理文件。

    附:创建表create table的函数调用栈
    #0 RelationCreateStorage
    #1 heap_create
    #2 heap_create_with_catalog
    #3 DefineRelation
    #4 CreateCommand
    #5 standard_ProcessUtility
    #6 gsaudit_ProcessUtility_hook
    #7 pgaudit_ProcessUtility
    #8 hypo_utility_hook
    #9 ProcessUtility
    #10 PortalRunUtility
    #11 PortalRunMulti
    #12 PortalRun
    #13 exec_simple_query
    #14 PostgresMain

    openGauss: 一款高性能、高安全、高可靠的企业级开源关系型数据库。

    🍒如果您觉得博主的文章还不错或者有帮助的话,请关注一下博主,如果三连点赞评论收藏就更好啦!谢谢各位大佬给予的支持!

  • 相关阅读:
    Java-注解基础
    Nginx一网打尽:动静分离、压缩、缓存、黑白名单、跨域、高可用、性能优化...想要的这都有!
    【CSDN话题挑战赛】【算法题解】颠倒二进制位
    Net6集成Nacos实现服务注册
    Linux19 --- 线程同步、用户级和内核级线程、互斥锁、信号量、读写锁、条件变量
    mac apktool安装
    情人节程序员用HTML网页表白【爱心表白】 HTML5七夕情人节表白网页源码 HTML+CSS+JavaScript
    部署SeaTunnel单节点Standalone 模式环境
    镍氢充电管理芯片-IC AH2185
    resetFields()报错
  • 原文地址:https://blog.csdn.net/GaussDB/article/details/127743832