はじめに
これは 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
手順
概要
- PostgreSQL を立ち上げ、空の DB を準備する
- PostgreSQL をインストールする
- database.yml を MySQL から PostgreSQL の設定に変更する
- PostgreSQL のユーザーとデータベースを作成する
- 依存するソフトウェアをインストールする
- PostgreSQL をマイグレーションする
- Redmine を停止する
- 運用中の MySQL の SQL ダンプを取得する
- Embulk で DB を移行する
- WSL 内で MySQL を立ち上げ、仮の DB を用意する
- ダンプした運用中の DB を仮の DB にリストアする
- WSL 内に Embulk の環境を構築する
- Embulk を実行して移行する
詳細
1. PostgreSQL を立ち上げ、空のDBを準備する
以下の流れについては Redmineのインストール - Redmineガイド を参照されることをお勧めします。
- PostgreSQL をインストールする
-
database.ymlを MySQL から PostgreSQL の設定に変更する - PostgreSQL のユーザーとデータベースを作成する
- 依存するソフトウェアをインストールする
-
database.ymlのadapterをpostgresqlに変更後、bundle installを実施することで、PostgreSQL 用の gem がインストールされます
-
- PostgreSQL をマイグレーションする
bundle exec rake db:migrate RAILS_ENV=productionbundle 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 に対応するため )
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 }} # 追加
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 }} # 追加
# !/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は未検証です。