Ubuntu 24.04LTSでRedshiftにCLI接続する

# はじめに

RedshiftにCLIで接続する際、PostgreSQLのCLIであるpsqlを使用することが多いと思いますが、最新のpsqlだと特定のメタコマンドが使用できないことがあります

Ubuntu 24.04LTSの標準のPostgreSQLは17であるため、17のpostgresql-clientでは以下のようなエラーとなります
```
dev => \l
ERROR:  column d.datcollate does not exist
dev => \d tablename
ERROR:  column c.relhastriggers does not exis
```

個人的には`\l` はあまり使うことはないですが、`\d` が使えないのはなかなかツライところです
これはRedshiftのベースとなるPostgreSQLのバージョンが古いことによるもので、psqlで接続した際に出力されるメッセージから
```
psql (17.2 (Ubuntu 17.2-1.pgdg24.04+1), server 8.0.2)
WARNING: psql major version 17, server major version 8.0.
         Some psql features might not work.
SSL connection (protocol: TLSv1.2, cipher: ECDHE-RSA-AES256-GCM-SHA384, compression: off, ALPN: none)
Type "help" for help.
```
とPostgreSQL 8ベースであり「一部動かないかもね」って警告メッセージがでます

弊社環境としてRedshift以外にAurora PostgreSQLもあるため、PostgreSQL ClientをRedshiftに合わせるというのも難しい状況です
そこで両方使えるよう、Redshiftに依存しないよう考えたいと思います

個人的には思いつく選択肢として
- Redshift RSQL
- PostgreSQL Clientを複数バージョン入れる

でしょうか

## Redshift RSQL
Redshift RSQLはAWSが提供しているCLIツールです

https://docs.aws.amazon.com/ja_jp/redshift/latest/mgmt/rsql-query-tool.html

LinuxではRPMでしか提供されておらず、2023年6月19日が現時点での最新バージョンとなってます
rpmをdebパッケージ化にするのに alien コマンドが使えますが、まずは使えるのかを検証してみます

Redshift用のODBCドライバとRSQLをダウンロードします
```
wget https://s3.amazonaws.com/redshift-downloads/drivers/odbc/2.1.6.0/AmazonRedshiftODBC-64-bit-2.1.6.0.x86_64.rpm
wget https://s3.amazonaws.com/redshift-downloads/amazon-redshift-rsql/1.0.8/AmazonRedshiftRsql-1.0.8.x86_64.rpm
```

rpmの中身を見るためにrpm2cpioをインストールします
```
$ sudo apt install rpm2cpio
```
rpmからファイルを抜き出します
```
$ rpm2cpio AmazonRedshiftODBC-64-bit-2.1.6.0.x86_64.rpm | cpio --list
./opt/amazon/redshiftodbcx64/amazon.redshiftodbc.ini
./opt/amazon/redshiftodbcx64/librsodbc64.so
./opt/amazon/redshiftodbcx64/odbc.csh
./opt/amazon/redshiftodbcx64/odbc.ini
./opt/amazon/redshiftodbcx64/odbc.sh
./opt/amazon/redshiftodbcx64/odbcinst.ini
./opt/amazon/redshiftodbcx64/root.crt
./opt/amazon/redshiftodbcx64/rsodbcsql
./opt/amazon/redshiftodbcx64/samples/connect/connect
./opt/amazon/redshiftodbcx64/samples/connect/connect.c
./opt/amazon/redshiftodbcx64/samples/connect/connect.mak
277765 blocks
$ rpm2cpio AmazonRedshiftODBC-64-bit-2.1.6.0.x86_64.rpm | cpio -id
277765 blocks
$ rpm2cpio AmazonRedshiftRsql-1.0.8.x86_64.rpm | cpio --list
./usr/share/aws/rsql/bin/rsql
./usr/share/aws/rsql/lib/libpq.so
./usr/share/aws/rsql/lib/libpq.so.5
./usr/share/aws/rsql/lib/libpq.so.5.1
./usr/share/aws/rsql/readme.txt
2389 blocks
$ rpm2cpio AmazonRedshiftRsql-1.0.8.x86_64.rpm | cpio -id
2389 blocks
```

実行ファイルとライブラリが使用するライブラリを確認してみます
```shell:AmazonRedshiftODBC
$ ldd librsodbc64.so
        linux-vdso.so.1 (0x00007ffcd6fca000)
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f0afac1c000)
        libresolv.so.2 => /lib/x86_64-linux-gnu/libresolv.so.2 (0x00007f0afac09000)
        libkeyutils.so.1 => /lib/x86_64-linux-gnu/libkeyutils.so.1 (0x00007f0afac02000)
        libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f0afabfd000)
        librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f0afabf8000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f0af9717000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f0af9505000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f0afac29000)
$ ldd rsodbcsql
        linux-vdso.so.1 (0x00007ffe6c1fe000)
        libodbc.so.2 => /lib/x86_64-linux-gnu/libodbc.so.2 (0x00007fecd47c9000)
        libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fecd454b000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fecd4462000)
        libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fecd4434000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fecd4222000)
        libltdl.so.7 => /lib/x86_64-linux-gnu/libltdl.so.7 (0x00007fecd4215000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fecd4841000)
```
```shell:AmazonRedshiftRsql
$ ldd rsql 
        linux-vdso.so.1 (0x00007ffdbfb98000)
        libodbc.so.2 => /lib/x86_64-linux-gnu/libodbc.so.2 (0x00007f0d4c7ae000)
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f0d4c7a9000)
        libssl.so.10 => not found
        libcrypto.so.10 => not found
        libreadline.so.6 => not found
        librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f0d4c7a2000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f0d4c6b9000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f0d4c4a7000)
        libltdl.so.7 => /lib/x86_64-linux-gnu/libltdl.so.7 (0x00007f0d4c49c000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f0d4c826000)
$ ldd libpq.so.5.1
        linux-vdso.so.1 (0x00007ffdd3907000)
        libssl.so.1.1 => not found
        libcrypto.so.1.1 => not found
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fd4ee365000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fd4ee153000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fd4ee3bf000)
```

ODBCドライバはぱっと見では大丈夫そうですが、RSQLパッケージ側がOpenSSLとreadlineのライブラリがないようです
```
$ ldconfig -p | grep libssl.so
        libssl.so.3 (libc6,x86-64) => /lib/x86_64-linux-gnu/libssl.so.3
        libssl.so (libc6,x86-64) => /lib/x86_64-linux-gnu/libssl.so
$ ldconfig -p | grep libcrypto.so
        libcrypto.so.3 (libc6,x86-64) => /lib/x86_64-linux-gnu/libcrypto.so.3
        libcrypto.so (libc6,x86-64) => /lib/x86_64-linux-gnu/libcrypto.so
$ ldconfig -p | grep libreadline.so
        libreadline.so.8 (libc6,x86-64) => /lib/x86_64-linux-gnu/libreadline.so.8
        libreadline.so (libc6,x86-64) => /lib/x86_64-linux-gnu/libreadline.so
```

not foundとなっている3つともUbuntu 24.04LTSよりバージョンが古いものを必要としています
特に、OpenSSLは1.0系と1.1系が必要そうですが、1.0系・1.1系はすでにEOLとなってます
また、libpq.soはPostgreSQLのライブラリですが、Ubuntu 24.04LTSのバージョンと比較するとこれもかなり古いです
```
$ ldconfig -p | grep libpq.so
        libpq.so.5 (libc6,x86-64) => /lib/x86_64-linux-gnu/libpq.so.5
$ ls -l /lib/x86_64-linux-gnu/libpq.so.5*
lrwxrwxrwx 1 root root     13 Nov 19 23:36 /lib/x86_64-linux-gnu/libpq.so.5 -> libpq.so.5.17
-rw-r--r-- 1 root root 354496 Nov 19 23:36 /lib/x86_64-linux-gnu/libpq.so.5.17
```
現時点で1年半もリリースがされておらず、OpenSSLものEOLのバージョンのままのでRSQLを使用するのは微妙なのでこちらは断念します

## PostgreSQL Clientを複数バージョン入れる
Ubuntuのpsqlコマンドは **pg_wrapper** というPerlスクリプトのsymlinkとなっており、このスクリプトが複数バージョンを切り替えて使用できるようになっています
（pg_wrapperはpostgresql-client-commonに含まれています）

実際のPostgreSQL Clientは `/usr/lib/postgresql/{version}` 下にインストールされてます

```shell
$ which psql
/usr/bin/psql
$ ls -l /usr/bin/psql
lrwxrwxrwx 1 root root 37 Aug  9 11:33 /usr/bin/psql -> ../share/postgresql-common/pg_wrapper*
$ file /usr/share/postgresql-common/pg_wrapper
/usr/share/postgresql-common/pg_wrapper: Perl script text executable
```
https://manpages.ubuntu.com/manpages/noble/man1/pg_wrapper.1.html

PostgreSQL Clientを複数バージョンインストールできるようにレポジトリを追加します
```shell
$ sudo apt install -y postgresql-common
$ sudo /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh
$ apt list postgresql-client*
Listing... Done
postgresql-client-10-dbgsym/noble-pgdg 10.23-7.pgdg24.04+1 amd64
postgresql-client-10/noble-pgdg 10.23-7.pgdg24.04+1 amd64
postgresql-client-11-dbgsym/noble-pgdg 11.22-9.pgdg24.04+1 amd64
postgresql-client-11/noble-pgdg 11.22-9.pgdg24.04+1 amd64
postgresql-client-12-dbgsym/noble-pgdg 12.22-2.pgdg24.04+1 amd64
postgresql-client-12/noble-pgdg 12.22-2.pgdg24.04+1 amd64
postgresql-client-13-dbgsym/noble-pgdg 13.18-1.pgdg24.04+1 amd64
postgresql-client-13/noble-pgdg 13.18-1.pgdg24.04+1 amd64
postgresql-client-14-dbgsym/noble-pgdg 14.15-1.pgdg24.04+1 amd64
postgresql-client-14/noble-pgdg,now 14.15-1.pgdg24.04+1 amd64
postgresql-client-15-dbgsym/noble-pgdg 15.10-1.pgdg24.04+1 amd64
postgresql-client-15/noble-pgdg,now 15.10-1.pgdg24.04+1 amd64
postgresql-client-16-dbgsym/noble-pgdg 16.6-1.pgdg24.04+1 amd64
postgresql-client-16/noble-pgdg 16.6-1.pgdg24.04+1 amd64
postgresql-client-17-dbgsym/noble-pgdg 17.2-1.pgdg24.04+1 amd64
postgresql-client-17/noble-pgdg,now 17.2-1.pgdg24.04+1 amd64 [installed,automatic]
postgresql-client-8.2/noble-pgdg 8.2.23-13.pgdg24.04+1 amd64
postgresql-client-8.3/noble-pgdg 8.3.23-10.pgdg24.04+1 amd64
postgresql-client-8.4/noble-pgdg 8.4.22-11.pgdg24.04+1 amd64
postgresql-client-9.0/noble-pgdg 9.0.23-11.pgdg24.04+1 amd64
postgresql-client-9.1/noble-pgdg 9.1.24-17.pgdg24.04+1 amd64
postgresql-client-9.2/noble-pgdg 9.2.24-14.pgdg24.04+1 amd64
postgresql-client-9.3/noble-pgdg 9.3.25-13.pgdg24.04+1 amd64
postgresql-client-9.4/noble-pgdg 9.4.26-13.pgdg24.04+1 amd64
postgresql-client-9.5/noble-pgdg 9.5.25-11.pgdg24.04+1 amd64
postgresql-client-9.6/noble-pgdg 9.6.24-10.pgdg24.04+1 amd64
postgresql-client-common/noble-pgdg,now 267.pgdg24.04+1 all [installed,automatic]
postgresql-client/noble-pgdg,now 17+267.pgdg24.04+1 all [installed]
```
RedshiftがPostgreSQL 8.0ベースなので `postgresql-client-8.2` をインストールしてもいいのですが、postgresql-client-14 でもエラーとなっていたメタコマンドが正常に動作したので 14 をインストールします
```shell
$ sudo apt install -y postgresql-client-14
```

ただし、pg_wrapperの128～136行目の以下の箇所でpsqlはインストール済の最新バージョンを使用するようになっており、psqlでは常に最新バージョンを使うようになっています
```perl:/usr/share/postgresql-common/pg_wrapper
# if we have no version yet, use the latest version. If we were called as psql,
# pg_archivecleanup, or pg_isready, always use latest version
if (not $version or $cmdname =~ /^(psql|pg_archivecleanup|pg_isready)$/) {
    my $max_version;
    if ($version and $version < 9.2) { # psql 15 only supports PG 9.2+
        $max_version = 14;
    }
    $version = get_newest_version($cmdname, $max_version);
}
```
今回、psqlでAWS上のRedshiftとAuroraにしか使用しないため、psqlでもバージョン切り替えができるようにpg_wrapperを変更します 

postgresql-client-commonをUpdateすると元に戻ってしまうため、このスクリプトをHomeディレクトリ化にコピーします
```shell
$ mkdir $HOME/bin
$ cp /usr/share/postgresql-common/pg_wrapper $HOME/bin
```
コピーしたpg_wrapperを以下のように修正します
```diff:$HOME/bin/pg_wrapper
--- /usr/share/postgresql-common/pg_wrapper     2024-11-21 19:54:02.000000000 +0900
+++ bin/pg_wrapper      2025-02-06 15:04:20.478248118 +0900
@@ -127,7 +127,7 @@
 
 # if we have no version yet, use the latest version. If we were called as psql,
 # pg_archivecleanup, or pg_isready, always use latest version
-if (not $version or $cmdname =~ /^(psql|pg_archivecleanup|pg_isready)$/) {
+if (not $version or $cmdname =~ /^(pg_archivecleanup|pg_isready)$/) {
     my $max_version;
     if ($version and $version < 9.2) { # psql 15 only supports PG 9.2+
         $max_version = 14
```
修正後、psqlのsymlinkを作成し `$HOME/bin`を先に参照するように環境変数 PATH に追加します
```shell
$ cd $HOME/bin
$ ln -sf pg_wrapper psql
$ export PATH=$HOME/bin:$PATH
```

pg_wrapperでのバージョンを切り替えての使用は以下となるので
```
$ psql --client {version}/{host}:{port} -U {username} {database}
```
Redshiftへの接続の場合は以下となります
```
$ psql --client 14/redshift:5439 -U awsuser dev
psql (14.15 (Ubuntu 14.15-1.pgdg24.04+1), server 8.0.2)
SSL connection (protocol: TLSv1.2, cipher: ECDHE-RSA-AES256-GCM-SHA384, bits: 256, compression: off)
Type "help" for help.
```
Aurora PostgreSQLの15バージョンでは以下で接続できます
```
$ psql --client 15/aurora:5432 -U postgres postgres
psql (15.10 (Ubuntu 15.10-1.pgdg24.04+1), server 15.4)
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, compression: off)
Type "help" for help.
```
`-h`で指定した場合は最新の 17 のものが使用されます
```
$ psql -h aurora -p 5432 -U postgres postgres
psql (17.2 (Ubuntu 17.2-1.pgdg24.04+1), server 15.4)
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, compression: off, ALPN: none)
Type "help" for help.
```
psqlコマンドで `--client` を指定するのはあまり慣れていないですが、やりたいことは達成できました