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.

252 lines
10 KiB

4 years ago
  1. #if MYSQL_6_10
  2. // Copyright © 2009, 2016, 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.Collections.Generic;
  25. using System.Diagnostics;
  26. using System.Text;
  27. using System.Threading;
  28. using Externals.MySql.Data.Common;
  29. namespace Externals.MySql.Data.MySqlClient
  30. {
  31. internal class TracingDriver : Driver
  32. {
  33. private static long driverCounter;
  34. private long driverId;
  35. private ResultSet activeResult;
  36. private int rowSizeInBytes;
  37. public TracingDriver(MySqlConnectionStringBuilder settings)
  38. : base(settings)
  39. {
  40. driverId = Interlocked.Increment(ref driverCounter);
  41. }
  42. public override void Open()
  43. {
  44. base.Open();
  45. MySqlTrace.TraceEvent(TraceEventType.Information, MySqlTraceEventType.ConnectionOpened,
  46. Resources.TraceOpenConnection, driverId, Settings.ConnectionString, ThreadID);
  47. }
  48. public override void Close()
  49. {
  50. base.Close();
  51. MySqlTrace.TraceEvent(TraceEventType.Information, MySqlTraceEventType.ConnectionClosed,
  52. Resources.TraceCloseConnection, driverId);
  53. }
  54. public override void SendQuery(MySqlPacket p)
  55. {
  56. rowSizeInBytes = 0;
  57. string cmdText = Encoding.GetString(p.Buffer, 5, p.Length - 5);
  58. string normalizedQuery = null;
  59. if (cmdText.Length > 300)
  60. {
  61. QueryNormalizer normalizer = new QueryNormalizer();
  62. normalizedQuery = normalizer.Normalize(cmdText);
  63. cmdText = cmdText.Substring(0, 300);
  64. }
  65. base.SendQuery(p);
  66. MySqlTrace.TraceEvent(TraceEventType.Information, MySqlTraceEventType.QueryOpened,
  67. Resources.TraceQueryOpened, driverId, ThreadID, cmdText);
  68. if (normalizedQuery != null)
  69. MySqlTrace.TraceEvent(TraceEventType.Information, MySqlTraceEventType.QueryNormalized,
  70. Resources.TraceQueryNormalized, driverId, ThreadID, normalizedQuery);
  71. }
  72. protected override int GetResult(int statementId, ref int affectedRows, ref long insertedId)
  73. {
  74. try
  75. {
  76. int fieldCount = base.GetResult(statementId, ref affectedRows, ref insertedId);
  77. MySqlTrace.TraceEvent(TraceEventType.Information, MySqlTraceEventType.ResultOpened,
  78. Resources.TraceResult, driverId, fieldCount, affectedRows, insertedId);
  79. return fieldCount;
  80. }
  81. catch (MySqlException ex)
  82. {
  83. // we got an error so we report it
  84. MySqlTrace.TraceEvent(TraceEventType.Information, MySqlTraceEventType.Error,
  85. Resources.TraceOpenResultError, driverId, ex.Number, ex.Message);
  86. throw ex;
  87. }
  88. }
  89. public override ResultSet NextResult(int statementId, bool force)
  90. {
  91. // first let's see if we already have a resultset on this statementId
  92. if (activeResult != null)
  93. {
  94. //oldRS = activeResults[statementId];
  95. if (Settings.UseUsageAdvisor)
  96. ReportUsageAdvisorWarnings(statementId, activeResult);
  97. MySqlTrace.TraceEvent(TraceEventType.Information, MySqlTraceEventType.ResultClosed,
  98. Resources.TraceResultClosed, driverId, activeResult.TotalRows, activeResult.SkippedRows,
  99. rowSizeInBytes);
  100. rowSizeInBytes = 0;
  101. activeResult = null;
  102. }
  103. activeResult = base.NextResult(statementId, force);
  104. return activeResult;
  105. }
  106. public override int PrepareStatement(string sql, ref MySqlField[] parameters)
  107. {
  108. int statementId = base.PrepareStatement(sql, ref parameters);
  109. MySqlTrace.TraceEvent(TraceEventType.Information, MySqlTraceEventType.StatementPrepared,
  110. Resources.TraceStatementPrepared, driverId, sql, statementId);
  111. return statementId;
  112. }
  113. public override void CloseStatement(int id)
  114. {
  115. base.CloseStatement(id);
  116. MySqlTrace.TraceEvent(TraceEventType.Information, MySqlTraceEventType.StatementClosed,
  117. Resources.TraceStatementClosed, driverId, id);
  118. }
  119. public override void SetDatabase(string dbName)
  120. {
  121. base.SetDatabase(dbName);
  122. MySqlTrace.TraceEvent(TraceEventType.Information, MySqlTraceEventType.NonQuery,
  123. Resources.TraceSetDatabase, driverId, dbName);
  124. }
  125. public override void ExecuteStatement(MySqlPacket packetToExecute)
  126. {
  127. base.ExecuteStatement(packetToExecute);
  128. int pos = packetToExecute.Position;
  129. packetToExecute.Position = 1;
  130. int statementId = packetToExecute.ReadInteger(4);
  131. packetToExecute.Position = pos;
  132. MySqlTrace.TraceEvent(TraceEventType.Information, MySqlTraceEventType.StatementExecuted,
  133. Resources.TraceStatementExecuted, driverId, statementId, ThreadID);
  134. }
  135. public override bool FetchDataRow(int statementId, int columns)
  136. {
  137. try
  138. {
  139. bool b = base.FetchDataRow(statementId, columns);
  140. if (b)
  141. rowSizeInBytes += (handler as NativeDriver).Packet.Length;
  142. return b;
  143. }
  144. catch (MySqlException ex)
  145. {
  146. MySqlTrace.TraceEvent(TraceEventType.Error, MySqlTraceEventType.Error,
  147. Resources.TraceFetchError, driverId, ex.Number, ex.Message);
  148. throw ex;
  149. }
  150. }
  151. public override void CloseQuery(MySqlConnection connection, int statementId)
  152. {
  153. base.CloseQuery(connection, statementId);
  154. MySqlTrace.TraceEvent(TraceEventType.Information, MySqlTraceEventType.QueryClosed,
  155. Resources.TraceQueryDone, driverId);
  156. }
  157. public override List<MySqlError> ReportWarnings(MySqlConnection connection)
  158. {
  159. List<MySqlError> warnings = base.ReportWarnings(connection);
  160. foreach (MySqlError warning in warnings)
  161. MySqlTrace.TraceEvent(TraceEventType.Warning, MySqlTraceEventType.Warning,
  162. Resources.TraceWarning, driverId, warning.Level, warning.Code, warning.Message);
  163. return warnings;
  164. }
  165. private bool AllFieldsAccessed(ResultSet rs)
  166. {
  167. if (rs.Fields == null || rs.Fields.Length == 0) return true;
  168. for (int i = 0; i < rs.Fields.Length; i++)
  169. if (!rs.FieldRead(i)) return false;
  170. return true;
  171. }
  172. private void ReportUsageAdvisorWarnings(int statementId, ResultSet rs)
  173. {
  174. if (!Settings.UseUsageAdvisor) return;
  175. if (HasStatus(ServerStatusFlags.NoIndex))
  176. MySqlTrace.TraceEvent(TraceEventType.Warning, MySqlTraceEventType.UsageAdvisorWarning,
  177. Resources.TraceUAWarningNoIndex, driverId, UsageAdvisorWarningFlags.NoIndex);
  178. else if (HasStatus(ServerStatusFlags.BadIndex))
  179. MySqlTrace.TraceEvent(TraceEventType.Warning, MySqlTraceEventType.UsageAdvisorWarning,
  180. Resources.TraceUAWarningBadIndex, driverId, UsageAdvisorWarningFlags.BadIndex);
  181. // report abandoned rows
  182. if (rs.SkippedRows > 0)
  183. MySqlTrace.TraceEvent(TraceEventType.Warning, MySqlTraceEventType.UsageAdvisorWarning,
  184. Resources.TraceUAWarningSkippedRows, driverId, UsageAdvisorWarningFlags.SkippedRows, rs.SkippedRows);
  185. // report not all fields accessed
  186. if (!AllFieldsAccessed(rs))
  187. {
  188. StringBuilder notAccessed = new StringBuilder("");
  189. string delimiter = "";
  190. for (int i = 0; i < rs.Size; i++)
  191. if (!rs.FieldRead(i))
  192. {
  193. notAccessed.AppendFormat("{0}{1}", delimiter, rs.Fields[i].ColumnName);
  194. delimiter = ",";
  195. }
  196. MySqlTrace.TraceEvent(TraceEventType.Warning, MySqlTraceEventType.UsageAdvisorWarning,
  197. Resources.TraceUAWarningSkippedColumns, driverId, UsageAdvisorWarningFlags.SkippedColumns,
  198. notAccessed.ToString());
  199. }
  200. // report type conversions if any
  201. if (rs.Fields != null)
  202. {
  203. foreach (MySqlField f in rs.Fields)
  204. {
  205. StringBuilder s = new StringBuilder();
  206. string delimiter = "";
  207. foreach (Type t in f.TypeConversions)
  208. {
  209. s.AppendFormat("{0}{1}", delimiter, t.Name);
  210. delimiter = ",";
  211. }
  212. if (s.Length > 0)
  213. MySqlTrace.TraceEvent(TraceEventType.Warning, MySqlTraceEventType.UsageAdvisorWarning,
  214. Resources.TraceUAWarningFieldConversion, driverId, UsageAdvisorWarningFlags.FieldConversion,
  215. f.ColumnName, s.ToString());
  216. }
  217. }
  218. }
  219. }
  220. }
  221. #endif