Skip to content

PG源码学习

memory

cpp
int main(int argc, char *argv[])
{
    MemoryContextInit();

    PostmasterMain(argc, argv);
}

void MemoryContextInit(void)
{
    TopMemoryContext = AllocSetContextCreate(
        (MemoryContext) NULL,
        "TopMemoryContext",
        ALLOCSET_DEFAULT_SIZES);

    CurrentMemoryContext = TopMemoryContext;

    ErrorContext = AllocSetContextCreate(
        TopMemoryContext,
        "ErrorContext",
        8 * 1024,
        8 * 1024,
        8 * 1024);
}

void InitializeGUCOptions(void)
{
    build_guc_variables()
}

void build_guc_variables(void)
{
    GUCMemoryContext = AllocSetContextCreate(
        TopMemoryContext,
        "GUCMemoryContext",
        ALLOCSET_DEFAULT_SIZES);
}

void PostmasterMain(int argc, char *argv[]){
    PostmasterContext = AllocSetContextCreate(
        TopMemoryContext,
        "Postmaster",
        ALLOCSET_DEFAULT_SIZES);

    MemoryContextSwitchTo(PostmasterContext);

    InitializeGUCOptions();
}

PostgresMain(){
    MessageContext = AllocSetContextCreate(
        TopMemoryContext,
        "MessageContext",
        ALLOCSET_DEFAULT_SIZES);
}

PostgreSQL进程

  • Postmaster 守护进程:PostmasterMain:调度中心
  • Postgres 服务进程:PostgresMain:处理查询
  • 辅助进程
    • SysLogger:系统日志进程
    • PgStat 统计数据收集进程
    • AutoVacuum 系统自动清理
    • AutoVacLauncherMain 监控进程
    • AutoVacWorkerMain 执行清理进程
    • BackgroundWriter:后台写进程:定期将存放普通数据的共享缓冲区写入磁盘
    • WalWriter:预写日志写进程:定期将存放预写日志的WAL缓冲区写入磁盘
    • PgArchiver:预写日志归档进程:对WAL日志归档备份
    • BackgroundWorker

辅助进程启动流程:

cpp
main()
{
    PostmasterMain()
    {
        // syslogger进程启动流程
        StartSysLogger() {
            SysLogger_Start() {
                postmaster_child_launch(B_LOGGER){
                    SysLoggerMain()
                }
            }
        }

        // BackgroundWriter
        StartChildProcess(B_BG_WRITER){
            postmaster_child_launch(B_BG_WRITER){
                BackgroundWriterMain()
            }
        }

        // bgworker进程启动流程
        maybe_start_bgworkers(){
            StartBackgroundWorker(){
                postmaster_child_launch(B_BG_WORKER){
                    BackgroundWorkerMain()
                }
            }
        }

        ServerLoop(){
            // AutoVacWorkerMain
            process_pm_pmsignal(){
                StartAutovacuumWorker(){
                    StartChildProcess(B_AUTOVAC_WORKER){
                        postmaster_child_launch(B_AUTOVAC_WORKER){
                            AutoVacWorkerMain()
                        }
                    }
                }
            }

            // BackendMain
            BackendStartup(){
                postmaster_child_launch(B_BACKEND){
                    BackendMain(){
                        PostgresMain()
                    }
                }
            }

            LaunchMissingBackgroundProcesses(){
                // WalWriterMain
                StartChildProcess(B_WAL_WRITER){
                    postmaster_child_launch(B_WAL_WRITER){
                        WalWriterMain()
                    }
                }
                // AutoVacLauncherMain
                StartChildProcess(B_AUTOVAC_LAUNCHER){
                    postmaster_child_launch(B_WAL_WRITER){
                        AutoVacLauncherMain()
                    }
                }
                // PgArchiverMain
                StartChildProcess(B_ARCHIVER){
                    postmaster_child_launch(B_ARCHIVER){
                        PgArchiverMain()
                    }
                }
            }
        }
    }
}

多用户模式参数:IsUnderPostmaster

cpp
// src/backend/utils/init/globals.c
bool IsUnderPostmaster = false;

// src/backend/postmaster/launch_backend.c
postmaster_child_launch(){
    InitPostmasterChild(void){
        bool IsUnderPostmaster = true;
    }
}

系统表

  • pg_namespace 命名空间
  • pg_tablespace 表空间
  • pg_database 数据库信息
  • pg_type 数据类型
  • pg_class 表对象信息
  • pg_attribute 表属性信息
  • pg_index 索引信息
  • pg_statistic 统计信息

初始化过程

3个默认系统数据库

数据库作用
template1模板数据库,可修改
template0用于备份
postgres用于连接

Portal执行过程

cpp
CreatePortal()       // 创建portal
PortalDefineQuery()  // 设置部分字段
PortalStart()        // 初始化portal
PortalRun()          // 调用portal执行过程
PortalDrop()         // 调用portal清理过程

SQL语句分类

SQL语句类型操作范围处理模块
数据定义语句 DDL statement,功能性操作元组以外功能处理器 Utility Processor
可优化语句 Optimizable statement元组相关执行器 Executor

数据定义语句

以建表语句为例

sql
create table t1(id int, age int);

调用栈

cpp
start(){
main(){
PostmasterMain(){
ServerLoop(){
BackendStartup(){
postmaster_child_launch(){
BackendMain(){
PostgresMain(){
exec_simple_query(){
    pg_parse_query() // 解析
    pg_analyze_and_rewrite_fixedparams() // 分析和重写查询树
    pg_plan_queries() // 生成查询计划

    CreatePortal()     // 创建portal
    PortalDefineQuery() // 设置部分字段
    PortalStart(){     // 初始化portal
        // 策略选择PORTAL_MULTI_QUERY
        ChoosePortalStrategy() 
    }
    
    PortalRun(){       // 调用portal执行过程
        PortalRunMulti(){
        PortalRunUtility(){
        ProcessUtility(){ // 功能处理器函数
        standard_ProcessUtility(){
        ProcessUtilitySlow(){
            // 对T_CreateStmt 节点进行转换处理
            transformCreateStmt() 
            DefineRelation(){
                // 创建物理文件并在相应系统表中注册
                heap_create_with_catalog(){
                    heap_create(){
                        // 创建物理文件
                        RelationCreateStorage()
                    }
                    // 向表中pg_type新增一条记录
                    AddNewRelationType()
                    // 将表的相关信息存入pg_class
                    AddNewRelationTuple()
                    // 将表的属性存入pg_attribute
                    AddNewAttributeTuples()
                    // 将约束存入pg_constraint
                    // 将默认值存入g_attrdef
                    StoreConstraints()
                }
            }
        }
    }
    PortalDrop() // 调用portal清理过程
}}}}}}}}}}}}}

常见的数据定义语句处理函数

节点类型核心处理函数功能
T_CreateStmtDefineRelation创建关系表

可优化语句

计划节点继承体系

cpp
// src/include/nodes/plannodes.h
Plan
    /* 控制节点 control node */
    Result
    ProjectSet
    ModifyTable
    Append
    MergeAppend
    RecursiveUnion
    BitmapAnd
    BitmapOr

    /* 扫描节点 scan node */
    Scan
        SeqScan
        SampleScan
        IndexScan
        IndexOnlyScan
        BitmapIndexScan
        BitmapHeapScan
        TidScan
        TidRangeScan
        SubqueryScan
        FunctionScan
        ValuesScan
        TableFuncScan
        CteScan
        NamedTuplestoreScan
        WorkTableScan
        ForeignScan
        CustomScan

    /* 连接节点 join node */
    Join
        NestLoop
        MergeJoin
        HashJoin

    /* 物化节点 meterialzation node */
    Material
    Memoize
    Sort
        IncrementalSort
    Group
    Agg
    WindowAgg
    Unique
    Gather
    GatherMerge
    Hash
    SetOp
    LockRows
    Limit

状态节点继承体系

cpp
// src/include/nodes/execnodes.h
PlanState
    ResultState
    ProjectSetState
    ModifyTableState
    AppendState
    MergeAppendState
    RecursiveUnionState
    BitmapAndState
    BitmapOrState
    ScanState
        SeqScanState
        SampleScanState
        IndexScanState
        IndexOnlyScanState
        BitmapIndexScanState
        BitmapHeapScanState
        TidScanState
        TidRangeScanState
        SubqueryScanState
        FunctionScanState
        ValuesScanState
        TableFuncScanState
        CteScanState
        NamedTuplestoreScanState
        WorkTableScanState
        ForeignScanState
        CustomScanState
        MaterialState
        MemoizeState
        SortState
        IncrementalSortState
        GroupState
        AggState
        WindowAggState
    JoinState
        NestLoopState
        MergeJoinState
        HashJoinState
    UniqueState
    GatherState
    GatherMergeState
    HashState
    SetOpState
    LockRowsState
    LimitState

执行器执行过程中涉及的主要数据结构

cpp
/* query descriptor */
typedef struct QueryDesc
{
    /* These fields are provided by CreateQueryDesc */
    // 语句类型
    CmdType        operation;        /* CMD_SELECT, CMD_UPDATE, etc. */
    // 查询计划树
    PlannedStmt *plannedstmt;    /* planner's output (could be utility, too) */
    // 查询语句
    const char *sourceText;        /* source text of the query */

    /* These fields are set by ExecutorStart */

    TupleDesc    tupDesc;        /* descriptor for result tuples */
    // 执行器全局状态
    EState       *estate;            /* executor's query-wide state */
    // 计划节点执行状态
    PlanState  *planstate;        /* tree of per-plan-node state */
} QueryDesc;


// PlannedStmt node
typedef struct PlannedStmt
{
    NodeTag        type;

    // 语句类型
    CmdType        commandType;    /* select|insert|update|delete|merge|utility */

    uint64        queryId;        /* query identifier (copied from Query) */

    // 查询计划树根节点
    struct Plan *planTree;        /* tree of Plan nodes */

    // 查询涉及的范围表
    List       *rtable;            /* list of RangeTblEntry nodes */

    /* rtable indexes of target relations for INSERT/UPDATE/DELETE/MERGE */
    // 结果关系表
    List       *resultRelations;    /* integer list of RT indexes, or NIL */

    Node       *utilityStmt;    /* non-null if this is utility stmt */

} PlannedStmt;


/* Executor state */
typedef struct EState
{
    NodeTag        type;
    // 查询涉及的范围表
    List       *es_range_table; /* List of RangeTblEntry */
    
    /* Other working state: */
    // EState内存上下文
    MemoryContext es_query_cxt; /* per-query context in which EState lives */

    // 用于节点之间传递元组的全局元组表
    List       *es_tupleTable;    /* List of TupleTableSlots */

    /*
     * this ExprContext is for per-output-tuple operations, such as constraint
     * checks and index-value computations.  It will be reset for each output
     * tuple.  Note that it will be created only if needed.
     */
    // 每获取一个元组就会回收的内存上下文
    ExprContext *es_per_tuple_exprcontext;

} EState;


/* PlanState node */
typedef struct PlanState
{

    NodeTag        type;

    // 计划节点指针
    Plan       *plan;            /* associated Plan node */

    // 执行器全局状态指针
    EState       *state;            /* at execution time, states of individual
                                 * nodes point to one EState for the whole
                                 * top-level plan */

    /*
     * Common structural data for all Plan types.  These links to subsidiary
     * state trees parallel links in the associated plan tree (except for the
     * subPlan list, which does not exist in the plan tree).
     */
    //  选择运算相关条件
    ExprState  *qual;            /* boolean qual condition */

    // 左右子树状态节点指针
    struct PlanState *lefttree; /* input plan tree(s) */
    struct PlanState *righttree;
} PlanState;

执行器运行

cpp
exec_simple_query(const char *query_string){
    
    // 词法语法分析
    List<RawStmt> *parsetree_list = pg_parse_query(const char *query_string);

    foreach(ListCell *parsetree_item, parsetree_list) {
        RawStmt *parsetree = lfirst_node(RawStmt, parsetree_item);

        List<Query> *querytree_list = pg_analyze_and_rewrite_fixedparams(RawStmt *parsetree)
        List<PlannedStmt> *plantree_list = pg_plan_queries(List *querytree_list)

        // portal阶段
        Portal portal = CreatePortal("", true, true);
        PortalDefineQuery(Portal portal, List *plantree_list)

        PortalStart(Portal portal){
            // 执行策略选择
            PortalStrategy portal->strategy = ChoosePortalStrategy(List *portal->stmts);
            switch (portal->strategy)
            {
                case PORTAL_ONE_SELECT:
                    // 创建QueryDesc
                    QueryDesc *queryDesc = CreateQueryDesc(PlannedStmt *plannedstmt)
                    ExecutorStart(QueryDesc *queryDesc){
                        // 对执行器进行必要初始化
                        standard_ExecutorStart(QueryDesc *queryDesc){
                            // 构造EState
                            EState *estate = CreateExecutorState();
                            queryDesc->estate = estate;

                            // 构造PlanState
                            InitPlan(QueryDesc *queryDesc){
                                // 递归处理查询计划树每个节点,转为对应的状态节点树
                                PlanState *planstate = ExecInitNode(Plan *node, EState *estate);
                                queryDesc->planstate = planstate;
                            }
                        }
                    }

                    portal->queryDesc = queryDesc;
            }
        }

        PortalRun(Portal portal){
            switch (portal->strategy){
                case PORTAL_ONE_SELECT:
                    PortalRunSelect(Portal portal){
                        ExecutorRun(QueryDesc *queryDesc){
                            standard_ExecutorRun(QueryDesc *queryDesc){
                                ExecutePlan(EState *estate, PlanState *planstate){
                                    for (;;){
                                        ExecProcNode(PlanState *node)
                                    }
                                }
                            }
                        }
                    }
            }
        }

        PortalDrop(Portal portal){
            PortalCleanup(Portal portal){
                // 清理执行器内部
                ExecutorEnd(QueryDesc *queryDesc){
                    standard_ExecutorEnd(QueryDesc *queryDesc){
                        // 处理执行状态树根节点已分配的资源
                        ExecEndPlan(PlanState *planstate, EState *estate){
                            ExecEndNode(PlanState *node)
                        }
                        // 释放执行器全局状态EState
                        FreeExecutorState(EState *estate)
                    }
                }

                // 释放QueryDesc
                FreeQueryDesc(QueryDesc *queryDesc);
            }
        }
    }
}

执行示例

sql
-- 课程信息
drop table if exists tb_course;
create table tb_course(
    no int, 
    name varchar(20)
);

-- 教师信息
drop table if exists tb_teacher;
create table tb_teacher(
    no int,
    name varchar(20),
    sex int
);

-- 教师任课信息
drop table if exists tb_teacher_course;
create table tb_teacher_course(
    tno int,
    cno int,
    stu_num int
);

-- 数据
insert into tb_course (no, name) values(1, 'math');
insert into tb_course (no, name) values(2, 'chinese');
insert into tb_course (no, name) values(3, 'english');

insert into tb_teacher (no, name, sex) values(1, 'Tom', 1);
insert into tb_teacher (no, name, sex) values(2, 'Jack', 1);
insert into tb_teacher (no, name, sex) values(3, 'Steve', 0);

insert into tb_teacher_course (tno, cno, stu_num) values(1, 1, 50);
insert into tb_teacher_course (tno, cno, stu_num) values(1, 2, 55);
insert into tb_teacher_course (tno, cno, stu_num) values(2, 3, 56);
insert into tb_teacher_course (tno, cno, stu_num) values(2, 2, 57);
insert into tb_teacher_course (tno, cno, stu_num) values(3, 1, 58);

-- 查询
select t.name, c.name, stu_num
from tb_course as c, tb_teacher_course as tc, tb_teacher as t
where c.no = tc.cno and t.no = tc.tno and c.name = 'math' and t.name = 'Tom';

查看计划

sql
explain select t.name, c.name, stu_num
from tb_course as c, tb_teacher_course as tc, tb_teacher as t
where c.no = tc.cno and t.no = tc.tno and c.name = 'math' and t.name = 'Tom';

                                     QUERY PLAN
-------------------------------------------------------------------------------------
 Hash Join  (cost=42.10..80.72 rows=1 width=120)
   Hash Cond: (tc.tno = t.no)
   ->  Hash Join  (cost=21.30..59.76 rows=41 width=66)
         Hash Cond: (tc.cno = c.no)
         ->  Seq Scan on tb_teacher_course tc  (cost=0.00..30.40 rows=2040 width=12)
         ->  Hash  (cost=21.25..21.25 rows=4 width=62)
               ->  Seq Scan on tb_course c  (cost=0.00..21.25 rows=4 width=62)
                     Filter: ((name)::text = 'math'::text)
   ->  Hash  (cost=20.75..20.75 rows=4 width=62)
         ->  Seq Scan on tb_teacher t  (cost=0.00..20.75 rows=4 width=62)
               Filter: ((name)::text = 'Tom'::text)
(11 rows)

parsetree_list

querytree_list

plantree_list

计划节点

节点类型说明
控制节点处理特殊情况的节点
扫描节点扫描表
物化节点缓存执行结果
连接节点实现连接算法

控制节点

Result

cpp
// src/include/nodes/execnodes.h
typedef struct ResultState
{
    PlanState    ps;                /* its first field is NodeTag */
    // 常量表达式
    ExprState  *resconstantqual;
    // 节点是否处理完所有元组
    bool        rs_done;        /* are we done? */
    // 标记是否需要计算常量表达式
    bool        rs_checkqual;    /* do we need to check the qual? */
} ResultState;
select 1 * 2
sql
db_test=# explain select 1 * 2;
                QUERY PLAN
------------------------------------------
 Result  (cost=0.00..0.01 rows=1 width=4)
(1 row)

扫描节点

物化节点

连接节点

连接类型(t1 join t2为例)

连接类型解释说明
Inner Join内连接t1, t2
Left Outer Join左连接t1, t2(NULL)
Right Outer Join右连接t1(NULL), t2
Full Outer Join全外连接t1(NULL), t2(NULL)
Semi JoinInt1
Anti JoinNot Int1

连接操作

连接操作节点类型文件描述
嵌套循环连接NestLoopnodeNestloop.c嵌套循环算法
归并连接MergeJoinnodeMergejoin.c归并连接算法
Hash连接HashJoinnodeHashjoin.cHybird Hash连接算法

typedef struct Join { pg_node_attr(abstract)

Plan plan; JoinType jointype; bool inner_unique; List joinqual; / JOIN quals (in addition to plan.qual) */ } Join;

NestLoop

cpp
typedef struct NestLoop
{
  Join    join;
  List     *nestParams;    /* list of NestLoopParam nodes */
} NestLoop;

元组操作

使用元组存储所有信息,包括各种系统信息,数据等

TupleTable

继承体系

cpp
// src/include/executor/tuptable.h
TupleTableSlot
    VirtualTupleTableSlot      // 虚拟元组
    HeapTupleTableSlot         // 物理元组
    BufferHeapTupleTableSlot   // 缓冲区物理元组
    MinimalTupleTableSlot       // 精简的物理元组

表达式节点

处理SQL语句中的函数调用、计算式和条件表达式时需要用到表达式计算

Expr 的继承体系

cpp
Expr
    Var
    Const
    Param
    Aggref
    GroupingFunc
    WindowFunc
    WindowFuncRunCondition
    MergeSupportFunc
    SubscriptingRef
    FuncExpr
    NamedArgExpr
    OpExpr
    ScalarArrayOpExpr
    BoolExpr
    SubLink
    SubPlan
    AlternativeSubPlan
    FieldSelect
    FieldStore
    RelabelType
    CoerceViaIO
    ArrayCoerceExpr
    ConvertRowtypeExpr
    CollateExpr
    CaseExpr
    CaseWhen
    CaseTestExpr
    ArrayExpr
    RowExpr
    RowCompareExpr
    CoalesceExpr
    MinMaxExpr
    SQLValueFunction
    XmlExpr
    JsonConstructorExpr
    JsonExpr
    NullTest
    BooleanTest
    CoerceToDomain
    CoerceToDomainValue
    SetToDefault
    CurrentOfExpr
    NextValueExpr
    InferenceElem
    TargetEntry

小结

SQL语句处理

SQL语句分类处理函数
可优化语句Executor
数据描述语句ProcessUtility

Portal对外接口:

  • PortalStart
  • PortalRun
  • PortalEnd

分页存储

大数据存储

2种大数据存储的方式:

  • TOAST:(The Oversized-Attribute Storage Technique)超尺寸字段存储技巧,使用数据压缩和线外存储实现
  • 大对象:使用一个专门的系统表(pg_largeobject)来存储大对象数据

TOAST 和 大对象比较

不同点TOAST大对象
触发方式自动触发(2k)手动调用
数据丢失不能丢失允许丢失
存储对象字符串文件
存储机制线外和压缩直接存储

表操作

创建表并插入数据

sql
-- 教师信息
drop table if exists tb_teacher;
create table tb_teacher(
    no int,
    name varchar(20),
    sex int
);

insert into tb_teacher (no, name, sex) values(1, 'Tom', 1);
insert into tb_teacher (no, name, sex) values(2, 'Jack', 1);
insert into tb_teacher (no, name, sex) values(3, 'Steve', 0);

打开关闭表

头文件

cpp
// src/include/access/relation.h

// 根据OID打开表
extern Relation relation_open(Oid relationId, LOCKMODE lockmode);

extern Relation try_relation_open(Oid relationId, LOCKMODE lockmode);

// 根据表名打开表
extern Relation relation_openrv(const RangeVar *relation, LOCKMODE lockmode);

extern Relation relation_openrv_extended(const RangeVar *relation,
    LOCKMODE lockmode, bool missing_ok);

// 关闭表
extern void relation_close(Relation relation, LOCKMODE lockmode);

示例:打开表,并输出字段名

cpp
#include "access/relation.h"
#include "utils/rel.h"

Relation rel;
TupleDesc tupdesc;
char *column_name;

// 查询表的oid
// select oid, relname from pg_class where relname = 'tb_teacher';
rel = relation_open(24644, AccessShareLock);

tupdesc = RelationGetDescr(rel);

for (int i = 0; i < tupdesc->natts; i++)
{
    Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
    column_name = pstrdup(NameStr(attr->attname));
    ereport(LOG, (errmsg("column_name: %s", column_name)));
}

relation_close(rel, AccessShareLock);
cpp
typedef struct TupleDescData
{
  // 元组属性个数
  int      natts;      /* number of attributes in the tuple */
  //   元组的复合类型ID
  Oid      tdtypeid;    /* composite type ID for tuple type */
//   元组模式
  int32    tdtypmod;    /* typmod for tuple type */
//   该元组描述符的引用计数,只有引用计数为0,该元组描述符才能被删除
  int      tdrefcount;    /* reference count, or -1 if not counting */
  // 数组表示元素的约束条件,从pg_constraint系统表中读取,每个元素表示一个约束条件
  TupleConstr *constr;    /* constraints, or NULL if none */
  /* attrs[N] is the description of Attribute Number N+1 */
  // 数组表示元组每个属性的相关信息,从pg_attribute系统表读取,每个元素表示一个属性
  FormData_pg_attribute attrs[FLEXIBLE_ARRAY_MEMBER];
}      TupleDescData;
typedef struct TupleDescData *TupleDesc;

扫描表

头文件

cpp
// src/include/access/tableam.h
// 初始化扫描
TableScanDesc table_beginscan_catalog(
    Relation relation, int nkeys,
    struct ScanKeyData *key);

// 结束扫描
void table_endscan(TableScanDesc scan)

// src/include/access/heapam.h
// 表扫描
extern HeapTuple heap_getnext(TableScanDesc sscan, ScanDirection direction);

示例:遍历表数据

cpp
#include "access/relation.h"
#include "utils/rel.h"
#include "access/htup_details.h"
#include "access/heapam.h"
#include "utils/builtins.h"


Relation  rel;
TableScanDesc scan;
HeapTuple  tuple;
TupleDesc tupDesc;
Datum     *values;
bool     *nulls;

// 通过oid打开表
rel = table_open(24644, RowExclusiveLock);
tupDesc = RelationGetDescr(rel);

// 初始化扫描
scan = table_beginscan_catalog(rel, 0, NULL);

values = (Datum *) palloc(tupDesc->natts * sizeof(Datum));
nulls = (bool *) palloc(tupDesc->natts * sizeof(bool));

// 进行表扫描
while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
{
    int no = DatumGetInt32(fastgetattr(tuple, 1, tupDesc, &nulls));
    char* name = TextDatumGetCString(fastgetattr(tuple, 2, tupDesc, &nulls));
    int sex = DatumGetInt32(fastgetattr(tuple, 3, tupDesc, &nulls));
    ereport(LOG, (errmsg("{no: %d, name: %s, sex: %d}", no, name, sex)));
}

table_endscan(scan);

// 关闭表
table_close(rel, RowExclusiveLock);

日志输出

shell
{no: 1, name: Tom, sex: 1}
{no: 2, name: Jack, sex: 1}
{no: 3, name: Steve, sex: 0}

元组操作

cpp
// src/include/access/heapam.h
void heap_insert(Relation relation, HeapTuple tup, CommandId cid,
            int options, BulkInsertState bistate);

TM_Result heap_delete(Relation relation, ItemPointer tid,
               CommandId cid, Snapshot crosscheck, bool wait,
               struct TM_FailureData *tmfd, bool changingPart);

TM_Result heap_update(Relation relation, ItemPointer otid,
               HeapTuple newtup,
               CommandId cid, Snapshot crosscheck, bool wait,
               struct TM_FailureData *tmfd, LockTupleMode *lockmode,
               TU_UpdateIndexes *update_indexes);

// src/include/access/heapam.h
// 以下是上层接口,内部调用上面几个对应的函数
// 元组插入
void simple_heap_insert(Relation relation, HeapTuple tup);

// 元组删除
void simple_heap_delete(Relation relation, ItemPointer tid);

// 元组更新
void simple_heap_update(Relation relation, ItemPointer otid,
                 HeapTuple tup, TU_UpdateIndexes *update_indexes);

// src/include/catalog/indexing.h
// 以下是上层接口,内部调用上面几个对应的函数
void CatalogTupleInsert(Relation heapRel, HeapTuple tup);

void CatalogTupleUpdate(Relation heapRel, ItemPointer otid,
    HeapTuple tup);

void CatalogTupleDelete(Relation heapRel, ItemPointer tid);

// src/include/access/htup_details.h
HeapTuple heap_modify_tuple(HeapTuple tuple,
          TupleDesc tupleDesc,
          const Datum *replValues,
          const bool *replIsnull,
          const bool *doReplace)

元组插入

示例

cpp
#include "access/relation.h"
#include "utils/rel.h"
#include "access/htup_details.h"
#include "access/heapam.h"
#include "utils/builtins.h"

Relation rel;
HeapTuple tuple;
TupleDesc tupDesc;
Datum values[3];
bool nulls[3] = {0};

rel = relation_open(24644, AccessShareLock);
tupDesc = RelationGetDescr(rel);

values[0] = Int32GetDatum(4);
values[1] = CStringGetTextDatum("jodi");
values[2] = Int32GetDatum(23);

tuple = heap_form_tuple(tupDesc, values, nulls);
simple_heap_insert(rel, tuple);
heap_freetuple(tuple);

relation_close(rel, AccessShareLock);

元组删除

示例

cpp
#include "access/relation.h"
#include "utils/rel.h"
#include "access/htup_details.h"
#include "access/heapam.h"
#include "utils/builtins.h"
#include "nodes/makefuncs.h"

Relation  rel;
TableScanDesc scan;
HeapTuple  tuple;
TupleDesc tupDesc;

rel = table_openrv(makeRangeVar(NULL, "tb_teacher", -1),RowExclusiveLock);
tupDesc = RelationGetDescr(rel);
scan = table_beginscan_catalog(rel, 0, NULL);

while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
{
    simple_heap_delete(rel, &tuple->t_self);
}

table_endscan(scan);
table_close(rel, RowExclusiveLock);

元组更新

示例

cpp
#include "access/relation.h"
#include "utils/rel.h"
#include "access/htup_details.h"
#include "access/heapam.h"
#include "utils/builtins.h"
#include "nodes/makefuncs.h"
#include "catalog/indexing.h"

Relation rel;
TableScanDesc scan;
HeapTuple tuple;
TupleDesc tupDesc;
HeapTuple newtuple;
Datum values[3] = {0};
bool nulls[3] = {0};
bool replaces[3] = {0};

rel = table_openrv(makeRangeVar(NULL, "tb_teacher", -1), RowExclusiveLock);
scan = table_beginscan_catalog(rel, 0, NULL);

while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
{
    memset(values, 0, sizeof(values));
    memset(nulls, false, sizeof(nulls));
    memset(replaces, false, sizeof(replaces));

    replaces[2] = true;
    values[2] = Int32GetDatum(10);

    newtuple = heap_modify_tuple(
        tuple, RelationGetDescr(rel),
        values, nulls, replaces);

    CatalogTupleUpdate(rel, &tuple->t_self, newtuple);
}

table_endscan(scan);
table_close(rel, RowExclusiveLock);