ODP.NETのGAC登録

/ .NET, Database

ODP.NETを利用している業務系アプリのWindows 8.1、Windows 10への対応作業中。(主に動作確認レベルですが)
アプリの導入手順としてOracle Clientをインストールしておけば動くはずなのですが、なぜか動きません。
原因はODP.NETがGAC(グローバルアセンブリキャッシュ)に登録されていないため。
ODP.NET(Oracle.DataAccess.dll)を静的参照している場合、それと分かるエラーメッセージなどが出ずにいきなり落ちてしまったりするので結構ハマりがち。
ちなみに少し面倒だけれどもリフレクションを使って動的参照の形で作るといきなり落ちるようなことは防げます。

.Net Frameworkのバージョンが2.0時代の古いアプリなので、Win8.1/10の場合、先にWindowsの機能に「.NET Framework 3.5(2.0)」を追加しておかないと、Oracle Clientのインストーラが.NET 2.0用のODP.NET DLLをGACに登録してくれません。
このような場合に後からGAC登録するには以下のコマンドを実行すれば良いとのこと。(パスは適宜編集してください)

Skylake問題などもあって、企業向けシステムのWindows 10対応が少し早まっているようです。
まぁ、そもそもWindows 7で動いていれば普通に動きそうなものなのですが、High DPIなどの対応まで考慮するとそのままでは厳しい部分もあったりなかったり。


psqlODBC

/ Database

前回に引き続き、PostgreSQL移行の話。

対象のシステムはクライアント側に入れたSQL Serverのストアドプロシージャからサーバ側のデータベースを直接参照する仕組みがあります。
今回はこのサーバDBをOracleからPostgreSQLに変更するので、この部分についても手直しが必要となりました。

サーバDBへの接続は事前定義が必要なリンクサーバ機能は使わず、OPENROWSET関数を用いたアドホックなもの。
OPENROWSET関数ではOLE DBデータソースの利用を前提としており、対Oracle接続では「Microsoft OLE DB Provider for Oracle」、いわゆる’MSDAORA’データプロバイダを利用していたわけですが、PostgreSQLの場合はどのドライバが一般的なのかよく分かりません。
ネイティブなOLE DBプロバイダも存在するようなのですが、試した限りではうまいこと動いてくれなかったため、よりメジャーっぽいODBCドライバ「psqlODBC」のほうを採用することに。
Microsoft OLE DB Provider for ODBC」、いわゆる’MSDASQL’データプロバイダを使うことによって、ODBCデータソースをOLE DBデータソースとして利用することができます。
そんなわけで、Stack Builderを使ってpsqlODBCをインストールして、SQL Server 2008 R2からの接続を試みたわけですが、どうにもうまくいきません。

ちなみにクエリはこんな感じ。

エラーメッセージを見る限り、ドライバが正しく認識されていない様子。
しばし悩んだ挙句、psqlODBCのダウンロードページを見てみると、Stack Builderでインストールされたもの(9.03.0210)よりも新しいバージョン(9.03.0300-1)を発見。
試しにこちらに入れ替えて試したところ、あっさり成功。
この手の話は実際にやってみないと分からないところもあるので厄介ですが、なにかの参考にでもなれば幸いです。


PostgreSQLへの移行

/ Database

ここ最近、Oracleベースで構築されているC/SシステムのPostgreSQLへの移行作業をしています。
ストアドプロシージャなどは個別に用意しますが、クライアント側は単一のアプリを利用するため、両データベースを切り替えて利用できる仕組みになっています。
O/Rマッパーなどは使っていないため、アプリからダイレクトでクエリを投げているわけですが、当然そのままではうまく動かない部分が出てくるので、それをテストで拾っていきます。
このフェイズは「テストが9割」と言われるのも納得の地味な作業。
移行作業についてはこちらにまとまった情報がありますが、最終的には全てのクエリをチェックする必要があるので、やはりそれなりの手数はかかるようです。

今回、単純なクエリに関してはどちらのデータベースでも動くように変更したので、主だったところを紹介してみます。

– to_char/to_number は cast に

PostgreSQLでのto_char/to_number関数は第2引数が必須のため、省略しているとエラーになってしまいます。
もちろん第2引数を指定する形に統一してもよいのですが、単純な数値→文字/文字→数値変換の場合、かえって記述が面倒なので、cast関数に置き換えてしまうのが手っ取り早いかと。
「cast(value as varchar(255))」、「cast(value as numeric)」といった感じでほぼ統一できると思います。

– 日付型に注意

まず、PostgreSQLにはsysdate/systimestamp関数がないので共通クエリは書けず、now、current_date、current_timestampなどの関数に置き換えが必要になるのですが、これらは機械的な置換で対応できるのでさほど問題にはなりません。
ちなみにcurrent_dateなどが返すdate型には時刻情報が含まれないので、sysdateを使っている箇所はtimestamp型を返すnowに置き換えたほうが無難。
to_dateも同様にdate型のため時刻情報はカットされるので、時刻も含めて扱っているにもかかわらず無造作にdate系関数を使っている場合はtimestamp型に変えましょう。

– 「文字型 = 数値」の比較はエラー

雑なクエリを書いていると暗黙の変換に頼って文字型カラム/変数と数値を直接比較したりすることがありますが、これエラーになります。
逆に数値カラム/変数を文字列で比較するぶんには大丈夫なようですが、いずれにしてもきちんと型を意識したほうが良いですね。

– サブクエリのエイリアス省略不可

文字通り、サブクエリにエイリアス名を付けていないとエラーになります。

– 文字列の大小比較は文字列結合よりも優先評価される

これは若干レアケースかもしれませんが、where句の条件で文字列同士を大小比較するときに、文字列結合を併用していると問題が生じる場合があります。
例えば「’20140724′ <= '201407' || '25'」などと書いた場合、Oracleでは文字列結合が先に評価されるのでは素直にtrueを返してくれますが、PostgreSQLでは大小比較のほうが先に評価されてしまい、結果としてboolean値ではなく「false25」といった文字列が返ってきます。もちろんエラー。 「'20140724' <= ('201407' || '25')」のようにカッコを付ければ解決はしますが、ちょっと嫌らしい現象です。 ちなみに比較演算子にイコールが含まれない場合は大丈夫なようなので、ちょっとしたバグの類なのかもしれません。 まぁ、そもそも文字列を大小比較とかいうのがイミフなのでやめときませうw
その他、「nvlをcoalesceに置換」、「from dualが不要」、「rowidがないのでoidで代替」、「months_between、add_monthsがないのでextractで代替」などといった細かい調整も必要でしたが、全体的にそれほど特殊な処理をしていないので概ねスムーズに移行できました。
あまり比べても仕方ないのですが、エラーメッセージが親切だったり、pgAdminツールが便利だったりして、個人的にはOracleよりもPostgreSQLのほうが使いやすい印象でした。
もちろん一番はSQL Serverですがw


バージョンリダイレクト

/ .NET, Database

Oracle ODP.NETの話。
ODP.NETは11gからWindows7に対応しています。
Win7対応アプリの開発なので、11gクライアントをセットアップした開発環境でビルドしているわけですが、ビルドしたモジュールをそのままWinXP+10gクライアントな環境で動作させるとデータベースにうまく接続できずにエラーとなります。
参照しているODP.NETのアセンブリバージョンが合っていないために発生する事象ですが、これを回避すべく「アセンブリバージョンのリダイレクト」という仕組みを試してみました。

方法としては、次のようなアプリケーション構成ファイル(app.config)を用意するだけ。
ハイライト部がバージョンリダイレクトの指定になります。

本来は旧バージョンを下位互換のある新バージョンに置き換えて利用するための仕組みですが、バージョン依存した特別なことをやっていなければ、逆パターンでも普通に動いてくれているようです。