CREATE DATABASE sampledb OWNER perrynzhou;
GRANT ALL PRIVILEGES ON DATABASE sampledb TO perrynzhou;
psql -h 127.0.0.1 -d sampledb
sampledb=# CREATE TABLE stu_xx_01(NAME TEXT NOT NULL,AGE INT NOT NULL);
1.PostgresMain:服务端监听到有客户端连接到PG,PG服务端会fork一个子进程来服务,这个子进程会传输postgre二进制名称和一些参数进行子进程的初始化,以便执行fork后的后续操作。PostgresMain就是这个子进程执行后续操作,当客户端通过网络发出sql,PostgresMain根据PG协议判断执行后续的SQL语句执行。
2.exec_simple_query:根据客户端请求的SQL语句执行SQL
3.PortalRun: 根据sql语句初始化Portal结构来封装SQL语句的执行
4.PortalRunMulti:根据portal->strategy的类型执行PortalRunMulti函数
5.PortalRunUtility:解析portal中的sql为解析树,然后执行portal中的非select的语句
6.ProcessUtility:根据解析树开始执行sql语句
7.standard_ProcessUtility:在ProcessUtility内执行standard_ProcessUtility方法继续向后执行SQL语句执行过程
/******如下是一个表创建的比较核心的函数*******/
8.ProcessUtilitySlow:根据parsetree开始执行create table的过程。
9.DefineRelation:返回一个表的ObjectAddr,其中包括pg_class中的oid,这个表对象的oid,这个表中column中的sub oid
10.heap_create_with_catalog:表创建函数
11.heap_create:表创建
12.table_relation_set_new_filenode:创建表的函数指针
13.heapam_relation_set_new_filenode:实际的执行标创建的函数
14.RelationCreateStorage:构建磁盘的表文件
// 如果是根据tablespace oid,database oid,table oid创建一个数据库表
15.smgrcreate->mdcreate->PathNameOpenFile
// ObjectAddress表示PG中数据库一种类型的对象
typedef struct ObjectAddress
{
Oid classId; /* Class Id from pg_class */
Oid objectId; /* OID of the object */
int32 objectSubId; /* Subitem within object (eg column), or 0 */
} ObjectAddress;
static void ProcessUtilitySlow(...)
{
// parsetree->type =T_CreateStmt
switch (nodeTag(parsetree))
{
case T_CreateStmt:
case T_CreateForeignTableStmt:
// 解析转换sql语句中的表的定义
stmts = transformCreateStmt((CreateStmt *) parsetree,
queryString);
while (stmts != NIL)
{
address = DefineRelation(cstmt,
RELKIND_RELATION,
InvalidOid, NULL,
queryString);
}
}
}
// 获取当前表的表空间
List *transformCreateStmt(CreateStmt *stmt, const char *queryString)
{
List *result;
CreateStmtContext cxt;
cxt.stmtType = "CREATE TABLE";
cxt.isforeign = false;
// 表空间获取
namespaceid =
RangeVarGetAndCheckCreationNamespace(stmt->relation, NoLock,
&existing_relid);
stmt->relation->schemaname = get_namespace_name(namespaceid);
// 编译stmt中的表中定义的column,
foreach(elements, stmt->tableElts)
{
// element 中的type=T_ColumnDef
Node *element = lfirst(elements);
//nodeTag(element)=T_ColumnDef
switch (nodeTag(element))
{
// (ColumnDef *)(element)定义了column中的定义
case T_ColumnDef:
// 解析column中定义的类型,约束等,把解析的结果全部存储到local的cxt中
transformColumnDefinition(&cxt, (ColumnDef *) element);
break;
}
}
stmt->tableElts = cxt.columns;
// 把ctx中的数据最终以result呈现
result = lappend(cxt.blist, stmt);
result = list_concat(result, cxt.alist);
result = list_concat(result, save_alist);
return result;
}
ObjectAddress
DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
ObjectAddress *typaddress, const char *queryString)
{
// NAMEDATALEN 规定了PG中表名称的长度为64个字符
strlcpy(relname, stmt->relation->relname, NAMEDATALEN);
// 构建这个表的所有列的以及相关属性
//最终调用heap_create_with_catalog去创建表
heap_create_with_catalog(....)
}
Oid heap_create_with_catalog(args...) {
/*
sampledb=# select oid,relname,relnamespace from pg_class where oid=1259;
oid | relname | relnamespace
------+----------+--------------
1259 | pg_class | 11
*/
//打开pg_class表,这里是以行的排他锁打开这个文件
pg_class_desc = table_open(RelationRelationId, RowExclusiveLock);
// 检查表中每个列的名称和数据类型
CheckAttributeNamesTypes(tupdesc, relkind,
allow_system_table_mods ? CHKATYPE_ANYARRAY : 0);
// 在static CatCache *SysCache中查找是否当前新增的表的名称是否存在于当前SysCache中,如果不存在则返回无效的oid
// relname = "stu_xx_01",relnamespace=2200
existing_relid = get_relname_relid(relname, relnamespace);
// 从pg_class表中针对当前表返回一个可用oid
relid = GetNewRelFileNode(reltablespace, pg_class_desc,
relpersistence);
// 最终进入这个方法,来创建表的磁盘文件
new_rel_desc = heap_create(relname,
relnamespace,
reltablespace,
relid,
InvalidOid,
accessmtd,
tupdesc,
relkind,
relpersistence,
shared_relation,
mapped_relation,
allow_system_table_mods,
&relfrozenxid,
&relminmxid);
// 针对当前表创建一种类型
TypeCreate(new_array_oid, /* force the type's OID to this */
relarrayname, /* Array type name */
relnamespace, /* Same namespace as parent */
InvalidOid, /* Not composite, no relationOid */
0, /* relkind, also N/A here */
ownerid, /* owner's ID */
-1, /* Internal size (varlena) */
TYPTYPE_BASE, /* Not composite - typelem is */
TYPCATEGORY_ARRAY, /* type-category (array) */
false, /* array types are never preferred */
DEFAULT_TYPDELIM, /* default array delimiter */
F_ARRAY_IN, /* array input proc */
F_ARRAY_OUT, /* array output proc */
F_ARRAY_RECV, /* array recv (bin) proc */
F_ARRAY_SEND, /* array send (bin) proc */
InvalidOid, /* typmodin procedure - none */
InvalidOid, /* typmodout procedure - none */
F_ARRAY_TYPANALYZE, /* array analyze procedure */
F_ARRAY_SUBSCRIPT_HANDLER, /* array subscript procedure */
new_type_oid, /* array element type - the rowtype */
true, /* yes, this is an array type */
InvalidOid, /* this has no array type */
InvalidOid, /* domain base type - irrelevant */
NULL, /* default value - none */
NULL, /* default binary representation */
false, /* passed by reference */
TYPALIGN_DOUBLE, /* alignment - must be the largest! */
TYPSTORAGE_EXTENDED, /* fully TOASTable */
-1, /* typmod */
0, /* array dimensions for typBaseType */
false, /* Type NOT NULL */
InvalidOid); /* rowtypes never have a collation */
// 在pg_class中注册新创建的表
AddNewRelationTuple(pg_class_desc,
new_rel_desc,
relid,
new_type_oid,
reloftypeid,
ownerid,
relkind,
relfrozenxid,
relminmxid,
PointerGetDatum(relacl),
reloptions);
// 在pg_attribute中注册表的colume的信息
AddNewAttributeTuples(relid, new_rel_desc->rd_att, relkind);
}
Relation
heap_create(const char *relname,
Oid relnamespace,
Oid reltablespace,
Oid relid,
Oid relfilenode,
Oid accessmtd,
TupleDesc tupDesc,
char relkind,
char relpersistence,
bool shared_relation,
bool mapped_relation,
bool allow_system_table_mods,
TransactionId *relfrozenxid,
MultiXactId *relminmxid)
{
// 传入relation表的相关定义,然后构建表Cache,最终插入到Cache中
rel = RelationBuildLocalRelation(relname,
relnamespace,
tupDesc,
relid,
accessmtd,
relfilenode,
reltablespace,
shared_relation,
mapped_relation,
relpersistence,
relkind);
// 这个函数实际调用的是 heapam_relation_set_new_filenode 这个函数
table_relation_set_new_filenode(rel, &rel->rd_node,
relpersistence,
relfrozenxid, relminmxid);
}
// rel 是创建表的定义,newrnode是{表空间oid、数据库oid、表文件oid}结构
static void heapam_relation_set_new_filenode(Relation rel,
const RelFileNode *newrnode,
char persistence,
TransactionId *freezeXid,
MultiXactId *minmulti)
{
// 实际创建表的阶段
srel = RelationCreateStorage(*newrnode, persistence);
}
SMgrRelation
RelationCreateStorage(RelFileNode rnode, char relpersistence)
{
// 在Cache中查找SMgrRelation
srel = smgropen(rnode, backend);
// 创建表的磁盘文件,smgrcreate实际调用的是mdcreate
smgrcreate(srel, MAIN_FORKNUM, false);
}
void
mdcreate(SMgrRelation reln, ForkNumber forkNum, bool isRedo)
{
//relpath最终调用GetRelationPath,返回当前创建表的路径(基于数据库目录的)
path = relpath(reln->smgr_rnode, forkNum);
// 创建一个数据库表的文件
fd = PathNameOpenFile(path, O_RDWR | O_CREAT | O_EXCL | PG_BINARY);
}
//设置输出的文件名称
(gdb) set logging file <文件名>
//输入这个命令后,此后的调试信息将输出到指定文件
(gdb) set logging on
//打印说有线程栈信息
(gdb) thread apply all bt
// 输入这个命令,关闭到指定文件的输出
(gdb) set logging off
$ ps -ef|grep -v grep|grep postgres
perrynz+ 1525 1 0 08:37 ? 00:00:00 /usr/local/postgres/bin/postgres -D /postgres/data
perrynz+ 1529 1525 0 08:37 ? 00:00:00 postgres: checkpointer
perrynz+ 1530 1525 0 08:37 ? 00:00:00 postgres: background writer
perrynz+ 1531 1525 0 08:37 ? 00:00:00 postgres: walwriter
perrynz+ 1532 1525 0 08:37 ? 00:00:00 postgres: autovacuum launcher
perrynz+ 1533 1525 0 08:37 ? 00:00:00 postgres: stats collector
perrynz+ 1534 1525 0 08:37 ? 00:00:00 postgres: logical replication launcher
perrynz+ 1536 1525 0 08:37 ? 00:00:00 postgres: perrynzhou sampledb 127.0.0.1(60390) idle
// gdb attach 到进程pid=1536
$ gdb /usr/local/postgres/bin/postgres
(gdb) attach 1536
(gdb) set print pretty on
(gdb) set print array on
(gdb) br PostgresMain
(gdb) br exec_simple_query
(gdb) br PortalRun
(gdb) br PortalRunMulti
(gdb) br PortalRunUtility
(gdb) br ProcessUtility
(gdb) br standard_ProcessUtility
(gdb) br ProcessUtilitySlow
(gdb) br DefineRelation
(gdb) br heap_create_with_catalog
(gdb) br heap_create
(gdb) br table_relation_set_new_filenode
(gdb) br heapam_relation_set_new_filenode
(gdb) br RelationCreateStorage
(gdb) br smgrcreate
(gdb) br mdcreate
(gdb) br PathNameOpenFile