背景
古い Windows Server で動作する ASP アプリケーションを、EOL 対応に伴い新しいサーバーへ移行していた。
On Error Resume Next でエラーが流れることもあり(これはコードの問題だが...)、原因を特定解決するのに少しだけ時間がかかったので、メモとしてこれを残していますmm
概要
1. 発生した事象
動作する ASP アプリケーションのサーバーを、新しいものへと移行したところ、DB 接続がうまくいかなくなったため、プロバイダーを変更することで対応した。
- BEFORE:
MSDASQL.1 - AFTER:
OraOLEDB.Oracle
ある程度 ASP アプリケーションは動作したが、一部のページ処理で Type mismatch エラーが発生していた。
(そもそも ODBC にしないんかい!というツッコミはおいといて...)
2. 具体的なコード
任意の SQL を実行した結果を取り出した場合
Set conn = Server.CreateObject("ADODB.Connection")
'~ 中略 ~'
Set result = conn.Execute(strSql)
Dim USER_ID
USER_ID = rs("ID")
以下のような判定コードを実行した際に問題が発生した。
If USER_ID = 0 Then
Type mismatch エラーだったので、簡易コードで出力してみたところ..
Response.Write VarType(USER_ID)
そうすると出力結果は 14 であることがわかった。14 は ASP において Decimal 型なので、ここが問題であった。
3. 原因
どうやらプロバイダーによる型の扱いの違いが問題のようだった。
-
MSDASQL.1: 型変換がゆるく ASP のVariant型に自動的にマッピングすることが多い -
OraOLEDB.Oracle: 型をより厳密に扱い、Decimal型として返すことがある
つまり、プロバイダーを変更したことによって、DB から値を取り出した時の型が変わってしまったようである。
対策
方法①
Decimal 型は他の数値型(Integer, Long, Double, など)を直接比較できないため、呼び出し元で型を変換して解決します。
- If USER_ID = 0 Then
+ If CLng(USER_ID) = 0 Then
上記では Decimal 型を Long 型に明示的に変換することで、比較を可能としています。
また、以下のようにすることでより安全なコードになります。
If IsNumeric(USER_ID) And CLng(USER_ID) = 0 Then
Null, Empty, 文字列(数値以外), オブジェクト などが入る可能性がある場合もあるため、数値型であることを事前に担保できます。
方法②
値を取り出す際にキャストして解決する方法もあります。
Set result = cnObj.Execute(strSql)
Dim USER_ID
- USER_ID = rs("ID")
+ USER_ID = CLng(rs("USER_ID"))
こちらも Not isNull(rs("USER_ID")) とか入れておくほうがより安全でしょう。
最後に
昨今は AI を使えば簡単にデバッグできるかと思いきや、ASP (VBScript) は昔から使われている枯れた言語とはいえ、ネット上の学習データが少ないのか、この答えにすぐ辿り着けず...
地道に自分でデバッグコードを差し込んで、答えを見つけられました。原因を見つけた時は、久しぶりにエンジニアっぽいアハ体験をしましたが、AI がない時代ってこんなんだったよな〜と思ったり。笑
これが誰かの役に立つことは薄いかなと思いつつ、ASP のアプリケーションにおいて、同じく EOL をやっている現場はまだあると思うので、その人たちに届けばとmm