You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

255 lines
9.2 KiB

4 years ago
  1. #if MYSQL_6_9
  2. // Copyright © 2009, 2011, Oracle and/or its affiliates. All rights reserved.
  3. //
  4. // MySQL Connector/NET is licensed under the terms of the GPLv2
  5. // <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
  6. // MySQL Connectors. There are special exceptions to the terms and
  7. // conditions of the GPLv2 as it is applied to this software, see the
  8. // FLOSS License Exception
  9. // <http://www.mysql.com/about/legal/licensing/foss-exception.html>.
  10. //
  11. // This program is free software; you can redistribute it and/or modify
  12. // it under the terms of the GNU General Public License as published
  13. // by the Free Software Foundation; version 2 of the License.
  14. //
  15. // This program is distributed in the hope that it will be useful, but
  16. // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  17. // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  18. // for more details.
  19. //
  20. // You should have received a copy of the GNU General Public License along
  21. // with this program; if not, write to the Free Software Foundation, Inc.,
  22. // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  23. using System;
  24. using System.Text;
  25. using Externals.MySql.Data.Types;
  26. using System.Diagnostics;
  27. using System.Collections.Generic;
  28. using Externals.MySql.Data.MySqlClient.Properties;
  29. using System.Threading;
  30. using Externals.MySql.Data.Common;
  31. namespace Externals.MySql.Data.MySqlClient
  32. {
  33. internal class TracingDriver : Driver
  34. {
  35. private static long driverCounter;
  36. private long driverId;
  37. private ResultSet activeResult;
  38. private int rowSizeInBytes;
  39. public TracingDriver(MySqlConnectionStringBuilder settings)
  40. : base(settings)
  41. {
  42. driverId = Interlocked.Increment(ref driverCounter);
  43. }
  44. public override void Open()
  45. {
  46. base.Open();
  47. MySqlTrace.TraceEvent(TraceEventType.Information, MySqlTraceEventType.ConnectionOpened,
  48. Resources.TraceOpenConnection, driverId, Settings.ConnectionString, ThreadID);
  49. }
  50. public override void Close()
  51. {
  52. base.Close();
  53. MySqlTrace.TraceEvent(TraceEventType.Information, MySqlTraceEventType.ConnectionClosed,
  54. Resources.TraceCloseConnection, driverId);
  55. }
  56. public override void SendQuery(MySqlPacket p)
  57. {
  58. rowSizeInBytes = 0;
  59. string cmdText = Encoding.GetString(p.Buffer, 5, p.Length - 5);
  60. string normalized_query = null;
  61. if (cmdText.Length > 300)
  62. {
  63. QueryNormalizer normalizer = new QueryNormalizer();
  64. normalized_query = normalizer.Normalize(cmdText);
  65. cmdText = cmdText.Substring(0, 300);
  66. }
  67. base.SendQuery(p);
  68. MySqlTrace.TraceEvent(TraceEventType.Information, MySqlTraceEventType.QueryOpened,
  69. Resources.TraceQueryOpened, driverId, ThreadID, cmdText);
  70. if (normalized_query != null)
  71. MySqlTrace.TraceEvent(TraceEventType.Information, MySqlTraceEventType.QueryNormalized,
  72. Resources.TraceQueryNormalized, driverId, ThreadID, normalized_query);
  73. }
  74. protected override int GetResult(int statementId, ref int affectedRows, ref long insertedId)
  75. {
  76. try
  77. {
  78. int fieldCount = base.GetResult(statementId, ref affectedRows, ref insertedId);
  79. MySqlTrace.TraceEvent(TraceEventType.Information, MySqlTraceEventType.ResultOpened,
  80. Resources.TraceResult, driverId, fieldCount, affectedRows, insertedId);
  81. return fieldCount;
  82. }
  83. catch (MySqlException ex)
  84. {
  85. // we got an error so we report it
  86. MySqlTrace.TraceEvent(TraceEventType.Information, MySqlTraceEventType.Error,
  87. Resources.TraceOpenResultError, driverId, ex.Number, ex.Message);
  88. throw ex;
  89. }
  90. }
  91. public override ResultSet NextResult(int statementId, bool force)
  92. {
  93. // first let's see if we already have a resultset on this statementId
  94. if (activeResult != null)
  95. {
  96. //oldRS = activeResults[statementId];
  97. if (Settings.UseUsageAdvisor)
  98. ReportUsageAdvisorWarnings(statementId, activeResult);
  99. MySqlTrace.TraceEvent(TraceEventType.Information, MySqlTraceEventType.ResultClosed,
  100. Resources.TraceResultClosed, driverId, activeResult.TotalRows, activeResult.SkippedRows,
  101. rowSizeInBytes);
  102. rowSizeInBytes = 0;
  103. activeResult = null;
  104. }
  105. activeResult = base.NextResult(statementId, force);
  106. return activeResult;
  107. }
  108. public override int PrepareStatement(string sql, ref MySqlField[] parameters)
  109. {
  110. int statementId = base.PrepareStatement(sql, ref parameters);
  111. MySqlTrace.TraceEvent(TraceEventType.Information, MySqlTraceEventType.StatementPrepared,
  112. Resources.TraceStatementPrepared, driverId, sql, statementId);
  113. return statementId;
  114. }
  115. public override void CloseStatement(int id)
  116. {
  117. base.CloseStatement(id);
  118. MySqlTrace.TraceEvent(TraceEventType.Information, MySqlTraceEventType.StatementClosed,
  119. Resources.TraceStatementClosed, driverId, id);
  120. }
  121. public override void SetDatabase(string dbName)
  122. {
  123. base.SetDatabase(dbName);
  124. MySqlTrace.TraceEvent(TraceEventType.Information, MySqlTraceEventType.NonQuery,
  125. Resources.TraceSetDatabase, driverId, dbName);
  126. }
  127. public override void ExecuteStatement(MySqlPacket packetToExecute)
  128. {
  129. base.ExecuteStatement(packetToExecute);
  130. int pos = packetToExecute.Position;
  131. packetToExecute.Position = 1;
  132. int statementId = packetToExecute.ReadInteger(4);
  133. packetToExecute.Position = pos;
  134. MySqlTrace.TraceEvent(TraceEventType.Information, MySqlTraceEventType.StatementExecuted,
  135. Resources.TraceStatementExecuted, driverId, statementId, ThreadID);
  136. }
  137. public override bool FetchDataRow(int statementId, int columns)
  138. {
  139. try
  140. {
  141. bool b = base.FetchDataRow(statementId, columns);
  142. if (b)
  143. rowSizeInBytes += (handler as NativeDriver).Packet.Length;
  144. return b;
  145. }
  146. catch (MySqlException ex)
  147. {
  148. MySqlTrace.TraceEvent(TraceEventType.Error, MySqlTraceEventType.Error,
  149. Resources.TraceFetchError, driverId, ex.Number, ex.Message);
  150. throw ex;
  151. }
  152. }
  153. public override void CloseQuery(MySqlConnection connection, int statementId)
  154. {
  155. base.CloseQuery(connection, statementId);
  156. MySqlTrace.TraceEvent(TraceEventType.Information, MySqlTraceEventType.QueryClosed,
  157. Resources.TraceQueryDone, driverId);
  158. }
  159. public override List<MySqlError> ReportWarnings(MySqlConnection connection)
  160. {
  161. List<MySqlError> warnings = base.ReportWarnings(connection);
  162. foreach (MySqlError warning in warnings)
  163. MySqlTrace.TraceEvent(TraceEventType.Warning, MySqlTraceEventType.Warning,
  164. Resources.TraceWarning, driverId, warning.Level, warning.Code, warning.Message);
  165. return warnings;
  166. }
  167. private bool AllFieldsAccessed(ResultSet rs)
  168. {
  169. if (rs.Fields == null || rs.Fields.Length == 0) return true;
  170. for (int i = 0; i < rs.Fields.Length; i++)
  171. if (!rs.FieldRead(i)) return false;
  172. return true;
  173. }
  174. private void ReportUsageAdvisorWarnings(int statementId, ResultSet rs)
  175. {
  176. if (!Settings.UseUsageAdvisor) return;
  177. if (HasStatus(ServerStatusFlags.NoIndex))
  178. MySqlTrace.TraceEvent(TraceEventType.Warning, MySqlTraceEventType.UsageAdvisorWarning,
  179. Resources.TraceUAWarningNoIndex, driverId, UsageAdvisorWarningFlags.NoIndex);
  180. else if (HasStatus(ServerStatusFlags.BadIndex))
  181. MySqlTrace.TraceEvent(TraceEventType.Warning, MySqlTraceEventType.UsageAdvisorWarning,
  182. Resources.TraceUAWarningBadIndex, driverId, UsageAdvisorWarningFlags.BadIndex);
  183. // report abandoned rows
  184. if (rs.SkippedRows > 0)
  185. MySqlTrace.TraceEvent(TraceEventType.Warning, MySqlTraceEventType.UsageAdvisorWarning,
  186. Resources.TraceUAWarningSkippedRows, driverId, UsageAdvisorWarningFlags.SkippedRows, rs.SkippedRows);
  187. // report not all fields accessed
  188. if (!AllFieldsAccessed(rs))
  189. {
  190. StringBuilder notAccessed = new StringBuilder("");
  191. string delimiter = "";
  192. for (int i = 0; i < rs.Size; i++)
  193. if (!rs.FieldRead(i))
  194. {
  195. notAccessed.AppendFormat("{0}{1}", delimiter, rs.Fields[i].ColumnName);
  196. delimiter = ",";
  197. }
  198. MySqlTrace.TraceEvent(TraceEventType.Warning, MySqlTraceEventType.UsageAdvisorWarning,
  199. Resources.TraceUAWarningSkippedColumns, driverId, UsageAdvisorWarningFlags.SkippedColumns,
  200. notAccessed.ToString());
  201. }
  202. // report type conversions if any
  203. if (rs.Fields != null)
  204. {
  205. foreach (MySqlField f in rs.Fields)
  206. {
  207. StringBuilder s = new StringBuilder();
  208. string delimiter = "";
  209. foreach (Type t in f.TypeConversions)
  210. {
  211. s.AppendFormat("{0}{1}", delimiter, t.Name);
  212. delimiter = ",";
  213. }
  214. if (s.Length > 0)
  215. MySqlTrace.TraceEvent(TraceEventType.Warning, MySqlTraceEventType.UsageAdvisorWarning,
  216. Resources.TraceUAWarningFieldConversion, driverId, UsageAdvisorWarningFlags.FieldConversion,
  217. f.ColumnName, s.ToString());
  218. }
  219. }
  220. }
  221. }
  222. }
  223. #endif