0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

RedmineのデータベースをMySQLからPostgreSQLへ移行した(Redmine 6.1 / Embulk 0.11.5 / MySQL 8 / PostgreSQL 18)

0
Posted at

はじめに

これは Windows 上で運用していた Redmine 6.1 のデータベースを、Embulk 0.11.5 を利用して MySQL 8.0 から PostgreSQL 18.4 へ移行した記録です。

本記事は、『RedmineのデータベースをMySQLからPostgreSQLへ移行した』 を参考とさせていただき、2026年8月時点の私の環境に合わせて内容を更新した内容となっています。
元記事の @ryouma_nagare 氏には感謝申し上げます。

環境

  • Windows 11 24H2 ... MySQL, PostgreSQL, Redmine が稼働
  • Ubuntu 24.04.1 (WSL) ... Embulk で利用
  • MySQL 8.0.35
  • PostgreSQL 18.4
  • Redmine 6.1.0 - 6.1.2

手順

概要

  1. PostgreSQL を立ち上げ、空の DB を準備する
    1. PostgreSQL をインストールする
    2. database.yml を MySQL から PostgreSQL の設定に変更する
    3. PostgreSQL のユーザーとデータベースを作成する
    4. 依存するソフトウェアをインストールする
    5. PostgreSQL をマイグレーションする
  2. Redmine を停止する
  3. 運用中の MySQL の SQL ダンプを取得する
  4. Embulk で DB を移行する
    1. WSL 内で MySQL を立ち上げ、仮の DB を用意する
    2. ダンプした運用中の DB を仮の DB にリストアする
    3. WSL 内に Embulk の環境を構築する
    4. Embulk を実行して移行する

詳細

1. PostgreSQL を立ち上げ、空のDBを準備する

以下の流れについては Redmineのインストール - Redmineガイド を参照されることをお勧めします。

  1. PostgreSQL をインストールする
  2. database.yml を MySQL から PostgreSQL の設定に変更する
  3. PostgreSQL のユーザーとデータベースを作成する
  4. 依存するソフトウェアをインストールする
    • database.yml の adapter を postgresql に変更後、 bundle install を実施することで、PostgreSQL 用の gem がインストールされます
  5. PostgreSQL をマイグレーションする
    • bundle exec rake db:migrate RAILS_ENV=production
    • bundle exec rake redmine:plugins:migrate RAILS_ENV=production
    • ※ Windows では RAILS_ENV=production をコマンドの後ろに追加する

2. Redmine を停止する

補足: Redmine を停止しなくても以降の処理は可能ですが、これ以降の変更は移行後の DB に引き継がれません。

3. 運用中の MySQL の SQL ダンプを取得する

MySQL のデータベースを以下のコマンド等でダンプします。

mysqldump -u <ユーザー名> -p <データベース名> > C:/temp/redmine_dump.sql

例: mysqldump -u root -p redmine > C:/temp/redmine_dump.sql

4. Embulk で DB を移行する

Windows 環境で手軽に実行するため、WSL 内に Embulk の環境を構築し、MySQL から PostgreSQL への移行を行います。

事前準備

# 必要なソフトウェアをインストール
sudo apt update
sudo apt install openjdk-8-jdk
sudo apt install mysql-server
sudo apt install mysql-client
sudo apt install postgresql-client

# 必要に応じて作業フォルダを作成する
mkdir ~/embulk_work
cd ~/embulk_work

※ Embulk 0.11.5 は Java 8 を公式サポートしているため、本手順では OpenJDK 8 を利用しています。

4.1 WSL 内で MySQL を立ち上げ、仮の DB を用意する

# MySQL を起動する
sudo service mysql start

# MySQL にログインする(Ubuntu 24.04 では auth_socket 認証により sudo mysql でログイン可能でした)
sudo mysql

# データベースとユーザーを作成する
CREATE DATABASE redmine_restore CHARACTER SET utf8mb4;
CREATE USER 'redmine'@'localhost' IDENTIFIED BY 'password';
GRANT ALL PRIVILEGES ON redmine_restore.* TO 'redmine'@'localhost';

# MySQL からログアウト
exit

4.2 ダンプした運用中の DB を仮の DB にリストアする

mysql -u redmine -p redmine_restore < /mnt/c/temp/redmine_dump.sql
補足: 運用中の MySQL に直接接続した場合の失敗例

Windows の localhost で運用中の MySQL に直接接続した場合、以下のようなエラーが出て接続できませんでした( mysql コマンドでは繋がることを確認 )。

詳細
org.embulk.exec.PartialExecutionException: java.lang.RuntimeException: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure

The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.
        at org.embulk.exec.BulkLoader$LoaderState.buildPartialExecuteException(BulkLoader.java:340)
        at org.embulk.exec.BulkLoader.doRun(BulkLoader.java:580)
        at org.embulk.exec.BulkLoader.access$000(BulkLoader.java:36)
        at org.embulk.exec.BulkLoader$1.run(BulkLoader.java:353)
        at org.embulk.exec.BulkLoader$1.run(BulkLoader.java:350)
        at org.embulk.spi.ExecInternal.doWith(ExecInternal.java:26)
        at org.embulk.exec.BulkLoader.run(BulkLoader.java:350)
        at org.embulk.EmbulkEmbed.run(EmbulkEmbed.java:278)
        at org.embulk.EmbulkRunner.runInternal(EmbulkRunner.java:288)
        at org.embulk.EmbulkRunner.run(EmbulkRunner.java:153)
        at org.embulk.cli.EmbulkRun.runInternal(EmbulkRun.java:115)
        at org.embulk.cli.EmbulkRun.run(EmbulkRun.java:24)
        at org.embulk.cli.Main.main(Main.java:53)
        Suppressed: java.lang.NullPointerException
                at org.embulk.exec.BulkLoader.doCleanup(BulkLoader.java:477)
                at org.embulk.exec.BulkLoader$3.run(BulkLoader.java:411)
                at org.embulk.exec.BulkLoader$3.run(BulkLoader.java:408)
                at org.embulk.spi.ExecInternal.doWith(ExecInternal.java:26)
                at org.embulk.exec.BulkLoader.cleanup(BulkLoader.java:408)
                at org.embulk.EmbulkEmbed.run(EmbulkEmbed.java:283)
                ... 5 more
Caused by: java.lang.RuntimeException: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure

The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.
        at org.embulk.input.jdbc.AbstractJdbcInputPlugin.transaction(AbstractJdbcInputPlugin.java:227)
        at org.embulk.exec.BulkLoader.doRun(BulkLoader.java:521)
        ... 11 more
Caused by: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure

The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
        at com.mysql.jdbc.Util.handleNewInstance(Util.java:425)
        at com.mysql.jdbc.SQLError.createCommunicationsException(SQLError.java:989)
        at com.mysql.jdbc.MysqlIO.<init>(MysqlIO.java:341)
        at com.mysql.jdbc.ConnectionImpl.coreConnect(ConnectionImpl.java:2189)
        at com.mysql.jdbc.ConnectionImpl.connectOneTryOnly(ConnectionImpl.java:2222)
        at com.mysql.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:2017)
        at com.mysql.jdbc.ConnectionImpl.<init>(ConnectionImpl.java:779)
        at com.mysql.jdbc.JDBC4Connection.<init>(JDBC4Connection.java:47)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
        at com.mysql.jdbc.Util.handleNewInstance(Util.java:425)
        at com.mysql.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:389)
        at com.mysql.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:330)
        at java.sql.DriverManager.getConnection(DriverManager.java:664)
        at java.sql.DriverManager.getConnection(DriverManager.java:208)
        at org.embulk.input.mysql.MySQLInputPlugin.newConnection(MySQLInputPlugin.java:130)
        at org.embulk.input.mysql.MySQLInputPlugin.newConnection(MySQLInputPlugin.java:27)
        at org.embulk.input.jdbc.AbstractJdbcInputPlugin.transaction(AbstractJdbcInputPlugin.java:213)
        ... 12 more
Caused by: java.net.ConnectException: Connection refused (Connection refused)
        at java.net.PlainSocketImpl.socketConnect(Native Method)
        at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
        at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
        at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
        at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
        at java.net.Socket.connect(Socket.java:607)
        at com.mysql.jdbc.StandardSocketFactory.connect(StandardSocketFactory.java:211)
        at com.mysql.jdbc.MysqlIO.<init>(MysqlIO.java:300)
        ... 29 more

Error: java.lang.RuntimeException: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure

The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.

4.3 WSL 内に Embulk の環境を構築する

各種インストール
# 最新版の Embulk 0.11.5 のインストール
curl --create-dirs -o ~/.embulk/bin/embulk -L https://github.com/embulk/embulk/releases/download/v0.11.5/embulk-0.11.5.jar
chmod +x ~/.embulk/bin/embulk

# jruby のインストール
# ※ Embulk 0.11 系では JRuby のセットアップが必要
mkdir ~/.embulk/lib
wget -P ~/.embulk/lib https://repo1.maven.org/maven2/org/jruby/jruby-complete/9.3.14.0/jruby-complete-9.3.14.0.jar
cat > ~/.embulk/embulk.properties <<EOF
jruby=file://$HOME/.embulk/lib/jruby-complete-9.3.14.0.jar
EOF

# ライブラリのインストール
java -jar ~/.embulk/bin/embulk gem install embulk -v 0.11.5
java -jar ~/.embulk/bin/embulk gem install liquid
java -jar ~/.embulk/bin/embulk gem install embulk-input-mysql
java -jar ~/.embulk/bin/embulk gem install embulk-output-postgresql

# postgresql driver のインストール
# ※ embulk-output-postgresql が内部で利用する PostgreSQL JDBC Driver は古く、PostgreSQL 18.4 環境では接続時にエラーとなったため、最新のドライバを手動でインストールする
wget -P ~/.embulk/lib https://jdbc.postgresql.org/download/postgresql-42.7.8.jar
シェルスクリプト

『RedmineのデータベースをMySQLからPostgreSQLへ移行した』 の記事のスクリプトを参考にさせていただきながら一部変更しています

ファイル構成
|-- extra
|   `-- wiki_content_versions.yml.liquid
|-- mysql2pgsql.sh
`-- mysql2pgsql.yml.liquid
変更点
  • 元の記事で紹介されていた import_in_progresses.yml.liquid と open_id_authentication_associations.yml.liquid は、Redmine 6.1 ではそれぞれ対応するテーブルが存在しないため、準備せず
  • wiki_content_versions の data カラムからの直接の読み取りを止め、MySQL 側で TO_BASE64(data) で文字列として取得した後、Embulk の移行処理後に PostgreSQL 側で decode(data_base64, 'base64') で復元するように変更。これにより、utf-8 だけでなく gzip にも対応しています
  • それぞれの DB で port を指定できるように変更
  • PGSQL_DRIVER_PATH を指定できるように変更( PostgreSQL 18.4 に対応するため )
extra/wiki_content_versions.yml.liquid
in:
  type: mysql
  host: {{ env.MYSQL_HOST }}
  port: {{ env.MYSQL_PORT }}   # 追加
  user: {{ env.MYSQL_USER }}
  password: {{ env.MYSQL_PASS }}
  database: {{ env.MYSQL_DB }}
  default_timezone: "Asia/Tokyo"
  options: {useLegacyDatetimeCode: false, serverTimezone: Asia/Tokyo}
  query: |
    SELECT id
           ,wiki_content_id
           ,page_id
           ,author_id
           # convert(data using utf8) as data -> 直接読み取らない
           ,TO_BASE64(data) AS data_base64  # 事前に用意した `data_base64` カラムに base64 で格納する
           ,compression
           ,comments
           ,updated_on
           ,version
    FROM {{ env.TABLE }}
  column_options:
    # data: {value_type: string}   # 削除
    data_base64: {value_type: string}   # 追加

out:
  type: postgresql
  host: {{ env.PGSQL_HOST }}
  port: {{ env.PGSQL_PORT }}   # 追加
  user: {{ env.PGSQL_USER }}
  password: {{ env.PGSQL_PASS }}
  database: {{ env.PGSQL_DB }}
  table: {{ env.TABLE }}
  default_timezone: "Asia/Tokyo"
  mode: truncate_insert
  column_options:
    # data: {value_type: string}   # 削除
    data_base64: {value_type: string}   # 追加
  driver_path: {{ env.PGSQL_DRIVER_PATH }}   # 追加
mysql2pgsql.yml.liquid
in:
  type: mysql
  host: {{ env.MYSQL_HOST }}
  port: {{ env.MYSQL_PORT }}   # 追加
  user: {{ env.MYSQL_USER }}
  password: {{ env.MYSQL_PASS}}
  database: {{ env.MYSQL_DB }}
  table: {{ env.TABLE }}
  default_timezone: "Asia/Tokyo"
  options: {useLegacyDatetimeCode: false, serverTimezone: Asia/Tokyo}

out:
  type: postgresql
  host: {{ env.PGSQL_HOST }}
  port: {{ env.PGSQL_PORT }}   # 追加
  user: {{ env.PGSQL_USER }}
  password: {{ env.PGSQL_PASS }}
  database: {{ env.PGSQL_DB }}
  table: {{ env.TABLE }}
  mode: truncate_insert
  default_timezone: "Asia/Tokyo"
  driver_path: {{ env.PGSQL_DRIVER_PATH }}   # 追加
mysql2pgsql.sh
# !/bin/bash

#######################################################
# 環境依存値
#######################################################
export MYSQL_HOST=localhost
export MYSQL_PORT=3306
export MYSQL_DB=redmine_restore
export MYSQL_USER=redmine
export MYSQL_PASS=password
MYSQL_BIN=/usr/bin/mysql
export PGSQL_HOST=YOUR_HOST_PG
export PGSQL_PORT=5432
export PGSQL_DB=YOUR_DB_PG
export PGSQL_USER=YOUR_NAME_PG
export PGSQL_PASS=YOUR_PASS_PG
export PGSQL_DRIVER_PATH=$HOME/.embulk/lib/postgresql-42.7.8.jar
PGSQL_BIN=/usr/bin/psql
EMBULK_BIN=~/.embulk/bin/embulk

export PGPASSWORD=${PGSQL_PASS}
export MYSQL_PWD=${MYSQL_PASS}

LOG_FILE=./mysql2pgsql_$(date +'%Y%m%d_%H%M%S').log

#######################################################
# Serial列を持つテーブルの抽出(PostgreSQL)
#######################################################
SERIAL_TABLES=$(export LANG=C ; $PGSQL_BIN ${PGSQL_DB} -h ${PGSQL_HOST} -p ${PGSQL_PORT} -U ${PGSQL_USER} -c '\d' | grep sequence | awk '{print $3}'  | sed -e 's/_id_seq$//g')

#######################################################
# AUTO INCREMENTの値をsequenceに反映
#######################################################
for TABLE in ${SERIAL_TABLES}
do
  # MySQLの該当テーブルからMAX(ID)を取得
  MAX_ID=$(${MYSQL_BIN} ${MYSQL_DB} -h ${MYSQL_HOST} -P ${MYSQL_PORT} -u ${MYSQL_USER} -e " SELECT MAX(ID) from ${TABLE}" --skip-column-names -s)

  # NULLでなければ(PostgreSQLのシーケンスに値をセット
  if [ "${MAX_ID}" != "NULL" ]; then
    $PGSQL_BIN ${PGSQL_DB} -h ${PGSQL_HOST} -p ${PGSQL_PORT} -U ${PGSQL_USER} -c "SELECT setval('${TABLE}_id_seq', ${MAX_ID}, true);" 1>/dev/null
  fi
done

#######################################################
# テーブル一覧の抽出(MySQL)
#######################################################
ALL_TABLES=$(${MYSQL_BIN} ${MYSQL_DB} -h ${MYSQL_HOST} -P ${MYSQL_PORT} -u ${MYSQL_USER} -e "show tables" --skip-column-names -s)

#######################################################
# wiki_content_versions の事前処理(data_base64 カラム追加)
#######################################################
echo "  preparing data_base64 column..."
$PGSQL_BIN ${PGSQL_DB} -h ${PGSQL_HOST} -p ${PGSQL_PORT} -U ${PGSQL_USER} -c \
"ALTER TABLE wiki_content_versions ADD COLUMN IF NOT EXISTS data_base64 text;"

#######################################################
# MySQLからPostgreSQLへテーブルデータを移行
#######################################################
for TABLE in ${ALL_TABLES}
do
  # schema_migrationsは移行しない
  if [ "$TABLE" != "schema_migrations" ]; then
    export TABLE
    echo importing ${TABLE} ...

    #######################################################
    # Embulk 実行
    #######################################################
    # queryが書かれた定義ファイルがある場合はそちらを実行
    if [ -e extra/${TABLE}.yml.liquid ]; then
      java -jar ${EMBULK_BIN} run extra/${TABLE}.yml.liquid 1>>${LOG_FILE}
    # そうでなければ共通の定義ファイル
    else
      java -jar ${EMBULK_BIN} run mysql2pgsql.yml.liquid 1>>${LOG_FILE}
    fi

    # 一応、件数だけ突合
    MYSQL_CNT=$(${MYSQL_BIN} ${MYSQL_DB} -h ${MYSQL_HOST} -P ${MYSQL_PORT} -u ${MYSQL_USER} -e "SELECT COUNT(*) FROM ${TABLE}" --skip-column-names -s)
    PGSQL_CNT=$($PGSQL_BIN ${PGSQL_DB} -h ${PGSQL_HOST} -p ${PGSQL_PORT} -U ${PGSQL_USER} -c "SELECT COUNT(*) FROM ${TABLE}" -t | tr -d ' ')
    if [ ${MYSQL_CNT} == ${PGSQL_CNT} ]; then
      RSLT=match
    else
      RSLT=not match!
    fi

    echo "  ${RSLT} ... MySQL:${MYSQL_CNT} PostgreSQL:${PGSQL_CNT}"
  fi
done

#######################################################
# wiki_content_versions の事後処理(復元 → 削除)
#######################################################
echo "  restoring gzip binary data..."
$PGSQL_BIN ${PGSQL_DB} -h ${PGSQL_HOST} -p ${PGSQL_PORT} -U ${PGSQL_USER} -c \
"UPDATE wiki_content_versions SET data = decode(data_base64, 'base64');"

echo "  dropping data_base64 column..."
$PGSQL_BIN ${PGSQL_DB} -h ${PGSQL_HOST} -p ${PGSQL_PORT} -U ${PGSQL_USER} -c \
"ALTER TABLE wiki_content_versions DROP COLUMN data_base64;"
差分
diff --git a/org b/new
index 2a877fe..609cee4 100644
--- a/org
+++ b/new
@@ -3,16 +3,19 @@
 #######################################################
 # 環境依存値
 #######################################################
-export MYSQL_HOST=YOUR_HOST_MS
-export MYSQL_DB=YOUR_DB_MS
-export MYSQL_USER=YOUR_NAME_MS
-export MYSQL_PASS=YOUR_PASS_MS
-MYSQL_BIN=/bin/mysql
+export MYSQL_HOST=localhost
+export MYSQL_PORT=3306
+export MYSQL_DB=redmine_restore
+export MYSQL_USER=redmine
+export MYSQL_PASS=password
+MYSQL_BIN=/usr/bin/mysql
 export PGSQL_HOST=YOUR_HOST_PG
+export PGSQL_PORT=5432
 export PGSQL_DB=YOUR_DB_PG
 export PGSQL_USER=YOUR_NAME_PG
 export PGSQL_PASS=YOUR_PASS_PG
-PGSQL_BIN=/usr/pgsql-11/bin/psql
+export PGSQL_DRIVER_PATH=$HOME/.embulk/lib/postgresql-42.7.8.jar
+PGSQL_BIN=/usr/bin/psql
 EMBULK_BIN=~/.embulk/bin/embulk
 
 export PGPASSWORD=${PGSQL_PASS}
@@ -23,7 +26,7 @@ LOG_FILE=./mysql2pgsql_$(date +'%Y%m%d_%H%M%S').log
 #######################################################
 # Serial列を持つテーブルの抽出(PostgreSQL)
 #######################################################
-SERIAL_TABLES=$(export LANG=C ; $PGSQL_BIN ${PGSQL_DB} -h ${PGSQL_HOST} -U ${PGSQL_USER} -c '\d' | grep sequence | awk '{print $3}'  | sed -e 's/_id_seq$//g')
+SERIAL_TABLES=$(export LANG=C ; $PGSQL_BIN ${PGSQL_DB} -h ${PGSQL_HOST} -p ${PGSQL_PORT} -U ${PGSQL_USER} -c '\d' | grep sequence | awk '{print $3}'  | sed -e 's/_id_seq$//g')
 
 #######################################################
 # AUTO INCREMENTの値をsequenceに反映
@@ -31,18 +34,25 @@ SERIAL_TABLES=$(export LANG=C ; $PGSQL_BIN ${PGSQL_DB} -h ${PGSQL_HOST} -U ${PGS
 for TABLE in ${SERIAL_TABLES}
 do
   # MySQLの該当テーブルからMAX(ID)を取得
-  MAX_ID=$(${MYSQL_BIN} ${MYSQL_DB} -h ${MYSQL_HOST} -u ${MYSQL_USER} -e " SELECT MAX(ID) from ${TABLE}" --skip-column-names -s)
+  MAX_ID=$(${MYSQL_BIN} ${MYSQL_DB} -h ${MYSQL_HOST} -P ${MYSQL_PORT} -u ${MYSQL_USER} -e " SELECT MAX(ID) from ${TABLE}" --skip-column-names -s)
 
   # NULLでなければ(PostgreSQLのシーケンスに値をセット
   if [ "${MAX_ID}" != "NULL" ]; then
-    $PGSQL_BIN ${PGSQL_DB} -h ${PGSQL_HOST} -U ${PGSQL_USER} -c "SELECT setval('${TABLE}_id_seq', ${MAX_ID}, true);" 1>/dev/null
+    $PGSQL_BIN ${PGSQL_DB} -h ${PGSQL_HOST} -p ${PGSQL_PORT} -U ${PGSQL_USER} -c "SELECT setval('${TABLE}_id_seq', ${MAX_ID}, true);" 1>/dev/null
   fi
 done
 
 #######################################################
 # テーブル一覧の抽出(MySQL)
 #######################################################
-ALL_TABLES=$(${MYSQL_BIN} ${MYSQL_DB} -h ${MYSQL_HOST} -u ${MYSQL_USER} -e "show tables" --skip-column-names -s)
+ALL_TABLES=$(${MYSQL_BIN} ${MYSQL_DB} -h ${MYSQL_HOST} -P ${MYSQL_PORT} -u ${MYSQL_USER} -e "show tables" --skip-column-names -s)
+
+#######################################################
+# wiki_content_versions の事前処理(data_base64 カラム追加)
+#######################################################
+echo "  preparing data_base64 column..."
+$PGSQL_BIN ${PGSQL_DB} -h ${PGSQL_HOST} -p ${PGSQL_PORT} -U ${PGSQL_USER} -c \
+"ALTER TABLE wiki_content_versions ADD COLUMN IF NOT EXISTS data_base64 text;"
 
 #######################################################
 # MySQLからPostgreSQLへテーブルデータを移行
@@ -54,17 +64,20 @@ do
     export TABLE
     echo importing ${TABLE} ...
 
+    #######################################################
+    # Embulk 実行
+    #######################################################
     # queryが書かれた定義ファイルがある場合はそちらを実行
     if [ -e extra/${TABLE}.yml.liquid ]; then
-      ${EMBULK_BIN} run extra/${TABLE}.yml.liquid 1>>${LOG_FILE}
+      java -jar ${EMBULK_BIN} run extra/${TABLE}.yml.liquid 1>>${LOG_FILE}
     # そうでなければ共通の定義ファイル
     else
-      ${EMBULK_BIN} run mysql2pgsql.yml.liquid 1>>${LOG_FILE}
+      java -jar ${EMBULK_BIN} run mysql2pgsql.yml.liquid 1>>${LOG_FILE}
     fi
 
     # 一応、件数だけ突合
-    MYSQL_CNT=$(${MYSQL_BIN} ${MYSQL_DB} -h ${MYSQL_HOST} -u ${MYSQL_USER} -e "SELECT COUNT(*) FROM ${TABLE}" --skip-column-names -s)
-    PGSQL_CNT=$($PGSQL_BIN ${PGSQL_DB} -h ${PGSQL_HOST} -U ${PGSQL_USER} -c "SELECT COUNT(*) FROM ${TABLE}" -t | tr -d ' ')
+    MYSQL_CNT=$(${MYSQL_BIN} ${MYSQL_DB} -h ${MYSQL_HOST} -P ${MYSQL_PORT} -u ${MYSQL_USER} -e "SELECT COUNT(*) FROM ${TABLE}" --skip-column-names -s)
+    PGSQL_CNT=$($PGSQL_BIN ${PGSQL_DB} -h ${PGSQL_HOST} -p ${PGSQL_PORT} -U ${PGSQL_USER} -c "SELECT COUNT(*) FROM ${TABLE}" -t | tr -d ' ')
     if [ ${MYSQL_CNT} == ${PGSQL_CNT} ]; then
       RSLT=match
     else
@@ -73,4 +86,15 @@ do
 
     echo "  ${RSLT} ... MySQL:${MYSQL_CNT} PostgreSQL:${PGSQL_CNT}"
   fi
-done
\ No newline at end of file
+done
+
+#######################################################
+# wiki_content_versions の事後処理(復元 → 削除)
+#######################################################
+echo "  restoring gzip binary data..."
+$PGSQL_BIN ${PGSQL_DB} -h ${PGSQL_HOST} -p ${PGSQL_PORT} -U ${PGSQL_USER} -c \
+"UPDATE wiki_content_versions SET data = decode(data_base64, 'base64');"
+
+echo "  dropping data_base64 column..."
+$PGSQL_BIN ${PGSQL_DB} -h ${PGSQL_HOST} -p ${PGSQL_PORT} -U ${PGSQL_USER} -c \
+"ALTER TABLE wiki_content_versions DROP COLUMN data_base64;"
\ No newline at end of file

4.4 Embulk を実行して移行する

bash mysql2pgsql.sh

その他

  • 使用しているプラグインによっては、リレーションが設定されたテーブルが含まれる場合があり、その際は移行に失敗する恐れがあります。その場合はシェルスクリプトのループの後にスクリプトを追加して、個別に Embulk で移行を行う必要があります。

    • 例(確認したもの):
      • additional_tags プラグイン: additional_taggings(事前に additional_tags が必要)
        • 追加スクリプト

          export TABLE=additional_taggings
          java -jar ${EMBULK_BIN} run mysql2pgsql.yml.liquid 1>>${LOG_FILE}
          
        • エラー例
          importing additional_taggings ...
          org.embulk.exec.PartialExecutionException: java.lang.RuntimeException: org.postgresql.util.              PSQLException: ERROR: テーブル"additional_taggings"への挿入、更新は外部キー制約            "fk_rails_6516da2d80"    反しています
            Detail: テーブル"additional_tags"にキー(tag_id)=(1)がありません
                  at org.embulk.exec.BulkLoader$LoaderState.buildPartialExecuteException(BulkLoader.            java:340)
                  at org.embulk.exec.BulkLoader.doRun(BulkLoader.java:580)
                  at org.embulk.exec.BulkLoader.access$000(BulkLoader.java:36)
                  at org.embulk.exec.BulkLoader$1.run(BulkLoader.java:353)
                  at org.embulk.exec.BulkLoader$1.run(BulkLoader.java:350)
                  at org.embulk.spi.ExecInternal.doWith(ExecInternal.java:26)
                  at org.embulk.exec.BulkLoader.run(BulkLoader.java:350)
                  at org.embulk.EmbulkEmbed.run(EmbulkEmbed.java:278)
                  at org.embulk.EmbulkRunner.runInternal(EmbulkRunner.java:288)
                  at org.embulk.EmbulkRunner.run(EmbulkRunner.java:153)
                  at org.embulk.cli.EmbulkRun.runInternal(EmbulkRun.java:115)
                  at org.embulk.cli.EmbulkRun.run(EmbulkRun.java:24)
                  at org.embulk.cli.Main.main(Main.java:53)
          Caused by: java.lang.RuntimeException: org.postgresql.util.PSQLException: ERROR: テーブル              "additional_taggings"への挿入、更新は外部キー制約"fk_rails_6516da2d80"に違反しています
            Detail: テーブル"additional_tags"にキー(tag_id)=(1)がありません
                  at org.embulk.output.jdbc.AbstractJdbcOutputPlugin.commit(AbstractJdbcOutputPlugin.             java:520)
                  at org.embulk.output.jdbc.AbstractJdbcOutputPlugin.transaction            (AbstractJdbcOutputPlugin   java:463)
                  at org.embulk.exec.BulkLoader$4$1$1.transaction(BulkLoader.java:535)
                  at org.embulk.exec.LocalExecutorPlugin.transaction(LocalExecutorPlugin.java:54)
                  at org.embulk.exec.BulkLoader$4$1.run(BulkLoader.java:530)
                  at org.embulk.spi.util.FiltersInternal$RecursiveControl.transaction(FiltersInternal.             java:85)
                  at org.embulk.spi.util.FiltersInternal.transaction(FiltersInternal.java:43)
                  at org.embulk.exec.BulkLoader$4.run(BulkLoader.java:525)
                  at org.embulk.input.jdbc.AbstractJdbcInputPlugin.transaction(AbstractJdbcInputPlugin.              java:230)
                  at org.embulk.exec.BulkLoader.doRun(BulkLoader.java:521)
                  ... 11 more
          Caused by: org.postgresql.util.PSQLException: ERROR: テーブル"additional_taggings"への挿入、更            新は    キー制約"fk_rails_6516da2d80"に違反しています
            Detail: テーブル"additional_tags"にキー(tag_id)=(1)がありません
                  at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.              java:2736)
                  at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.            java:2421)
                  at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:372)
                  at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:525)
                  at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:435)
                  at org.postgresql.jdbc.PgStatement.executeWithFlags(PgStatement.java:357)
                  at org.postgresql.jdbc.PgStatement.executeCachedSql(PgStatement.java:342)
                  at org.postgresql.jdbc.PgStatement.executeWithFlags(PgStatement.java:318)
                  at org.postgresql.jdbc.PgStatement.executeUpdate(PgStatement.java:291)
                  at org.embulk.output.jdbc.JdbcOutputConnection.executeUpdate(JdbcOutputConnection.            java:641)
                  at org.embulk.output.jdbc.JdbcOutputConnection.collectInsert(JdbcOutputConnection.            java:423)
                  at org.embulk.output.jdbc.AbstractJdbcOutputPlugin.doCommit(AbstractJdbcOutputPlugin.              java:896)
                  at org.embulk.output.jdbc.AbstractJdbcOutputPlugin$3.run(AbstractJdbcOutputPlugin.            java:513)
                  at org.embulk.output.jdbc.AbstractJdbcOutputPlugin$RetryableSQLExecution.call              (AbstractJdbcOutputPlugin.java:1343)
                  at org.embulk.output.jdbc.AbstractJdbcOutputPlugin$RetryableSQLExecution.call              (AbstractJdbcOutputPlugin.java:1331)
                  at org.embulk.util.retryhelper.RetryExecutor.run(RetryExecutor.java:109)
                  at org.embulk.util.retryhelper.RetryExecutor.runInterruptible(RetryExecutor.java:90)
                  at org.embulk.output.jdbc.AbstractJdbcOutputPlugin.withRetry            (AbstractJdbcOutputPlugin   java:1309)
                  at org.embulk.output.jdbc.AbstractJdbcOutputPlugin.withRetry            (AbstractJdbcOutputPlugin   java:1301)
                  at org.embulk.output.jdbc.AbstractJdbcOutputPlugin.commit(AbstractJdbcOutputPlugin.             java:508)
                  ... 20 more
          
          Error: java.lang.RuntimeException: org.postgresql.util.PSQLException: ERROR: テーブル              "additional_taggings"への挿入、更新は外部キー制約"fk_rails_6516da2d80"に違反しています
            Detail: テーブル"additional_tags"にキー(tag_id)=(1)がありません
          
      • additionals プラグイン: dashboards(事前に projects が必要)
        • 追加スクリプト

          export TABLE=dashboards
          java -jar ${EMBULK_BIN} run mysql2pgsql.yml.liquid 1>>${LOG_FILE}
          
        • エラー例
          importing dashboards ...
          org.embulk.exec.PartialExecutionException: java.lang.RuntimeException: org.postgresql.util.PSQLException:   ERROR: テーブ  ル"dashboards"への挿入、更新は外部キー制約"fk_rails_5ad01c40ce"に違反しています
          Detail: テーブル"projects"にキー(project_id)=(8)がありません
                  at org.embulk.exec.BulkLoader$LoaderState.buildPartialExecuteException(BulkLoader.java:340)
                  at org.embulk.exec.BulkLoader.doRun(BulkLoader.java:580)
                  at org.embulk.exec.BulkLoader.access$000(BulkLoader.java:36)
                  at org.embulk.exec.BulkLoader$1.run(BulkLoader.java:353)
                  at org.embulk.exec.BulkLoader$1.run(BulkLoader.java:350)
                  at org.embulk.spi.ExecInternal.doWith(ExecInternal.java:26)
                  at org.embulk.exec.BulkLoader.run(BulkLoader.java:350)
                  at org.embulk.EmbulkEmbed.run(EmbulkEmbed.java:278)
                  at org.embulk.EmbulkRunner.runInternal(EmbulkRunner.java:288)
                  at org.embulk.EmbulkRunner.run(EmbulkRunner.java:153)
                  at org.embulk.cli.EmbulkRun.runInternal(EmbulkRun.java:115)
                  at org.embulk.cli.EmbulkRun.run(EmbulkRun.java:24)
                  at org.embulk.cli.Main.main(Main.java:53)
          Caused by: java.lang.RuntimeException: org.postgresql.util.PSQLException: ERROR: テーブル"dashboards"への挿入    新は外部  キー制約"fk_rails_5ad01c40ce"に違反しています
          Detail: テーブル"projects"にキー(project_id)=(8)がありません
                  at org.embulk.output.jdbc.AbstractJdbcOutputPlugin.commit(AbstractJdbcOutputPlugin.java:520)
                  at org.embulk.output.jdbc.AbstractJdbcOutputPlugin.transaction(AbstractJdbcOutputPlugin.java:463)
                  at org.embulk.exec.BulkLoader$4$1$1.transaction(BulkLoader.java:535)
                  at org.embulk.exec.LocalExecutorPlugin.transaction(LocalExecutorPlugin.java:54)
                  at org.embulk.exec.BulkLoader$4$1.run(BulkLoader.java:530)
                  at org.embulk.spi.util.FiltersInternal$RecursiveControl.transaction(FiltersInternal.java:85)
                  at org.embulk.spi.util.FiltersInternal.transaction(FiltersInternal.java:43)
                  at org.embulk.exec.BulkLoader$4.run(BulkLoader.java:525)
                  at org.embulk.input.jdbc.AbstractJdbcInputPlugin.transaction(AbstractJdbcInputPlugin.java:230)
                  at org.embulk.exec.BulkLoader.doRun(BulkLoader.java:521)
                  ... 11 more
          Caused by: org.postgresql.util.PSQLException: ERROR: テーブル"dashboards"への挿入、更新は外部キー制   "fk_rails_5ad01c40ce"  に違反しています
          Detail: テーブル"projects"にキー(project_id)=(8)がありません
                  at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2736)
                  at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2421)
                  at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:372)
                  at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:525)
                  at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:435)
                  at org.postgresql.jdbc.PgStatement.executeWithFlags(PgStatement.java:357)
                  at org.postgresql.jdbc.PgStatement.executeCachedSql(PgStatement.java:342)
                  at org.postgresql.jdbc.PgStatement.executeWithFlags(PgStatement.java:318)
                  at org.postgresql.jdbc.PgStatement.executeUpdate(PgStatement.java:291)
                  at org.embulk.output.jdbc.JdbcOutputConnection.executeUpdate(JdbcOutputConnection.java:641)
                  at org.embulk.output.jdbc.JdbcOutputConnection.collectInsert(JdbcOutputConnection.java:423)
                  at org.embulk.output.jdbc.AbstractJdbcOutputPlugin.doCommit(AbstractJdbcOutputPlugin.java:896)
                  at org.embulk.output.jdbc.AbstractJdbcOutputPlugin$3.run(AbstractJdbcOutputPlugin.java:513)
                  at org.embulk.output.jdbc.AbstractJdbcOutputPlugin$RetryableSQLExecution.cal   (AbstractJdbcOutputPlugin.  java:1343)
                  at org.embulk.output.jdbc.AbstractJdbcOutputPlugin$RetryableSQLExecution.cal   (AbstractJdbcOutputPlugin.  java:1331)
                  at org.embulk.util.retryhelper.RetryExecutor.run(RetryExecutor.java:109)
                  at org.embulk.util.retryhelper.RetryExecutor.runInterruptible(RetryExecutor.java:90)
                  at org.embulk.output.jdbc.AbstractJdbcOutputPlugin.withRetry(AbstractJdbcOutputPlugin.java:1309)
                  at org.embulk.output.jdbc.AbstractJdbcOutputPlugin.withRetry(AbstractJdbcOutputPlugin.java:1301)
                  at org.embulk.output.jdbc.AbstractJdbcOutputPlugin.commit(AbstractJdbcOutputPlugin.java:508)
                  ... 20 more
          
          Error: java.lang.RuntimeException: org.postgresql.util.PSQLException: ERROR: テーブル"dashboards"への挿入、更新    部キー制  約"fk_rails_5ad01c40ce"に違反しています
          Detail: テーブル"projects"にキー(project_id)=(8)がありません
          
  • 当初は pgloader 3.6.9 で試したのですが、上手くいかずに Embulk での移行を選択しました。尚、最新の pgloader v4-dev は未検証です。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?