PostgreSQL資料庫集簇初始化——initdb初始化資料庫(命令列引數處理)
template1和template0資料庫用於建立資料庫。PG中採用從模板資料庫複製的方法來建立新的資料庫,在建立資料庫的命令中可以用-T選項來指定以哪個資料庫為模板來建立新資料庫。template1資料庫是建立資料庫命令預設的模板,也就是說通過不帶-T選項的命令建立的使用者資料庫和template1一模一樣。template1是可以修改的,如果對tempalte1進行了修改,那麼在修改之後建立的使用者資料庫中也能體現出這些修改的結果。template1的存在允許使用者可以製作一個自定義的模板資料庫,在其中使用者可以建立一些應用需要的表、資料、索引等,在日後需要多次建立相同內容的資料庫時,都可以用template1作為模板生成。
src\bin\initdb
initdb是PG中一個獨立的程式,它的主要工作就是對資料集簇進行初始化,建立模板資料庫和系統表,並向系統表中插入初始元組。在這以後,使用者建立各種資料庫、表、檢視、索引等資料庫物件和進行其他操作時,都是在模板資料庫和系統表的基礎上進行的。執行initdb程式時,將從發initdb.c檔案中的main函式開始執行,initdb執行時將按照順序執行下列工作:
1. 根據使用者輸入的命令列引數獲取輸入的命令名。
initdb把使用者指定的選項轉換成對應的引數,通過外部程式呼叫的方式執行postgres程式。postgres程式在這種方式下將進入bootstrap模式建立資料集簇,並讀取後端介面postgres.bki檔案來建立模板資料庫。
initdb [option...] --pgdata|-D directory 常用option選項如下:
-A METHOD | --auth = METHOD 指定本地連線的預設使用者認證方式
-D DATADIR | --pgdata = DATADIR 資料目錄的路徑,必須是對當前使用者可讀寫的空目錄,也可以使用環境變數PGDATA來指定而省略本選項
-E ENCODING | --encoding = ENCODING 指定預設資料庫編碼方式
-U NAME | --username = NAME 指定資料庫超級使用者名稱
-W | --pwprompt 提示超級使用者設定口令
-d | --debug 以除錯模式執行,可以打印出很多除錯訊息
-L directory 指定輸入檔案(比如postgres.bki)位置
1 static struct option long_options[] = { 2 {"pgdata", required_argument, NULL, 'D'}, 3 {"encoding", required_argument, NULL, 'E'}, 4 {"locale", required_argument, NULL, 1}, 5 {"lc-collate", required_argument, NULL, 2}, 6 {"lc-ctype", required_argument, NULL, 3}, 7 {"lc-monetary", required_argument, NULL, 4}, 8 {"lc-numeric", required_argument, NULL, 5}, 9 {"lc-time", required_argument, NULL, 6}, 10 {"lc-messages", required_argument, NULL, 7}, 11 {"no-locale", no_argument, NULL, 8}, 12 {"text-search-config", required_argument, NULL, 'T'}, 13 {"auth", required_argument, NULL, 'A'}, 14 {"pwprompt", no_argument, NULL, 'W'}, 15 {"pwfile", required_argument, NULL, 9}, 16 {"username", required_argument, NULL, 'U'}, 17 {"help", no_argument, NULL, '?'}, 18 {"version", no_argument, NULL, 'V'}, 19 {"debug", no_argument, NULL, 'd'}, 20 {"show", no_argument, NULL, 's'}, 21 {"noclean", no_argument, NULL, 'n'}, 22 {"xlogdir", required_argument, NULL, 'X'}, 23 {NULL, 0, NULL, 0} 24 };
getopt_long函式用於處理命令列引數,程式碼處於src/port/getopt_long.c。
1 while ((c = getopt_long(argc, argv, "dD:E:L:nU:WA:sT:X:", long_options, &option_index)) != -1){ 2 switch (c){ 3 case 'A': 4 authmethod = xstrdup(optarg); 5 break; 6 ...
2. 設定系統編碼為LC_ALL,查詢執行命令的絕對路徑並設定該路徑。
set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("initdb"));
設定指定應用的locale和service目錄,函式獲取argv[0]的值而不是全路徑
1 void set_pglocale_pgservice(const char *argv0, const char *app){ 2 char path[MAXPGPATH]; 3 char my_exec_path[MAXPGPATH]; 4 char env_path[MAXPGPATH + sizeof("PGSYSCONFDIR=")]; /* longer than PGLOCALEDIR */ 5 /* don't set LC_ALL in the backend */ 6 if (strcmp(app, PG_TEXTDOMAIN("postgres")) != 0) 7 setlocale(LC_ALL, ""); 8 if (find_my_exec(argv0, my_exec_path) < 0) 9 return; 10 #ifdef ENABLE_NLS 11 get_locale_path(my_exec_path, path); 12 bindtextdomain(app, path); 13 textdomain(app); 14 if (getenv("PGLOCALEDIR") == NULL){ 15 /* set for libpq to use */ 16 snprintf(env_path, sizeof(env_path), "PGLOCALEDIR=%s", path); 17 canonicalize_path(env_path + 12); 18 putenv(strdup(env_path)); 19 } 20 #endif 21 if (getenv("PGSYSCONFDIR") == NULL){ 22 get_etc_path(my_exec_path, path); 23 /* set for libpq to use */ 24 snprintf(env_path, sizeof(env_path), "PGSYSCONFDIR=%s", path); 25 canonicalize_path(env_path + 13); 26 putenv(strdup(env_path)); 27 } 28 }
3. 設定環境變數(pg_data等),獲取系統配置檔案的原始檔路徑(postgres.bki、postgresql.conf. sample等檔案),並檢查該路徑下各檔案的可用性。
4. 設定中斷訊號處理函式,對終端命令列SIGHUP、程式中斷SIGINT、程式退出SIGQUIT、軟體中斷SIGTERM和管道中斷SIGPIPE等訊號進行遮蔽,保證初始化工作順利進行。
5. 建立資料目錄,以及該目錄下一些必要的子目錄,如base、global、base/1等。
6. 測試當前伺服器系統性能,由測試結果建立配置檔案postgresql.conf、pg_hba.conf、pg_ident.conf,並對其中定義的引數做一些設定。
7. 在bootstrap模式下建立資料庫template1,儲存在資料目錄的子目錄base/1/中。
3141行
1 /* Bootstrap template1 */ 2 bootstrap_template1(short_version); 3 4 /* 5 * Make the per-database PG_VERSION for template1 only after init'ing it 6 */ 7 set_short_version(short_version, "base/1");
8. 建立系統檢視、系統表TOAST表等,複製template1來建立template0和postgres,這些操作都用普通的SQL命令來完成。
setup_auth(); if (pwprompt || pwfilename) get_set_pwd(); setup_depend(); setup_sysviews(); setup_description(); setup_conversion(); setup_dictionary(); setup_privileges(); setup_schema(); vacuum_db(); make_template0(); make_postgres();
9. 列印操作成功等相關資訊,退出。
if (authwarning != NULL) fprintf(stderr, "%s", authwarning); /* Get directory specification used to start this executable */ strcpy(bin_dir, argv[0]); get_parent_directory(bin_dir); printf(_("\nSuccess. You can now start the database server using:\n\n" " %s%s%spostgres%s -D %s%s%s\n" "or\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, pg_data_native, QUOTE_PATH, QUOTE_PATH, bin_dir, (strlen(bin_dir) > 0) ? DIR_SEP : "", QUOTE_PATH, QUOTE_PATH, pg_data_native, QUOTE_PATH);