//-----------------------------------------------------------------------------
//
// Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License").
// You may not use this file except in compliance with the License.
// A copy of the License is located at
//
// http://aws.amazon.com/apache2.0
//
// or in the "license" file accompanying this file. This file is distributed
// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
// express or implied. See the License for the specific language governing
// permissions and limitations under the License.
//
//-----------------------------------------------------------------------------
using System;
using System.Data;
using System.Data.Common;
using System.Data.SqlClient;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
using Amazon.XRay.Recorder.Core;
using Amazon.XRay.Recorder.Core.Internal.Utils;
namespace Amazon.XRay.Recorder.Handlers.SqlServer
{
///
/// Traceable wrapper of . Currently synchronized and asynchronized call
/// are traced, which includes ExecuteNonQuery, ExecuteReader, ExecuteScalar and ExecuteXmlReader.
///
///
public class TraceableSqlCommand : DbCommand, ICloneable
{
private IDbCommandInterceptor _interceptor { get; set; }
///
/// Initializes a new instance of the class.
///
///
/// Include the in the sanitized_query section of
/// the SQL subsegment. Parameterized values will appear in their tokenized form and will not be expanded.
/// You should not enable this flag if you are including sensitive information as clear text.
/// This flag will override any behavior configured by .
/// If a value is not provided, then the globally configured value will be used, which is false by default.
/// See the official documentation on SqlCommand.Parameters
///
public TraceableSqlCommand(bool? collectSqlQueries = null)
{
InnerSqlCommand = new SqlCommand();
_interceptor = new DbCommandInterceptor(AWSXRayRecorder.Instance, collectSqlQueries);
}
///
/// Initializes a new instance of the class.
///
/// The text of the query.
///
/// Include the in the sanitized_query section of
/// the SQL subsegment. Parameterized values will appear in their tokenized form and will not be expanded.
/// You should not enable this flag if you are including sensitive information as clear text.
/// This flag will override any behavior configured by .
/// If a value is not provided, then the globally configured value will be used, which is false by default.
/// See the official documentation on SqlCommand.Parameters
///
public TraceableSqlCommand(string cmdText, bool? collectSqlQueries = null)
{
InnerSqlCommand = new SqlCommand(cmdText);
_interceptor = new DbCommandInterceptor(AWSXRayRecorder.Instance, collectSqlQueries);
}
///
/// Initializes a new instance of the class.
///
/// The text of the query.
/// The connection to an instance of SQL Server.
///
/// Include the in the sanitized_query section of
/// the SQL subsegment. Parameterized values will appear in their tokenized form and will not be expanded.
/// You should not enable this flag if you are including sensitive information as clear text.
/// This flag will override any behavior configured by .
/// If a value is not provided, then the globally configured value will be used, which is false by default.
/// See the official documentation on SqlCommand.Parameters
///
public TraceableSqlCommand(string cmdText, SqlConnection connection, bool? collectSqlQueries = null)
{
InnerSqlCommand = new SqlCommand(cmdText, connection);
_interceptor = new DbCommandInterceptor(AWSXRayRecorder.Instance, collectSqlQueries);
}
///
/// Initializes a new instance of the class.
///
/// The text of the query.
/// The connection to an instance of SQL Server.
/// The in which the executes.
///
/// Include the in the sanitized_query section of
/// the SQL subsegment. Parameterized values will appear in their tokenized form and will not be expanded.
/// You should not enable this flag if you are including sensitive information as clear text.
/// This flag will override any behavior configured by .
/// If a value is not provided, then the globally configured value will be used, which is false by default.
/// See the official documentation on SqlCommand.Parameters
///
public TraceableSqlCommand(string cmdText, SqlConnection connection, SqlTransaction transaction, bool? collectSqlQueries = null)
{
InnerSqlCommand = new SqlCommand(cmdText, connection, transaction);
_interceptor = new DbCommandInterceptor(AWSXRayRecorder.Instance, collectSqlQueries);
}
private TraceableSqlCommand(TraceableSqlCommand from)
{
InnerSqlCommand = from.InnerSqlCommand.Clone();
}
///
/// Occurs when the execution of a Transact-SQL statement completes.
///
public event StatementCompletedEventHandler StatementCompleted
{
add { InnerSqlCommand.StatementCompleted += value; }
remove { InnerSqlCommand.StatementCompleted -= value; }
}
///
/// Gets the inner SQL command.
///
public SqlCommand InnerSqlCommand { get; private set; }
///
/// Gets or sets the text command to run against the data source.
///
public override string CommandText
{
get { return InnerSqlCommand.CommandText; }
set { InnerSqlCommand.CommandText = value; }
}
///
/// Gets or sets the wait time before terminating the attempt to execute a command and generating an error.
///
public override int CommandTimeout
{
get { return InnerSqlCommand.CommandTimeout; }
set { InnerSqlCommand.CommandTimeout = value; }
}
///
/// Indicates or specifies how the property is interpreted.
///
public override CommandType CommandType
{
get { return InnerSqlCommand.CommandType; }
set { InnerSqlCommand.CommandType = value; }
}
///
/// Gets or sets the used by this .
///
public new SqlConnection Connection
{
get { return InnerSqlCommand.Connection; }
set { InnerSqlCommand.Connection = value; }
}
///
/// Gets or sets a value indicating whether the command object should be visible in a customized interface control.
///
public override bool DesignTimeVisible
{
get { return InnerSqlCommand.DesignTimeVisible; }
set { InnerSqlCommand.DesignTimeVisible = value; }
}
///
/// Gets the collection of objects.
///
public new SqlParameterCollection Parameters
{
get { return InnerSqlCommand.Parameters; }
}
///
/// Gets or sets the within which this object executes.
///
public new SqlTransaction Transaction
{
get { return InnerSqlCommand.Transaction; }
set { InnerSqlCommand.Transaction = value; }
}
///
/// Gets or sets how command results are applied to the when used by the Update method of a .
///
public override UpdateRowSource UpdatedRowSource
{
get { return InnerSqlCommand.UpdatedRowSource; }
set { InnerSqlCommand.UpdatedRowSource = value; }
}
///
/// Gets or sets the used by this .
///
protected override DbConnection DbConnection
{
get { return Connection; }
set { Connection = (SqlConnection)value; }
}
///
/// Gets or sets the within which this object executes.
///
protected override DbTransaction DbTransaction
{
get { return Transaction; }
set { Transaction = (SqlTransaction)value; }
}
///
/// Gets the collection of objects.
///
protected override DbParameterCollection DbParameterCollection
{
get { return Parameters; }
}
///
/// Attempts to cancels the execution of a .
///
public override void Cancel()
{
InnerSqlCommand.Cancel();
}
///
/// Clones this instance.
///
/// A new object that is a copy of this instance.
public TraceableSqlCommand Clone()
{
return new TraceableSqlCommand(this);
}
object ICloneable.Clone()
{
return Clone();
}
///
/// Creates the parameter. Wrapper of the same function in .
///
/// A System.Data.SqlClient.SqlParameter object.
public new SqlParameter CreateParameter()
{
return InnerSqlCommand.CreateParameter();
}
///
/// Executes a SQL statement against a connection object. Wrapper of the same function in .
///
///
/// The number of rows affected.
///
public override int ExecuteNonQuery()
{
return Intercept(() => InnerSqlCommand.ExecuteNonQuery());
}
///
/// This is the asynchronous version of . Providers should override with an appropriate implementation.
/// The cancellation token may optionally be ignored.The default implementation invokes the synchronous method and
/// returns a completed task, blocking the calling thread. The default implementation will return a cancelled task if passed an already cancelled cancellation token.
/// Exceptions thrown by will be communicated via the returned Task Exception property.Do not invoke other methods
/// and properties of the DbCommand object until the returned Task is complete.
/// Wrapper of the same function in .
///
/// The token to monitor for cancellation requests.
///
/// A task representing the asynchronous operation.
///
public override Task ExecuteNonQueryAsync(CancellationToken cancellationToken)
{
return InterceptAsync(() => InnerSqlCommand.ExecuteNonQueryAsync(cancellationToken));
}
///
/// Executes the reader. Wrapper of the same function in .
///
/// A System.Data.SqlClient.SqlDataReader object.
public new SqlDataReader ExecuteReader()
{
return Intercept(() => InnerSqlCommand.ExecuteReader());
}
///
/// Executes the reader. Wrapper of the same function in .
///
/// The behavior.
/// A System.Data.SqlClient.SqlDataReader object.
public new SqlDataReader ExecuteReader(CommandBehavior behavior)
{
return Intercept(() => InnerSqlCommand.ExecuteReader(behavior));
}
///
/// Executes the reader asynchronous. Wrapper of the same function in .
///
/// A task representing the asynchronous operation.
public new Task ExecuteReaderAsync()
{
return InterceptAsync(() => InnerSqlCommand.ExecuteReaderAsync());
}
///
/// Executes the reader asynchronous. Wrapper of the same function in .
///
/// The cancellation token.
/// A task representing the asynchronous operation.
public new Task ExecuteReaderAsync(CancellationToken cancellationToken)
{
return InterceptAsync(() => InnerSqlCommand.ExecuteReaderAsync(cancellationToken));
}
///
/// Executes the reader asynchronous. Wrapper of the same function in .
///
/// The behavior.
/// A task representing the asynchronous operation.
public new Task ExecuteReaderAsync(CommandBehavior behavior)
{
return InterceptAsync(() => InnerSqlCommand.ExecuteReaderAsync(behavior));
}
///
/// Executes the reader asynchronous. Wrapper of the same function in .
///
/// The behavior.
/// The cancellation token.
/// A task representing the asynchronous operation.
public new Task ExecuteReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken)
{
return InterceptAsync(() => InnerSqlCommand.ExecuteReaderAsync(behavior, cancellationToken));
}
///
/// Executes the query and returns the first column of the first row in the result set returned by the query. All other columns and rows are ignored.
/// Wrapper of the same function in .
///
///
/// The first column of the first row in the result set.
///
public override object ExecuteScalar()
{
return Intercept(() => InnerSqlCommand.ExecuteScalar());
}
///
/// This is the asynchronous version of . Providers should override with an appropriate implementation.
/// The cancellation token may optionally be ignored.The default implementation invokes the synchronous method and returns
/// a completed task, blocking the calling thread. The default implementation will return a cancelled task if passed an already cancelled cancellation token. Exceptions thrown by ExecuteScalar will be
/// communicated via the returned Task Exception property.Do not invoke other methods and properties of the DbCommand object until the returned Task is complete.
/// Wrapper of the same function in .
///
/// The token to monitor for cancellation requests.
///
/// A task representing the asynchronous operation.
///
public override Task