Menu

[r5]: / trunk / source / DBVisualizer / DebugeeObjectSource.vb  Maximize  Restore  History

Download this file

201 lines (139 with data), 6.8 kB

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
Imports System.Data.Common
Imports Microsoft.VisualStudio.DebuggerVisualizers
Imports System.IO
''' <summary>
''' This class implements the debugee side of the visualizer. It is responsible for running the commands against the server.
''' </summary>
''' <remarks>As DBConnection is not serializable, in order to run commands against it,
''' the debugger side must send the sql text to the debuggee side, run the command and
''' return the results. This is accomplished by using the TransferData method to send
''' the SQL statement and the GetObject method to return the result of the SQL statement as a DataTable.</remarks>
Friend Class DebugeeObjectSource
Inherits VisualizerObjectSource
#Region "Database Logic"
' This string is set during TransferData() and is used by the GetObject() routine to return the data.
Private mSQL As String
''' <summary>
''' Runs the current SQL against the table and returns the result as a data table
''' </summary>
''' <param name="connection">The connection to run the SQL against</param>
''' <param name="sql">The SQL statement to run against the connection</param>
''' <returns>A data table contining the results of the SQL statement</returns>
Private Shared Function ExecuteSQL(ByVal connection As DbConnection, ByVal sql As String) As DataTable
' Local Variables
Dim resultTable As DataTable
Dim readSW As Stopwatch
' Create a command to run against the connection
Using command As DbCommand = connection.CreateCommand()
' Set the command text
command.CommandText = sql
' Run the command to get a data reader
Using reader As DbDataReader = command.ExecuteReader()
' Fill the table from the reader
readSW = Stopwatch.StartNew
resultTable = ReadTable(reader)
End Using
End Using
' Return the result table
Return resultTable
End Function
''' <summary>
''' Reads the contents of a data reader into a data table
''' </summary>
''' <param name="reader">The reader to read from</param>
''' <returns>A table filled with the data from the reader</returns>
Private Shared Function ReadTable(ByVal reader As DbDataReader) As DataTable
' Local Variables
Dim table As DataTable
Dim row As DataRow
' Set up the data table
table = New DataTable
table.RemotingFormat = SerializationFormat.Binary
CreateColumns(reader, table)
' Fill all the data in the table
Do While reader.Read
row = table.NewRow
For colIndex As Integer = 0 To reader.FieldCount - 1
row(colIndex) = reader(colIndex)
Next
table.Rows.Add(row)
Loop
' Return the table
Return table
End Function
''' <summary>
''' Creates the columns in the data table to match the data reader
''' </summary>
''' <param name="reader">The reader to read the column information from</param>
''' <param name="table">The data table to add the columns to</param>
''' <remarks></remarks>
Private Shared Sub CreateColumns(ByVal reader As DbDataReader, ByVal table As DataTable)
' Loop around all the columns in the reader and add them to the table
For colIndex As Integer = 0 To reader.FieldCount - 1
table.Columns.Add(reader.GetName(colIndex))
Next
End Sub
#End Region
#Region "Visualizer Object Source Functionality"
''' <summary>
''' Transfers data from the debugger side to the debugee side
''' </summary>
''' <param name="target">The target object we're visualizing</param>
''' <param name="incomingData">A stream of incoming data</param>
''' <param name="outgoingData">A stream of outgoing data</param>
''' <remarks>This method is used to transfer a sql statement from the debugger side
''' to the debugee side.
''' </remarks>
Public Overrides Sub TransferData(ByVal target As Object, _
ByVal incomingData As Stream, _
ByVal outgoingData As Stream)
' Read the SQL statement from the incoming data
mSQL = GetStringFromStream(incomingData)
' We don't need to call the base to transfer any data
'MyBase.TransferData(target, incomingData, outgoingData)
End Sub
''' <summary>
''' Transfers the result from the debugee side to the debugger side
''' </summary>
''' <param name="target">The target object being visualized (must derive from <see cref="DbConnection"/></param>
''' <param name="outgoingData">The datastream for the output</param>
''' <remarks>Intercepts the call to get the target and replaces it with the data table returned
''' from the query that was transfered via <see cref="TransferData"/></remarks>
Public Overrides Sub GetData(ByVal target As Object, ByVal outgoingData As System.IO.Stream)
' Local Variables
Dim resultTable As DataTable
Dim result As New QueryResult
Dim sw As Stopwatch
' We catch exceptions here and send them to the client side instead
Try
sw = Stopwatch.StartNew
' Try and get the data from the database
resultTable = ExecuteSQL(DirectCast(target, DbConnection), mSQL)
sw.Stop()
result.ResultTable = resultTable
result.QueryTime = sw.Elapsed
Catch ex As Exception
' Record the exception details
result.Exception = ex
End Try
' Substitute the target for the result we've built up
' this will serialize it and send it to the client
MyBase.GetData(result, outgoingData)
End Sub
#End Region
#Region "Generic Data Transfer Functionality"
''' <summary>
''' Reads the contents of a stream into a string.
''' </summary>
''' <param name="stream">The stream to read from</param>
''' <returns>The string that was read from the stream</returns>
''' <remarks>The returned string will start from the current stream position.</remarks>
Private Function GetStringFromStream(ByVal stream As IO.Stream) As String
' Use a streamreader to read from the stream
Using reader As New StreamReader(stream)
' return the contents
Return reader.ReadToEnd()
End Using
End Function
#End Region
End Class