システムユーザでの実行

概要

通常、ReplaceSchemaは "スキーマ(もしくはデータベース)インスタンスやDBユーザ自体は既に作成されていること" を前提としています。 例えば、ディベロッパーがローカルに開発用DB環境を構築しようとしたときに以下の手順を踏みます:

  • A. DBをインストール
  • B. DBツール(システムユーザ)でユーザとスキーマの作成
  • C. ReplaceSchemaの実行(テーブルなどが作成される)

この手順の "B" のステップを、DBFluteに "システムユーザの接続情報" と "システムユーザで実行するDDL" を定義することで、ReplaceSchemaの中で実行することが可能です。

システムユーザの接続情報

replaceSchemaDefinitionMap.dfprop の additionalUserMap にて、システムユーザを定義します。

e.g. additionalUserMapの定義("system" という名前の定義) @replaceSchemaDefinitionMap.dfprop
; additionalUserMap = map:{
    ; system = map:{
        #; url = ...
        ; user = system
        ; password = orcl
    }
}

接続URLがアプリユーザの接続情報と変わる場合は "url" も指定します。

パスワードファイルの利用

システムユーザのパスワードをディベロッパー間で統一できない場合は、 バージョン管理システムではコミットしない(SVN-Ignoreなど)外だしのパスワードファイルを作成して、 それぞれの環境ごとにパスワードを設定することができます。@since 0.9.8.5

additionalUserMap の password では、df:dfprop/ に続けてパスワードファイル名を指定します。

e.g. パスワードファイルを指定 @replaceSchemaDefinitionMap.dfprop
; additionalUserMap = map:{
    ; system = map:{
        #; url = ...
        ; user = system
        ; password = df:dfprop/system-password.txt
    }
}

"DBFluteクライアント/dfprop" 配下に指定したパスワードファイルを作成し、中身はパスワード文字列のみを記述します。 パスワードファイルのファイル名は任意です。このファイルは、バージョン管理システムではコミットしない設定(SVN-Ignoreなど)にしておきます。 このようにすることで、環境ごとに異なるパスワードを設定することができます。

e.g. パスワードファイルを作成 @Directory
DBFluteクライアント
 |-dfprop
    |-xxx.dfprop
    |-system-password.txt

指定されたファイルが存在しない場合は、例外となります。@since 0.9.8.7 ※それ以前は password を設定しないのと同じ

明示的に(ファイルが存在しない場合の)デフォルトパスワードを設定することもできます。 多くの人のパスワードが統一的だが一部の人だけ違う、というような場合に有効です。 明示的なデフォルトパスワードは、パスワードファイルの定義の後にパイプライン "|" を付けてその後に記述します。

e.g. パスワードファイルがない場合のデフォルトパスワード(orcl)を指定 @replaceSchemaDefinitionMap.dfprop
; additionalUserMap = map:{
    ; system = map:{
        #; url = ...
        ; user = system
        ; password = df:dfprop/system-password.txt|orcl
    }
}

空パスワードをデフォルトパスワードにしたい場合は、"|" だけ後ろに付けて空っぽにします。

e.g. パスワードファイルがない場合は空パスワードを指定 @replaceSchemaDefinitionMap.dfprop
; additionalUserMap = map:{
    ; system = map:{
        #; url = ...
        ; user = system
        ; password = df:dfprop/system-password.txt|
    }
}

システムユーザで実行するDDL

実行ユーザの一時的切り替え

通常 ReplaceSchema は、databaseInfoMap.dfprop にて定義されたユーザで実行されます。

スキーマ作成のDDLにおいて、 -- #df:changeUser([システムユーザ情報の名前])# というSQLコメントを定義することで、ReplaceSchemaの中で一時的にシステムユーザに切り替えることが可能です。 "システムユーザ情報の名前" は additionalUserMap にて定義されたものとなります。

e.g. システムユーザに切り替え("system" という名前の定義を利用) @replace-schema-xxx.sql
-- #df:changeUser(system)#
create user ...;
grant ...;

以下の条件で実行ユーザが元のユーザに戻ります:

  • 該当のSQLファイルが終了する
  • -- #df:backToMainUser()# が指定される

基本的には、システムユーザで実行するDDLだけを定義する個別のSQLファイルを用意して、 アプリユーザで実行するSQLファイルと別にすることをお奨めします。

e.g. システムユーザ用のSQLを分ける @playsql
playsql
 |-replace-schema-00-system.sql
 |-replace-schema-10-basic.sql
 |-replace-schema-20-view.sql
 |-...

アプリユーザの存在チェック

checkUser() の基本

ReplaceSchemaを実行する度にアプリユーザを作成するのではなく、既にユーザが存在する場合は以降の "システムユーザで実行するSQL" を実行しないで続行するようにします。ユーザを作成するDDLの定義箇所で -- #df:checkUser()# というSQLコメントを定義することで、そのユーザが既に存在する場合に以降のシステムユーザでの実行を無効になります。

e.g. ユーザが既に存在する場合は権限付与は実行しない (Oracle) @replace-schema-xxx.sql
-- #df:changeUser(system)#
-- #df:checkUser()#
create user /*$dfprop.mainUser*/ identified by /*$dfprop.mainPassword*/;

grant connect to /*$dfprop.mainUser*/;
grant resource to /*$dfprop.mainUser*/;
grant create view to /*$dfprop.mainUser*/;
grant create synonym to /*$dfprop.mainUser*/;
grant create database link to /*$dfprop.mainUser*/;
grant create public database link to /*$dfprop.mainUser*/;
grant create materialized view to /*$dfprop.mainUser*/;

ユーザ名やパスワードなどは、変数のフィルタ機能を利用して指定すると良いでしょう。

checkUser() の目的指定

-- #df:checkUser([目的, 目的, ...])# という形式で、明示的にチェックの目的を指定することができます(@since 0.9.8.8)。 このようにすることで、スキーマはもともと存在していてユーザだけを新しく作成するというような場合に、DBFluteが自動でその状況を判断して、 システムユーザでの実行後に自動で(その前にスキップされた)スキーマ初期化処理が再実行されます。 つまり、目的がわかることで、DBFluteがそういった微調整を自動で判断して行うことができるようになります。

e.g. ユーザだけを作成するパターンが存在する (MySQL) @replace-schema-xxx.sql
-- #df:changeUser(system)#
-- #df:checkUser(mainSchema)#
create database /*$dfprop.mainCatalog*/;

-- #df:reviveUser()#
-- #df:checkUser(mainUser, grant)#
grant all privileges on /*$dfprop.mainCatalog*/.*
  to /*$dfprop.mainUser*/@localhost identified by '/*$dfprop.mainPassword*/';

flush privileges;

checkUser() の補足

この "checkUser" 機能は、単に該当SQLの実行が失敗するか否かだけを判定して、そのユーザでのそれ以降でのSQLの実行するかどうかを決めているので、 他の目的で同じような挙動をしたい場合があるならば、この機能をそのまま利用することができます。

また、ユーザを drop して再作成することはできません。なぜなら、ユーザが既に存在する場合は ReplaceSchema 自身が既にそのユーザで接続をしているからです。DBMSによって挙動は変わる可能性はありますが、基本的に接続中にセッションがあるユーザは drop できません。一度作ったユーザは以降の ReplaceSchema 実行時もそのまま利用することを前提としています。

アプリユーザが存在していても実行したいDDL

アプリユーザが既に存在していも、常にシステムユーザで実行したい(する必要がある)DDLがある場合は、 -- #df:reviveUser()# というSQLコメントが定義することで、それ以降のSQLを再度システムユーザで実行することができます。

e.g. ユーザが既に存在する場合でも実行したいSQLがある場合 @replace-schema-xxx.sql
-- #df:changeUser(system)#
-- #df:checkUser(mainSchema, mainUser)#
create user /*$dfprop.mainUser*/ identified by /*$dfprop.mainPassword*/;

grant connect to /*$dfprop.mainUser*/;
grant resource to /*$dfprop.mainUser*/;
grant create view to /*$dfprop.mainUser*/;
...

-- #df:reviveUser()#
-- #df:checkUser(grant)#
grant SELECT on /*$nextSchema*/.VENDOR_NEXT_SCHEMA to /*$dfprop.mainUser*/;
grant SELECT on /*$nextSchema*/.VENDOR_NEXT_SCHEMA_STATUS to /*$dfprop.mainUser*/;
grant SELECT on /*$nextSchema*/.VENDOR_NEXT_SCHEMA_SECRET_AUTH to /*$dfprop.mainUser*/;
...
grant EXECUTE on /*$nextSchema*/.FN_NEXT_SYNONYM_SAME_NAME to /*$dfprop.mainUser*/;
grant EXECUTE on /*$nextSchema*/.NEXT_PKG to /*$dfprop.mainUser*/;
grant EXECUTE on /*$nextSchema*/.VD_NEXT_SYNONYM_PROCEDURE to /*$dfprop.mainUser*/;

再度システムユーザで実行する場合も、"checkUser" 機能が利用出来ます。 例えば、最初の権限付与が失敗したら、それ以降の権限付与のSQLは実行しないというような挙動にできます。

主に、サブスキーマ(サブデータベース)のオブジェクトに対する権限などに有効です。 例えば、サブスキーマのオブジェクトが再作成された場合に(例えばサブスキーマのReplaceSchemaを実行するなど)、 メインスキーマ自体は何も変わっていなくても、メインユーザの権限がなくなっている可能性があります(DBMSによって挙動が違う可能性あり)。

環境ごとの実行チェック

システムユーザで実行するDDLは、環境によっては実行したくない(する必要がない)ということが想定されます。 例えば、ディベロッパーのローカル開発環境構築の手間を省くための "ユーザ作成SQL" は、既にユーザなどの環境が整っている(かもしれない)結合テスト環境や(最初のリリース時の)本番環境では実行したくありません。

"環境ごとの実行チェック" 機能を併用して、例えば "ut" の場合のみ実行されるようにできます。

e.g. システムユーザに切り替え("system" という名前の定義を利用) @replace-schema-xxx.sql
-- #df:checkEnv(ut)#

-- #df:changeUser(system)#
create user ...;
grant ...;

ユーザ作成SQLのExample

MySQL

例えば、MySQLで開発用のユーザとスキーマ(データベース)を作成する場合は、以下のようになります。 (0.9.8.8 以前であれば、checkUserの引数は指定は削除すること)

e.g. MySQLでのユーザ作成SQL (ut環境のみで動作するように指定) @replace-schema-00-system.sql
-- #df:changeUser(system)#
-- #df:checkUser(mainSchema)#
create database /*$dfprop.mainCatalog*/;

-- #df:reviveUser()#
-- #df:checkUser(mainUser, grant)#
grant all privileges on /*$dfprop.mainCatalog*/.*
  to /*$dfprop.mainUser*/@localhost identified by '/*$dfprop.mainPassword*/';

flush privileges;

上記内容のSQLファイル "replace-schema-00-system.sql" を以下からダウンロードできます。

reps-00-system-for-mysql.zip

Oracle

e.g. Oracleでのユーザ作成SQL (ut環境のみで動作するように指定) @replace-schema-00-system.sql
-- #df:changeUser(system)#
-- #df:checkUser(mainSchema, mainUser)#
create user /*$dfprop.mainUser*/ identified by /*$dfprop.mainPassword*/;

-- #df:reviveUser()#
-- #df:checkUser(grant)#
grant connect to /*$dfprop.mainUser*/;
grant resource to /*$dfprop.mainUser*/;
grant create view to /*$dfprop.mainUser*/;
grant create synonym to /*$dfprop.mainUser*/;
grant create database link to /*$dfprop.mainUser*/;
grant create public database link to /*$dfprop.mainUser*/;
grant create materialized view to /*$dfprop.mainUser*/;

サブスキーマのユーザでの利用(非推奨)

この機能は、特にシステムユーザでなくても利用可能な機能です。例えば、サブスキーマのユーザに切り替えで実行するようなことも可能です。 但し、この機能はあまりそういう利用方法を想定していません。なぜなら、サブスキーマに関してはサブスキーマ側で "ReplaceSchema" 環境を構築して(DBFluteクライアントをもう一つ用意して)構成管理をする方が管理しやすいからです。