背景
Testcontainersでgvenzl/oracle-xeを使用してdockerにOracle XEを起動する際、SYSとしてデフォルトPDBのXEPDB1に初期化SQLを実行したい。
やり方など
詳細は公式ドキュメント https://hub.docker.com/r/gvenzl/oracle-xe の Initialization scripts に解説がある。
まず、コンテナの機能で/container-entrypoint-initdb.d ディレクトリ下へ *.sql を配置するとDB初期化時にこれらを実行する。次に、testcontainersのwithCopyFileToContainerでホストのファイルをコンテナにコピーできる。なので、これらを組み合わせて使用する。またポイントとしてSYS ユーザでこれらSQLを実行する。なので、権限が必要な初期化処理はこれを利用する。
サンプルのソースコードは以下の通り。
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.containers.OracleContainer;
import org.testcontainers.utility.MountableFile;
@Container
@ServiceConnection
static OracleContainer oracle = new OracleContainer("gvenzl/oracle-xe:21.3.0-slim-faststart")
.withCopyFileToContainer(
MountableFile.forClasspathResource("create_tablespace.sql"), "/container-entrypoint-initdb.d/init.sql");
MountableFile.forClasspathResourceでクラスパス下のファイルを/container-entrypoint-initdb.d/init.sqlというディレクトリ・ファイル名として配置している。以下はサンプルSQLとしてtablespaceを作成している。ポイントはalter sessionでPDBのXEPDB1に変更している。
alter session set container = XEPDB1;
CREATE TABLESPACE TBS_DATA_01 DATAFILE '/opt/oracle/oradata/XE/tbsdata01.dbf' SIZE 250M;
はまった点
alter session set container = XEPDB1をしないとPDBで実行しないので、あとで一般ユーザでアクセスすると存在しないエラーになってしまう。なので、初期化SQLが成功したのに何も実行されてないように見えてしまう。
alter session... 無し時の実行時のログを見ると、
STDOUT: CONTAINER: running /container-entrypoint-initdb.d/init.sql ...
(省略)
STDOUT: Completed: CREATE TABLESPACE TBS_DATA_01 DATAFILE '/opt/oracle/oradata/XE/tbsdata01.dbf' SIZE 250M
STDOUT: CREATE TABLESPACE TBS_DATA_01 DATAFILE '/opt/oracle/oradata/XE/tbsdata01.dbf' SIZE 250M
のように問題無く初期化SQLが実行されたように見えるが、テスト実行時に実際に使用するXEPDB1に作成したわけでは無い。なので、何も実行されてない、と勘違いしてしまった。oracleのCDPとPDBの関係を知っていれば何てこと無い話だが、普段あまり意識しない点なのではまってしまった。
以下はalter session (略) XEPDB1有りの実行時のログ。ログにもXEPDB1が含まれるのが分かる。
STDOUT: XEPDB1(3):Completed: CREATE TABLESPACE TBS_DATA_01 DATAFILE '/opt/oracle/oradata/XE/tbsdata01.dbf' SIZE 250M
STDOUT: XEPDB1(3):CREATE TABLESPACE TBS_DATA_01 DATAFILE '/opt/oracle/oradata/XE/tbsdata01.dbf' SIZE 250M