ADO.NETとA5:SQL Mk-2の仲良しデバッグ
A5:SQL Mk-2を勝手に応援を勝手に応援シリーズ第二弾です。
普段は『自作の「SQL Server sp_executesql stripper for A5:SQL Mk-2」+SQL Server Profiler』と「A5:SQL Mk-2 スクリプト - 流星墓場」で公開されてる「SetParameterジェネレータ」で事足りてるんだけど、SQLServer以外でもC#/VB.NET上のデバッグ時にいつもの擬似命令付きSQLを取得できるようにとやっつけでコード書いてみました。
対応パラメータ形式は現状名前付き(NamedParameterだっけ?)パラメータのみです。ODBCドライバやOracleの標準プロバイダを選んだ際の
INSERT INTO TBL1 (col1, col2) VALUES (?, ?)
の記法はまだ対応してません。
確かSystem.Data.SqlClient、System.Data.SQLite、Oracleの拡張プロバイダ(みたいなのがあった気がする)辺りなら
INSERT INTO TBL1 (col1, col2) VALUES (@col1, @col2)
で書けた筈です。
では早速デバッグ用コードをば…。十分なテストをしてないβ版なので取扱いに注意ください。
'v0.0.1 手抜きβVer 'v0.0.2 2回目βVer ' Null値対応してない大ポカを修正 ' DateTimeとTimeの秒とミリ秒の区切りの修正 ' 末尾にSQL区切り";"の出力を追加(A5:SQL Mk-2上なら";;"とかなってても平気なので) 'v0.0.3 βVer ' 時刻は24時間表記する時"HH"と大文字にしないとね…。orz ''' <summary> ''' 使用例 ''' Dim cmd As New System.Data.SqlClient.SqlCommand() ''' cmd.Connection = connectionObject ''' cmd.CommandText = "INSERT INTO TBL1 (col1, col2) VALUES (@col1, @col2)" ''' cmd.Parameters.Add("@col1", System.Data.SqlDbType.VarChar).Value = "ABC" ''' cmd.Parameters.Add("@col2", System.Data.SqlDbType.Int).Value = 1 ''' ''' Debug.Print(a5m2cmdParse(cmd)) '実行直前にデバッグ出力 ''' cmd.ExecuteNonQuery() ''' </summary> ''' <param name="dbcmd">System.Data.IDbCommandを実装してる???Commandのインスタンス</param> ''' <returns>A5:SQL Mk-2でパラメータ設定付で実行する為の文字列 </returns> Public Shared Function a5m2cmdParse(ByVal dbcmd As System.Data.IDbCommand) As String Dim sb As New System.Text.StringBuilder() sb.Length = 0 For Each p As System.Data.IDataParameter In dbcmd.Parameters Dim a5name As String = p.ParameterName.Substring(1) Dim a5val As String = String.Empty Dim a5type As String = "String" Dim isNullValue As Boolean = False If IsNothing(p.Value) OrElse IsDBNull(p.Value) Then isNullValue = True End If Select Case p.DbType Case DbType.Int16, DbType.Int32, DbType.Int64 a5type = "Integer" a5val = If(isNullValue, "NULL", CInt(p.Value).ToString()) Case DbType.UInt16, DbType.UInt32 a5type = "Integer" a5val = If(isNullValue, "NULL", CInt(p.Value).ToString()) Case DbType.UInt64 'a5type = "Integer" a5type = "Currency" '擬似命令でUint64指定が出来ないのでCurrencyで代替 a5val = If(isNullValue, "NULL", CDec(p.Value).ToString()) Case DbType.Decimal a5type = "Currency" a5val = If(isNullValue, "NULL", CDec(p.Value).ToString()) Case DbType.Byte, DbType.Byte a5type = "Short" a5val = If(isNullValue, "NULL", CShort(p.Value).ToString()) Case DbType.Single, DbType.Double a5type = "Float" a5val = If(isNullValue, "NULL", CDbl(p.Value).ToString()) Case DbType.Date a5type = "Date" a5val = If(isNullValue, "NULL", "'" & CDate(p.Value).ToString("yyyy/MM/dd") & "'") Case DbType.DateTime, DbType.DateTime2 a5type = "DateTime" a5val = If(isNullValue, "NULL", "'" & CDate(p.Value).ToString("yyyy/MM/dd HH:mm:ss.fff") & "'") Case DbType.Time a5type = "Time" a5val = If(isNullValue, "NULL", "'" & CDate(p.Value).ToString("HH:mm:ss.fff") & "'") Case DbType.AnsiString, DbType.AnsiStringFixedLength, DbType.String, DbType.StringFixedLength a5val = If(isNullValue, "NULL", "'" & CStr(p.Value).Replace("'", "''") & "'") a5type = "String" 'Case DbType.Boolean ' 'DB毎に実装違いそう '他はもう面倒 'Case DbType.Binary 'Case DbType.Guid 'Case DbType.Object 'Case DbType.VarNumeric 'Case DbType.Xml Case Else a5val = If(isNullValue, "NULL", "'" & (p.Value.ToString()).Replace("'", "''") & "'") a5type = "String" End Select sb.AppendLine("--*SetParameter " & a5name & " " & a5val & " " & a5type) Next sb.AppendLine(dbcmd.CommandText) sb.AppendLine(";") '区切り追加 Return sb.ToString() End Function
(C#版が欲しいならILSpyでも使って逆コンパイルしてください!)
呼び出し方は
Dim cmd As New System.Data.SqlClient.SqlCommand() cmd.Connection = connectionObject cmd.CommandText = "INSERT INTO TBL1 (col1, col2) VALUES (@col1, @col2)" cmd.Parameters.Add("@col1", System.Data.SqlDbType.VarChar).Value = "ABC" cmd.Parameters.Add("@col2", System.Data.SqlDbType.Int).Value = 1 Debug.Print(a5m2cmdParse(cmd)) '<-ここ cmd.ExecuteNonQuery()
の様にSQLもパラメータもセットしおわったSqlCommand等のインスタンス*1を渡して結果文字列を取得するだけです。簡単ですね!
ではデバッグは皆に任せた!
*1: System.Data.IDbCommandインターフェースを実装してる*Commandなら基本何でも可