上篇文章分析到使用引导模式创建了template0,下面继续分析
到了这里引导模式的工作基本就结束了,下面开始使用postgres的单用户模式对template1创建系统表,视图,依赖,以及扩展插件的安装等一列操作。
首先是通过setup_auth()设置search_path和exit_on_error,下面的代码本来是放在setup_auth()中执行,但是新版本中被提出来了。
//这里第一个参数给的是postgres,第二个参数给的是-single -F -O -c search_path=pg_catalog -c exit_on_error=true
//这里把exit_on_error设为true之后,任何错误将中止当前会话。默认是false,只有 FATAL 错误(致命)将中止会话。
snprintf(cmd, sizeof(cmd),
"\"%s\" %s template1 >%s",
backend_exec, backend_options,
DEVNULL);
然后是通过setup_depend()设置依赖关系,其实就是更新pg_depend和pg_shdepend表
static void
setup_depend(FILE *cmdfd)
{
const char *const *line;
static const char *const pg_depend_setup[] = {
……
//删除pg_depend和pg_shdepend表中的数据并清理
//pg_depend和pg_shdepend表之前通过postgres.bki创建
"DELETE FROM pg_depend;\n\n",
"VACUUM pg_depend;\n\n",
"DELETE FROM pg_shdepend;\n\n",
"VACUUM pg_shdepend;\n\n",
//向pg_depend表中填充数据
"INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
" FROM pg_class;\n\n",
"INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
" FROM pg_proc;\n\n",
……
NULL
};
//逐行执行
for (line = pg_depend_setup; *line != NULL; line++)
PG_CMD_PUTS(*line);
}
通过setup_sysviews()创建系统视图
static void
setup_sysviews(FILE *cmdfd)
{
char **line;
char **sysviews_setup;
//这里其实就是读取了system_views.sql文件,然后逐行执行
sysviews_setup = readfile(system_views_file);
for (line = sysviews_setup; *line != NULL; line++)
{
PG_CMD_PUTS(*line);
free(*line);
}
free(sysviews_setup);
}
通过setup_description()创建pg_description和pg_shdescription表,也就是描述表
static void
setup_description(FILE *cmdfd)
{
//创建临时表tmp_pg_description
PG_CMD_PUTS("CREATE TEMP TABLE tmp_pg_description ( "
" objoid oid, "
" classname name, "
" objsubid int4, "
" description text) WITHOUT OIDS;\n\n");
//把postgres.description文件中的内容copy到tmp_pg_description表
PG_CMD_PRINTF1("COPY tmp_pg_description FROM E'%s';\n\n",
escape_quotes(desc_file));
//把tmp_pg_description表中的数据插入到pg_description表
PG_CMD_PUTS("INSERT INTO pg_description "
" SELECT t.objoid, c.oid, t.objsubid, t.description "
" FROM tmp_pg_description t, pg_class c "
" WHERE c.relname = t.classname;\n\n");
//后面pg_shdescription表也是同理,这里不再分析
……
PG_CMD_PUTS("DROP TABLE tmp_pg_description;\n\n");
PG_CMD_PUTS("DROP TABLE tmp_pg_shdescription;\n\n");
}
通过setup_collation()创建pg_collation表,也就是排序规则表
static void
setup_collation(FILE *cmdfd)
{
//直接向pg_collation表插入数据
PG_CMD_PRINTF3("INSERT INTO pg_collation (collname, collnamespace, collowner, collprovider, collencoding, collcollate, collctype) VALUES ('ucs_basic', 'pg_catalog'::regnamespace, %u, '%c', %d, 'C', 'C');\n\n",
BOOTSTRAP_SUPERUSERID, COLLPROVIDER_LIBC, PG_UTF8);
PG_CMD_PUTS("SELECT pg_import_system_collations('pg_catalog');\n\n");
}
通过setup_conversion()创建表pg_conversion,也就是编码转换表
static void
setup_conversion(FILE *cmdfd)
{
char **line;
char **conv_lines;
//这里其实就是读取了conversion_create.sql文件,然后逐行执行
conv_lines = readfile(conversion_file);
for (line = conv_lines; *line != NULL; line++)
{
if (strstr(*line, "DROP CONVERSION") != *line)
PG_CMD_PUTS(*line);
free(*line);
}
free(conv_lines);
}
通过 setup_dictionary()创建一些额外的目录
static void
setup_dictionary(FILE *cmdfd)
{
char **line;
char **conv_lines;
//这里其实就是读取了\src\backend\catalog\snowball_create.sql文件,然后逐行执行
conv_lines = readfile(dictionary_file);
for (line = conv_lines; *line != NULL; line++)
{
PG_CMD_PUTS(*line);
free(*line);
}
free(conv_lines);
}
通过setup_privileges()设置权限
//函数比较长这里就不贴了,内容是一些修改权限的sql文
setup_privileges()
通过setup_schema()创建info_schema
static void
setup_schema(FILE *cmdfd)
{
char **line;
char **lines;
lines = readfile(info_schema_file);
//这里读取了information_schema.sql文件
for (line = lines; *line != NULL; line++)
{
PG_CMD_PUTS(*line);
free(*line);
}
free(lines);
//这里更新了一下sql_implementation_info表中的character_value字段
PG_CMD_PRINTF1("UPDATE information_schema.sql_implementation_info "
" SET character_value = '%s' "
" WHERE implementation_info_name = 'DBMS VERSION';\n\n",
infoversion);
PG_CMD_PRINTF1("COPY information_schema.sql_features "
" (feature_id, feature_name, sub_feature_id, "
" sub_feature_name, is_supported, comments) "
" FROM E'%s';\n\n",
escape_quotes(features_file));
}
添加plpgsql扩展
static void
load_plpgsql(FILE *cmdfd)
{
PG_CMD_PUTS("CREATE EXTENSION plpgsql;\n\n");
}
对template1进行清理
//这个函数其实就是对template1分别执行以下命令
//ANALYZE:收集template1的统计信息
//VACUUM FULL:完全清理template1
//VACUUM FREEZE:选择激进的元组“冻结”
vacuum_db();
到了这里template1就算是完工了,下面需要把template1 COPY一份 成为template0
/*
* copy template1 to template0
* 代码就不分析了,注释已经写的很明白了
*/
make_template0()
然后再把template1 COPY一份 成为postgres
/*
* copy template1 to postgres
*/
static void
make_postgres(FILE *cmdfd)
{
const char *const * line;
//这里还会顺带把postgres数据库设置为默认连接数据库
static const char *const postgres_setup[] = {
"CREATE DATABASE postgres;\n\n",
"COMMENT ON DATABASE postgres IS 'default administrative connection database';\n\n",
NULL
};
for (line = postgres_setup; *line; line++)
PG_CMD_PUTS(*line);
}
到了这里,初期化基本就结束了,剩下来还有一些收尾工作,比如数据同步
//这里其实就是是否等待数据同步到磁盘,默认是开启的,可以在initdb时通过-N关闭
if (do_sync)
fsync_pgdata();
else
printf(_("\nSync to disk skipped.\nThe data directory might become corrupt if the operating system crashes.\n"));
最后就是向用户返回成功信息了
printf(_("\nSuccess. You can now start the database server using:\n\n"
" %s%s%spg_ctl%s -D %s%s%s -l logfile start\n\n"),
QUOTE_PATH, bin_dir, (strlen(bin_dir) > 0) ? DIR_SEP : "", QUOTE_PATH,
QUOTE_PATH, pgdata_native, QUOTE_PATH);
initdb流程分析结束