openGauss核心分析(九):資料庫表的建立過程

小侃資料庫發表於2023-03-14

除了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;
……

image.png

CreateCommand函式先解析parse_tree獲取stmt,如果stmt為空則表明表已經存在。如果stmt不為空對stmts進行遍歷,如果是 CreateStmt就呼叫DefineRelation。AlterTableCreateToastTable判斷是否需要建立toast表並建立,AlterCStoreCreateTables判斷是否需要建立列存表並建立。

#ifdef PGXCvoid CreateCommand(CreateStmt *parse_tree, const char *query_string, ParamListInfo params,
                   bool is_top_level, bool sent_to_remote, bool isCTAS)#elsevoid 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);
……

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

其中heap_create內部首先呼叫了RelationBuildLocalRelation建立RelationData,並加入到relCache,RelationData表示一個表的元資訊,這些資訊都可以由系統表元組中的資訊構造得到。然後根據這些資訊透過呼叫RelalionCreateStorage函式建立物理檔案。heap_create_with_catalog主要完成表物理檔案的建立和表元資訊註冊到系統表中,涉及系統包包括pg_class,pg_attribute,pg_depend,pg_object,pg_type,pg_index和pg_partition。

image.png

附:建立表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

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70023856/viewspace-2939606/,如需轉載,請註明出處,否則將追究法律責任。

相關文章