PostgreSQL 10.4.1 - Installing on Windows 10

# 概要

Windows 10に開発・検証用にPostgreSQL 10.4.1をインストールし、初歩的な設定を行うまでの作業メモです。
インストーラー版は使わずZIP Archive版で手動インストールします。

**環境**

* Windows 10 Professional
* PostgreSQL 10.4.1 (ZIP Archive)

**参考**

* [PostgreSQL] (https://www.postgresql.org/)
* [PostgreSQL 10.3文書] (https://www.postgresql.jp/document/10/html/index.html)

# インストール

## ダウンロード

[ダウンロードページ] (https://www.postgresql.org/download/windows/)よりWindows版のアーカイブファイルをダウンロードし適当な場所へ展開します。
この記事ではpostgresql-10.4-1-windows-x64-binaries.zipをダウンロードし`D:\dev\postgresql-10.4.1`へ展開しました。

下記は展開した直後のディレクトリの状態です。
"pgAdmin 4"ディレクトリにpgAdmin4の実行環境が含まれています。

```text
/postgresql-10.4.1
  |
  +--- /bin
  +--- /doc
  +--- /include
  +--- /lib
  +--- /pgAdmin 4
  +--- /share
  +--- /StackBuilder
  +--- /symbols
```

## データ、ログ用のディレクトリを作成

展開したディレクトリ内にデータ、ログ用のディレクトリを作成します。

* データ
    * D:\dev\postgresql-10.4.1\data
* ログ
    * D:\dev\postgresql-10.4.1\logs

## 環境変数の登録

* path
    * D:\dev\postgresql-10.4.1\bin
* PGDATA
    * D:\dev\postgresql-10.4.1\data

## データベースクラスタの作成

* [第18章 サーバの準備と運用 - 18.2. データベースクラスタの作成]  (https://www.postgresql.jp/document/10/html/creating-cluster.html)
* [PostgreSQLサーバアプリケーション - initdb] (https://www.postgresql.jp/document/10/html/app-initdb.html)

スーパーユーザーはpostgresとしました。

```text
> pg_ctl initdb -o "-A password -W -U postgres -E UTF8 --no-locale"
データベースシステム内のファイルの所有者は"<USER NAME>"となります。
このユーザがサーバプロセスも所有する必要があります。

データベースクラスタはロケール"C"で初期化されます。
デフォルトのテキスト検索設定はenglishに設定されました。

データベージのチェックサムは無効です。

新しいスーパユーザのパスワードを入力してください: <postgresユーザーのパスワード>
再入力してください: <postgresユーザーのパスワード>

既存のディレクトリD:/dev/postgresql-10.4.1/dataの権限を修正します ... 完了
サブディレクトリを作成します ... 完了
max_connectionsのデフォルト値を選択します ... 100
shared_buffersのデフォルト値を選択します ... 128MB
動的共有メモリの実装を選択します ... windows
設定ファイルを作成します ... 完了
ブートストラップスクリプトを実行します ... 完了
ブートストラップ後の初期化を行っています ... 完了
データをディスクに同期します...完了

成功しました。以下のようにしてデータベースサーバを起動できます。

    D:/dev/postgresql-10.4.1/bin/pg_ctl -D D:/dev/postgresql-10.4.1/data -l <ログファイル> start

```

## データベースの起動

```text
> pg_ctl -l "D:/dev/postgresql-10.4.1/logs/postgresql.log" start
サーバの起動完了を待っています.......完了
サーバ起動完了
```

## データベースの停止

```text
> pg_ctl stop
サーバ停止処理の完了を待っています....完了
サーバは停止しました
```

## ステータスの確認

```text
> pg_ctl status
pg_ctl: サーバが動作中です(PID: 6112)
D:/dev/postgresql-10.4.1/bin/postgres.exe
```

## 新しいユーザーの作成

* [PostgreSQLクライアントアプリケーション - createuser] (https://www.postgresql.jp/document/10/html/app-createuser.html)

postgresユーザー（スーパーユーザー）を使って、test_userというユーザーを作成します。

```text
> createuser -U postgres -W -P test_user
新しいロールのためのパスワード: <test_userのパスワード>
もう一度入力してください: <test_userのパスワード>
パスワード: <postgresユーザーのパスワード>
```

### ユーザーの削除

```text
> dropuser -U postgres -W test_user
パスワード: <postgresユーザーのパスワード>
```

## 新しいデータベースの作成

* [PostgreSQLクライアントアプリケーション - createdb] (https://www.postgresql.jp/document/10/html/app-createdb.html)

postgresユーザー（スーパーユーザー）を使って、test_userユーザーがオーナーのtest_dbデータベースを作成します

```text
> createdb -E UTF8 -l Japanese_Japan.932 -T template0 -O test_user -U postgres -W test_db
パスワード: <postgresユーザーのパスワード>
```

### データベースの一覧

```text
> psql -U postgres -l
                                              データベース一覧
   名前    |  所有者   | エンコーディング |      照合順序      | Ctype(変換演算子)  |     アクセス権限
-----------+-----------+------------------+--------------------+--------------------+-----------------------
 postgres  | postgres  | UTF8             | C                  | C                  |
 template0 | postgres  | UTF8             | C                  | C                  | =c/postgres          +
           |           |                  |                    |                    | postgres=CTc/postgres
 template1 | postgres  | UTF8             | C                  | C                  | =c/postgres          +
           |           |                  |                    |                    | postgres=CTc/postgres
 test_db   | test_user | UTF8             | Japanese_Japan.932 | Japanese_Japan.932 |
(4 行)
```

### データベースの削除

```text
> dropdb -U postgres -W -i -e test_db
データベース"test_db"は恒久的に削除されます。
実行しますか? (y/n)y
パスワード: <postgresユーザーのパスワード>
SELECT pg_catalog.set_config('search_path', '', false)
DROP DATABASE test_db;
```

# 起動・停止用のバッチファイル

起動用

```bat:postgresql_start.bat
D:\dev\postgresql-10.4.1\bin\pg_ctl.exe -l "D:\dev\postgresql-10.4.1\logs\postgresql.log" start
```

停止用

```bat:postgresql_stop.bat
D:\dev\postgresql-10.4.1\bin\pg_ctl stop
```

# psql

> PostgreSQLの対話的ターミナル

* [PostgreSQLクライアントアプリケーション - psql] (https://www.postgresql.jp/document/10/html/app-psql.html)

## スーパーユーザー(postgresユーザー)でログイン

スーパーユーザーとはデータベースクラスタ作成時に指定したユーザーです。

```text
> psql -U postgres
psql (10.4)
"help" でヘルプを表示します。

postgres=#
```

## 一般ユーザーでログイン

```text
> psql -d test_db -U test_user
ユーザー test_user のパスワード:
psql (10.4)
"help" でヘルプを表示します。

test_db=>
```

### 検証用のテーブル作成

```sql
CREATE TABLE memo (
  id integer NOT NULL,
  title varchar(255) NOT NULL,
  description text NOT NULL,
  done boolean DEFAULT false NOT NULL,
  updated timestamp without time zone DEFAULT current_timestamp NOT NULL,
  CONSTRAINT memo_pkey PRIMARY KEY(id)
);

CREATE SEQUENCE memo_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;

ALTER SEQUENCE memo_id_seq OWNED BY memo.id;

ALTER TABLE ONLY memo ALTER COLUMN id SET DEFAULT nextval('memo_id_seq'::regclass);
```

テストデータの投入

```sql
insert into memo (title, description, done) values ('a memo 1', 'memo 1 description', false);
insert into memo (title, description, done) values ('b memo 2', 'memo 2 description', false);
insert into memo (title, description, done) values ('1 memo 3', 'memo 3 description', false);
insert into memo (title, description, done) values ('2 memo 4', 'memo 4 description', false);
insert into memo (title, description, done) values ('あ memo 5', 'memo 5 description', false);
insert into memo (title, description, done) values ('か memo 6', 'memo 6 description', false);
insert into memo (title, description, done) values ('さ memo 7', 'memo 7 description', false);
insert into memo (title, description, done) values ('Ａ memo 8', 'memo 8 description', false);
insert into memo (title, description, done) values ('Ｂ memo 9', 'memo 9 description', false);
insert into memo (title, description, done) values ('ア memo 10', 'memo 10 description', false);
insert into memo (title, description, done) values ('亜 memo 11', 'memo 11 description', false);
```

```sql
test_db=> select id,title from memo;
 id |   title
----+------------
  1 | a memo 1
  2 | b memo 2
  3 | 1 memo 3
  4 | 2 memo 4
  5 | あ memo 5
  6 | か memo 6
  7 | さ memo 7
  8 | Ａ memo 8
  9 | Ｂ memo 9
 10 | ア memo 10
 11 | 亜 memo 11
(11 行)

test_db=> select id,title from memo order by title desc;
 id |   title
----+------------
 11 | 亜 memo 11
  7 | さ memo 7
  6 | か memo 6
  5 | あ memo 5
 10 | ア memo 10
  9 | Ｂ memo 9
  2 | b memo 2
  8 | Ａ memo 8
  1 | a memo 1
  4 | 2 memo 4
  3 | 1 memo 3
(11 行)
```

### データベースの一覧

メタコマンド`\l`

```text
test_db=> \l
```

### テーブル、ビュー、シーケンスの一覧

メタコマンド`\z`

```text
test_db=> \z
```

### psqlの終了

メタコマンド`\q`

```text
test_db=> \q
```

# pgAdmin 4

PostgreSQLの展開ディレクトリ内にはpgAdmin4の実行環境が含まれていて、その中にあるpgAdmin4.exeを実行すればpgAdmin4が起動します。
しかし現時点(2018/05)ではpgAdmin4を起動しようとすると"The application server could not be contacted."というFatal Errorが発生して起動しないという現象がありました。

![fatal.png](https://qiita-image-store.s3.amazonaws.com/0/22772/150bc6a0-df1c-d112-2a22-f0638f73658c.png)

**解決方法**

"\<PostgreSQLのインストールディレクトリ\>\pgAdmin 4\venv\Lib\site-packages\backports"ディレクトリに空(0バイト)の`__init__.py`ファイルを作成します。
これでpgAdmin4が起動するようになると思います。

![pgadmin.png](https://qiita-image-store.s3.amazonaws.com/0/22772/0f77d0bb-e324-66fa-7cac-cd6e9d01be9c.png)

それでも起動しない場合は"C:\Users\\<ログインユーザー\>\AppData\Roaming\pgAdmin"ディレクトリを削除すると起動することがあるようです。（こちらは未確認です。）

この問題はpgAdmin4 V2.1のときに修正されたようですが、v3で再発しているような感じです。

https://www.pgadmin.org/docs/pgadmin4/dev/release_notes_2_1.html のBug #2918 


**エラーが発生している箇所**

ちなみに、ログに出力されていたエラーをみると"pgAdmin 4\web\pgadmin\utils\driver\psycopg2\connection.py"というファイルの42行目で行っているimportが失敗しているようです。

```py:42行目
from backports import csv
```

この部分のブロック全体は下記のようになっていてバージョン2とバージョン3でインポートするモジュールを切り替えているようで（pythonのことはほとんどわかりませんが）、バージョン2のときにインポートするbackports.csvがインポートできないことが原因のようです。

```py
if sys.version_info < (3,):
    # Python2 in-built csv module do not handle unicode
    # backports.csv module ported from PY3 csv module for unicode handling
    from backports import csv
    from StringIO import StringIO
    IS_PY2 = True
else:
    from io import StringIO
    import csv
    IS_PY2 = False
```