Accessの暗部を征する:DAOからADO CommandへのパラダイムシフトとSQLインジェクションの完全排除
多くのAccess開発者が、未だにDAOの`CurrentDb.Execute “INSERT INTO … ‘” & strVar & “‘”`といった文字列連結によるSQL構築から脱却できずにいる。これは単なるコードの書き方の問題ではない。アプリケーションの脆弱性を放置する、エンジニアとしての怠慢だ。
本稿では、レガシーシステムの墓場から脱出し、ADO `Command`オブジェクトを駆使した堅牢なデータアクセス層の構築手法を伝授する。
—
なぜ文字列連結が「死」を招くのか
`strSQL = “SELECT FROM Users WHERE ID = ‘” & Me.txtID & “‘”`
このコードは、型安全性を放棄し、SQLインジェクションという脆弱性を自ら招き入れている。入力値に `’ OR ‘1’=’1` が含まれた瞬間、データベースの整合性は崩壊する。
シニアエンジニアであれば、「SQLはデータと分離されるべきである」という原則を骨の髄まで叩き込んでいるはずだ。この分離を実現する唯一の手段が、パラメータ化クエリである。
—
ADO Commandオブジェクトによる堅牢な実装
ADO(ActiveX Data Objects)の`Command`オブジェクトは、プリコンパイルされたSQLステートメントのテンプレートを保持し、実行時にパラメータをバインドする。これにより、SQL構文とデータは明確に分離される。
実装例:セキュアなパラメータクエリ
‘ 参照設定: Microsoft ActiveX Data Objects x.x Library
Public Sub ExecuteSecureUpdate(ByVal userID As Long, ByVal userName As String)
Dim conn As ADODB.Connection
Dim cmd As ADODB.Command
‘ 現在のDBへの接続(DAOではなくADOで開く)
Set conn = CurrentProject.Connection
Set cmd = New ADODB.Command
With cmd
Set .ActiveConnection = conn
‘ パラメータを ? でプレースホルダー化(Access/Jet SQLの場合)
.CommandText = “UPDATE Users SET UserName = ? WHERE UserID = ?”
.CommandType = adCmdText
‘ パラメータの型とサイズを明示する(型安全性とメモリ効率の極致)
.Parameters.Append .CreateParameter(“@pName”, adVarWChar, adParamInput, 50, userName)
.Parameters.Append .CreateParameter(“@pID”, adInteger, adParamInput, , userID)
‘ トランザクション処理の開始
conn.BeginTrans
On Error GoTo RollbackHandler
.Execute , , adExecuteNoRecords
conn.CommitTrans
End With
‘ クリーンアップ(極めて重要)
CleanExit:
Set cmd = Nothing
If Not conn Is Nothing Then conn.Close
Set conn = Nothing
Exit Sub
RollbackHandler:
conn.RollbackTrans
Err.Raise Err.Number, “ExecuteSecureUpdate”, “Transaction Failed: ” & Err.Description
Resume CleanExit
End Sub
—
伝説のアーキテクトが教える、メモリとパフォーマンスの鉄則
1. オブジェクトライフサイクルの管理
VBAはガベージコレクションが脆弱だ。`Set obj = Nothing`を怠ることは、メモリリークという時限爆弾を仕掛けるに等しい。特にループ内で`Command`オブジェクトを生成するような愚行は避け、必要であれば`Parameters`コレクションの`Refresh`メソッドではなく、`CreateParameter`による動的生成を徹底せよ。
2. トランザクションの重みを知れ
`conn.BeginTrans`から`CommitTrans`の範囲は、可能な限り短く保て。長時間ロックは他セッションをブロックし、デッドロックの温床となる。また、エラーハンドリングなしのトランザクションは、システムを中途半端な状態で凍結させる自殺行為である。
3. Windows APIとの連携
もし、さらに深い制御(例えば、ADO接続のタイムアウトやネットワーク遅延の監視)が必要な場合は、`wininet.dll`等のWindows APIを呼び出し、接続状況を低レイヤーで監視する構成を検討すべきだ。しかし、まずはADOの`CommandTimeout`プロパティを適切に設定するだけで、多くのトラブルは回避できる。
—
結論:コードは「防御」である
あなたが書くコードは、単なる機能要件の羅列ではない。悪意あるユーザーや予期せぬデータ入力から、基幹システムという「資産」を守るための防壁である。
文字列連結という安易な妥協を捨て、`Command`オブジェクトという規律あるアーキテクチャを採用せよ。それが、長年レガシーシステムと対峙してきたエンジニアが到達する、唯一の「正解」である。
—
「枯れた技術」とは、使い古された技術を指すのではない。洗練し尽くされ、何年経っても揺るがない堅牢性を備えた技術を指すのだ。
