LEFログ:学習記録ノート

leflog: 学習の記録をどんどんアップしていきます

WSLにPostgreSQLをinstallすると、デフォルトのEncoding(文字コード)がSQL_ASCIIになってしまう問題の解決方法(UTF8に変更、Debian系、WSL2)

タイトル:「WSLにPostgreSQLをinstallすると、デフォルトのEncoding(文字コード)がSQL_ASCIIになってしまう問題の解決方法(UTF8に変更、Debian系、WSL2)」

※初めは丁寧語(敬体)で書いていたのですが、逆に読みづらくなってしまったので常体に変更しました。

劇的BeforeAfter

Before

文字コードSQL_ASCII(アスキー文字)になってしまっている

After

文字コードがデフォルトでUTF8になっている

結論

  • PostgreSQLのデフォルト文字コードは、Linuxのlocaleを参照する
  • WSLはデフォルトの状態だと、rootユーザーは「Cロケール」になってしまっている。この状態だと、PostgreSQLをインストールしたときに、文字コードが「SQL_ASCII」になってしまい、とても不便。
  • PostgreSQLはrootユーザーとして操作するため、rootユーザーのlocaleを参照する。そのため、一般ユーザーのlocaleだけを変更しても意味がない。
  • localeの変更はLANG環境変数だけでなく、LC_ALLも変更する必要がある

根本的な解決方法

rootユーザー側でlocaleを確認する

su -
locale

rootユーザーでdpkg-reconfigure localesを実行してLANGを変更する

su -
dpkg-reconfigure locales

dpkgの操作は、矢印キーで「言語と文字コード」を選んで、スペースキーで「*」を付けたまま、エンターキーを打つ。
そして、もう一度「言語と文字コード」を選んでから、エンターキーを打つと設定される(GUI操作なのでちょっと注意が必要)。

Debian - ロケール(日本語)環境の設定 - Linux入門 - Webkaru

rootユーザーと一般ユーザーの両方でやっておく。

defaultのlocale設定ファイルをsudo vim で書き換えて、LC_ALL=CCを削除して保存する

cd /etc/default
ls # localeファイルがあるか確認
cp locale /任意のフォルダ # バックアップを一応取っておく
sudo vim locale #LC_ALL=Cの「C」の部分だけを削除する(イコール記号「=」は残す)
cat locale # 変更を確認
su -
locale # rootユーザーのまま再度確認
exit

PostgreSQLをpurgeして再インストールする

su -
apt purge postgre*
exit
sudo apt autoremove
sudo apt list --installed # インストールしたパッケージの確認
sudo apt update
sudo apt upgrade
# 後はMicrosoftの公式ドキュメントの通りに
sudo apt install postgresql postgresql-contrib

WSL を使用してデータベースを追加または接続する | Microsoft Docs

以上の操作をおこなうと、デフォルトの文字コードがUTF8になる

psql シェルで、

postgres=# \l

をおこなうと、encoding(文字コード)などが確認できる

別の解決方法

template1の文字コードを変更する。新しく作成するDBは「template1」の設定を元に作られるため、ここを変更しておけば何とかなる。

【PostgreSQL】データベースの文字コードを変更する | PostgresWeb - ポスグレウェブ

【PostgreSQL】template1の文字コードを変更する | PostgresWeb - ポスグレウェブ

PostgreSQL: template1 のエンコーディングを UTF-8 に変更する - tkrdの日記

PostgreSQLでデフォルトのEncoding・Collate・Ctypeなどを変更したい

あるいは、新しいDBを作成するたびに文字コードなどを色々指定する。

PostgreSQL データベースの作成 - Kakiro-Web カキローウェブ

ターミナルで日本語(全角文字)が入力できないとき

  • sudo apt install postgresql-contribをちゃんとしているか?(contribパッケージをインストールし忘れていないか?)

  • 文字コードの設定がUTF8になっているか?

  • 一旦PostgreSQLを再起動したか?

sudo service postgresql restart

なぜこの問題に気づいたか?

WSL2にインストールしたPostgreSQLに、Windows側(VSCode拡張機能)から接続したあと、DB(データベース)を読み込もうとしたとき、次のようなエラーが出て疑問に思ったため。

Started executing query at Line 1

Commands completed successfully 

Unhandled exception while executing query: 'ascii' codec can't decode byte 0xe3 in position 0: ordinal not in range(128) 

Total execution time: 00:00:00.007

このエラーメッセージを読んで、ascii(アスキー文字)になっていることに気づきました。

WSL2でPostgreSQLを起動し、psqlの操作画面で

postgres=# \l

と入力したところ、

Encoding  |Collate  |Ctype
SQL_ASCII |C        |C

になっていた。

ロケール参照について

initdb

このサイトに

テンプレートデータベースの符号化方式を選択します。 これが今後作成される全てのデータベースについてのデフォルト符号化方式となりますが、作成時に上書きすることもできます。 デフォルトは、ロケールから取得しますが、取得できなければSQL_ASCIIになります。 PostgreSQLサーバによってサポートされる文字セットについては23.3.1で説明します。

と書いてあったため分かりました。

また、これらの記事も参考になりました。

文字セットサポート

第1章 PostgreSQLの今昔を知る―20年を超える歴史,リリースサイクル,環境構築:詳解 PostgreSQL[10/11対応]―現場で役立つ新機能と実践知識|gihyo.jp … 技術評論社

PostgreSQLはinitdbの際にロケールを指定しない場合,OS側に設定されているロケールを使用します。

Debian系でPostgreSQLのロケールを変更する - Qiita

initdbのデフォルト値として、ロケールは実行時のLANG環境変数等が、エンコーディングロケールから推測するかSQL_ASCIIが使われます。

PostgreSQL 9.1 installation and database encoding - Stack Overflow

なぜSQL_ASCIIのままだとマズいのか

SQL_ASCIIのままだと、半角文字しかDBに登録することができない。実際にDBに登録していくときは、日本語のような全角文字も入力するわけで、このままだと様々な問題が生じてしまう。

そのため、あらゆる言語を入力できる「UTF8」に変える必要がある。

ちなみに、PostgreSQLの表記では、大文字の「UTF8」でハイフンは要らないので注意。

柴田 淳-みんなのPython/東進デジタルユニバーシティ講師さんはTwitterを使っています: 「PostgreSQLのwikiにあるべからず集勉強になる。 エンコーディングにSQL_ASCIIを使うな、NOT INをら使うな、タイムゾーンなしのtimestampを使うなとか、色々な「べからず」が理由を添えて書いてある。 https://t.co/yjUpuPfBCi」 / Twitter

Don't Do This - PostgreSQL wiki

Debianのlocalファイルの位置を調べた方法

postgresql - How do I change the default client_encoding in Postgres? - Stack Overflow

の記事を読んで、

The method for doing this may vary depending on your system, but usually you can do it by modifying ~/.config/locale.conf (your user only) or /etc/default/locale or /etc/locale.conf (system-wide). This will affect more than just postgres, and I believe more closely addresses the root of the problem. You can check your current locale settings by running locale.

と書いてあったので、/etc/default/localeにrootユーザーのlocale設定が置いてあることが分かった。
ここでLC_ALL=CLC_ALL=に変えてあげれば、ロケール設定がうまくいく。

他にも以下のような記事を参考にした。

Linuxでシステムロケールを変更または設定する方法

How to Change or Set System Locales in Linux

command line - How do I change the default locale in Ubuntu Server? - Ask Ubuntu

システムワイドなロケール設定 〜 Debian GNU/Linux - 彷徨えるフジワラ

第 8 章 基本設定、ネットワーク、アカウント、印刷...

今回の調査の課題点

initdbコマンドを使えば初期設定の文字コードを変更できるみたいですが、どうやって使えば良いのかよく分かりませんでした(Debianを使っているからかもしれません)。時間のあるときに調べようと思いました。

PostgreSQLの初期設定 | Netsphere Laboratories https://www.nslabs.jp/postgresql-setup.rhtml

今回の教訓

Linuxのrootユーザーの設定(システム設定)と一般ユーザー設定には違いがあることが多いので注意する。

エラーが起きた場合は、それぞれの設定を確認する。