【テクニカル・上級編】【上級】CurrentDb.QueryDefsのSQLプロパティを動的書き換え:SQLインジェクションを防ぐパラメータ管理 – Access VBA解析バイブル

スポンサーリンク

Accessの深淵:QueryDefの動的構築とSQLインジェクションの制圧

Access VBAで「文字列結合によるSQL構築」を行う開発者は、今すぐその手を止めるべきだ。

`”SELECT FROM T_Order WHERE CustomerID = ‘” & Me.txtID & “‘”`

このコードは、コードベースに対する時限爆弾である。SQLインジェクションのリスクは論ずるまでもないが、それ以上に、Accessのデータベースエンジン(ACE)が実行計画を再利用できず、毎回コンパイルオーバーヘッドを発生させるという「パフォーマンス上の罪」を犯している。

本稿では、`CurrentDb.QueryDefs`を使いこなし、セキュリティと実行速度を両立させる「パラメータ管理の極致」を伝授する。

なぜ文字列連結は「悪」なのか

Accessにおいて、`DoCmd.RunSQL`や`CurrentDb.Execute`で文字列を連結して渡すのは、プリコンパイルの恩恵を全て捨てる行為だ。

1. クエリプランのキャッシュ放棄: 文字列が1文字でも変われば、ACEはそれを「未知のクエリ」と見なす。複雑な結合や集計を含むクエリでは、毎回プラン再構築が行われ、I/O負荷が跳ね上がる。
2. 型変換の脆弱性: 文字列連結では、日付型や数値型のフォーマットがロケールに依存し、バグの温床となる。
3. セキュリティ: 悪意あるユーザーがUIを通じてSQLの構造を破壊する余地を残す。

これらを解決する唯一の解が、`QueryDef`オブジェクトの`Parameters`コレクションを用いた、パラメータ化クエリの動的制御である。

実践:QueryDefによるパラメータ管理の実装

既存のクエリを書き換えるのではなく、DAOの`QueryDef`オブジェクトをメモリ上で生成し、型を厳格に定義して実行する手法だ。

‘ 伝説的なアーキテクトによる、安全なクエリ実行の定石
Public Sub ExecuteSecureQuery(ByVal customerID As Long, ByVal targetDate As Date)
Dim db As DAO.Database
Dim qdf As DAO.QueryDef
Dim rs As DAO.Recordset

‘ CurrentDbを不用意に連発しないこと。メモリリークと再接続の温床となる。
Set db = CurrentDb

‘ 永続的なクエリを汚さず、一時的なクエリ定義を作成
‘ SQL内の [pID] や [pDate] がパラメータのプレースホルダーとなる
Set qdf = db.CreateQueryDef(“”, _
“SELECT FROM T_Orders WHERE CustomerID = [pID] AND OrderDate >= [pDate]”)

‘ パラメータの型を明示的に定義する。ここが「防御」の要。
‘ ACEは型を知ることで、最適化された実行計画を構築する。
qdf.Parameters(“pID”).Value = customerID
qdf.Parameters(“pDate”).Value = targetDate

‘ 実行
Set rs = qdf.OpenRecordset(dbOpenSnapshot)

‘ 処理ロジック(省略)

‘ オブジェクトの明示的解放(メモリ管理の鉄則)
rs.Close
qdf.Close
Set rs = Nothing
Set qdf = Nothing
Set db = Nothing
End Sub

このコードが優れている理由

  • 型安全性: `Parameters`コレクションに値を代入する際、VBAの型とACEの型が自動的にネゴシエーションされる。意図しない型変換によるエラーはここで弾かれる。
  • オブジェクトのライフサイクル: `CreateQueryDef`の第一引数に空文字 `””` を渡すことで、データベースウィンドウを汚染しない「テンポラリクエリ」として生成している。関数の終了とともにメモリから掃き出される、極めてクリーンな実装だ。

更なる高みへ:システム間連携とメモリの最適化

大規模なシステム連携や、数万件のレコードを処理する際、`CurrentDb`を安易に呼び出すことは避けるべきだ。`CurrentDb`は呼び出すたびにオブジェクトを再生成する。

  • 静的参照の保持: モジュールレベルの変数で`Database`オブジェクトを保持し、アプリケーションの終了まで使い回せ。ただし、バックエンド(BE)の再リンクが必要な場合は、適切に`Nothing`をセットして再接続を行う必要がある。
  • Windows APIの活用: もしAccessからWin32 APIを叩き、メモリ使用量を監視したり、プロセス管理を行う必要がある場合は、`PtrSafe`宣言を忘れてはならない。64bit版Accessが主流となった今、`Long`と`LongPtr`の使い分けができないエンジニアは淘汰される運命にある。

結びに代えて:アーキテクトの矜持

「動けばいい」というコードは、数年後の自分や同僚を地獄へ突き落とす呪いに等しい。

今回紹介したパラメータ化クエリの手法は、一見手間がかかるように見えるだろう。しかし、この「型を意識し、オブジェクトの生成と消滅を制御する」という規律こそが、大規模なAccessシステムを安定して運用し続けるための唯一の道である。

API仕様を読み込み、ACEの内部挙動を想像せよ。それができる者だけが、Accessというレガシーな枠組みを超えた、真のエンジニアリングを体現できるのだ。

タイトルとURLをコピーしました