e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
334 lines
12 KiB
C#
334 lines
12 KiB
C#
//------------------------------------------------------------------------------
|
|
// <copyright file="SmiEventSink_Default.cs" company="Microsoft">
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
// </copyright>
|
|
// <owner current="true" primary="true">[....]</owner>
|
|
// <owner current="true" primary="false">[....]</owner>
|
|
//------------------------------------------------------------------------------
|
|
|
|
namespace Microsoft.SqlServer.Server {
|
|
|
|
using System.Data.Sql;
|
|
using System.Data.SqlClient;
|
|
using System.Diagnostics;
|
|
|
|
internal class SmiEventSink_Default : SmiEventSink {
|
|
|
|
private SmiEventSink _parent; // next level up, which we'll defer to if we don't need to handle the event.
|
|
|
|
private SqlErrorCollection _errors;
|
|
private SqlErrorCollection _warnings;
|
|
|
|
private SqlErrorCollection Errors {
|
|
get {
|
|
if ( null == _errors ) {
|
|
_errors = new SqlErrorCollection( );
|
|
}
|
|
|
|
return _errors;
|
|
}
|
|
}
|
|
|
|
internal bool HasMessages {
|
|
get {
|
|
SmiEventSink_Default parent = (SmiEventSink_Default)_parent;
|
|
if (null != parent) {
|
|
return parent.HasMessages;
|
|
}
|
|
else {
|
|
bool result = (null != _errors || null != _warnings);
|
|
return result;
|
|
}
|
|
}
|
|
}
|
|
|
|
virtual internal string ServerVersion {
|
|
get {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
internal SmiEventSink Parent {
|
|
get {
|
|
return _parent;
|
|
}
|
|
set {
|
|
_parent = value;
|
|
}
|
|
}
|
|
|
|
private SqlErrorCollection Warnings {
|
|
get {
|
|
if ( null == _warnings ) {
|
|
_warnings = new SqlErrorCollection( );
|
|
}
|
|
|
|
return _warnings;
|
|
}
|
|
}
|
|
|
|
protected virtual void DispatchMessages(bool ignoreNonFatalMessages) {
|
|
// virtual because we want a default implementation in the cases
|
|
// where we don't have a connection to process stuff, but we want to
|
|
// provide the connection the ability to fire info messages when it
|
|
// hooks up.
|
|
SmiEventSink_Default parent = (SmiEventSink_Default)_parent;
|
|
if (null != parent) {
|
|
parent.DispatchMessages(ignoreNonFatalMessages);
|
|
}
|
|
else {
|
|
SqlException errors = ProcessMessages(true, ignoreNonFatalMessages); // ignore warnings, because there's no place to send them...
|
|
if (null != errors) {
|
|
throw errors;
|
|
}
|
|
}
|
|
}
|
|
|
|
protected SqlException ProcessMessages(bool ignoreWarnings, bool ignoreNonFatalMessages) {
|
|
SqlException result = null;
|
|
SqlErrorCollection temp = null; // temp variable to store that which is being thrown - so that local copies can be deleted
|
|
|
|
if ( null != _errors ) {
|
|
Debug.Assert( 0 != _errors.Count, "empty error collection?" ); // must be something in the collection
|
|
|
|
if (ignoreNonFatalMessages) {
|
|
temp = new SqlErrorCollection();
|
|
foreach(SqlError error in _errors) {
|
|
if (error.Class >= TdsEnums.FATAL_ERROR_CLASS){
|
|
temp.Add(error);
|
|
}
|
|
}
|
|
if (temp.Count <= 0) {
|
|
temp = null;
|
|
}
|
|
}
|
|
else {
|
|
if (null != _warnings ) {
|
|
// When we throw an exception we place all the warnings that
|
|
// occurred at the end of the collection - after all the errors.
|
|
// That way the user can see all the errors AND warnings that
|
|
// occurred for the exception.
|
|
foreach ( SqlError warning in _warnings ) {
|
|
_errors.Add( warning );
|
|
}
|
|
}
|
|
temp = _errors;
|
|
}
|
|
|
|
_errors = null;
|
|
_warnings = null;
|
|
}
|
|
else {
|
|
Debug.Assert( null == _warnings || 0 != _warnings.Count, "empty warning collection?" );// must be something in the collection
|
|
|
|
if (!ignoreWarnings) {
|
|
temp = _warnings;
|
|
}
|
|
_warnings = null;
|
|
}
|
|
|
|
if ( null != temp ) {
|
|
result = SqlException.CreateException( temp, ServerVersion );
|
|
}
|
|
return result;
|
|
}
|
|
|
|
internal void CleanMessages() {
|
|
SmiEventSink_Default parent = (SmiEventSink_Default)_parent;
|
|
if (null != parent) {
|
|
parent.CleanMessages();
|
|
}
|
|
else {
|
|
_errors = null;
|
|
_warnings = null;
|
|
}
|
|
}
|
|
|
|
internal void ProcessMessagesAndThrow() {
|
|
ProcessMessagesAndThrow(false);
|
|
}
|
|
|
|
internal void ProcessMessagesAndThrow(bool ignoreNonFatalMessages) {
|
|
if (HasMessages) {
|
|
DispatchMessages(ignoreNonFatalMessages);
|
|
}
|
|
}
|
|
|
|
internal enum UnexpectedEventType {
|
|
BatchCompleted,
|
|
ColumnInfoAvailable,
|
|
DefaultDatabaseChanged,
|
|
MessagePosted,
|
|
MetaDataAvailable,
|
|
ParameterAvailable,
|
|
ParametersAvailable,
|
|
RowAvailable,
|
|
StatementCompleted,
|
|
TableNameAvailable,
|
|
TransactionCommitted,
|
|
TransactionDefected,
|
|
TransactionEnlisted,
|
|
TransactionEnded,
|
|
TransactionRolledBack,
|
|
TransactionStarted,
|
|
}
|
|
|
|
|
|
internal SmiEventSink_Default () {
|
|
}
|
|
|
|
internal SmiEventSink_Default ( SmiEventSink parent ) {
|
|
_parent = parent;
|
|
}
|
|
|
|
|
|
// NOTE: See the note in SmiEventSink about throwing from these methods;
|
|
// We're throwing here because we don't want to miss something, but
|
|
// you'll need to turn on Bid tracing to figure out what it is that
|
|
// was thrown, because they will be eaten by the server and replaced
|
|
// with a different exception.
|
|
|
|
|
|
// Called at end of stream
|
|
internal override void BatchCompleted( ) {
|
|
if (null == _parent) {
|
|
throw SQL.UnexpectedSmiEvent(UnexpectedEventType.BatchCompleted);
|
|
}
|
|
_parent.BatchCompleted();
|
|
}
|
|
|
|
internal override void ParametersAvailable(SmiParameterMetaData[] metaData, ITypedGettersV3 paramValues) {
|
|
if (null == _parent) {
|
|
throw SQL.UnexpectedSmiEvent(UnexpectedEventType.ParametersAvailable);
|
|
}
|
|
_parent.ParametersAvailable(metaData, paramValues);
|
|
}
|
|
|
|
internal override void ParameterAvailable(SmiParameterMetaData metaData, SmiTypedGetterSetter paramValue, int ordinal) {
|
|
if (null == _parent) {
|
|
throw SQL.UnexpectedSmiEvent(UnexpectedEventType.ParameterAvailable);
|
|
}
|
|
_parent.ParameterAvailable(metaData, paramValue, ordinal);
|
|
}
|
|
|
|
// Called when the server database context changes (ENVCHANGE token)
|
|
internal override void DefaultDatabaseChanged( string databaseName ) {
|
|
if (null == _parent) {
|
|
throw SQL.UnexpectedSmiEvent(UnexpectedEventType.DefaultDatabaseChanged);
|
|
}
|
|
_parent.DefaultDatabaseChanged( databaseName );
|
|
}
|
|
|
|
// Called for messages and errors (ERROR and INFO tokens)
|
|
internal override void MessagePosted ( int number, byte state, byte errorClass, string server, string message, string procedure, int lineNumber ) {
|
|
if (null == _parent) {
|
|
if (Bid.AdvancedOn) {
|
|
Bid.Trace("<sc.SmiEventSink_Default.MessagePosted|ADV> %d#, number=%d state=%d errorClass=%d server='%ls' message='%ls' procedure='%ls' linenumber=%d.\n",
|
|
0,
|
|
number,
|
|
state,
|
|
errorClass,
|
|
(null != server) ? server : "<null>",
|
|
(null != message) ? message : "<null>",
|
|
(null != procedure) ? procedure : "<null>",
|
|
lineNumber
|
|
);
|
|
}
|
|
SqlError error = new SqlError ( number, state, errorClass, server, message, procedure, lineNumber );
|
|
|
|
if ( error.Class < TdsEnums.MIN_ERROR_CLASS ) {
|
|
Warnings.Add( error );
|
|
}
|
|
else {
|
|
Errors.Add( error );
|
|
}
|
|
}
|
|
else {
|
|
_parent.MessagePosted( number, state, errorClass, server, message, procedure, lineNumber );
|
|
}
|
|
}
|
|
|
|
// Called for new resultset starting (COLMETADATA token)
|
|
internal override void MetaDataAvailable( SmiQueryMetaData[] metaData, bool nextEventIsRow ) {
|
|
if (null == _parent) {
|
|
throw SQL.UnexpectedSmiEvent(UnexpectedEventType.MetaDataAvailable);
|
|
}
|
|
_parent.MetaDataAvailable( metaData, nextEventIsRow );
|
|
}
|
|
|
|
// Called when a new row arrives (ROW token)
|
|
internal override void RowAvailable( ITypedGetters rowData ) {
|
|
if (null == _parent) {
|
|
throw SQL.UnexpectedSmiEvent(UnexpectedEventType.RowAvailable);
|
|
}
|
|
_parent.RowAvailable( rowData );
|
|
}
|
|
|
|
// Called when a new row arrives (ROW token)
|
|
internal override void RowAvailable( ITypedGettersV3 rowData ) {
|
|
if (null == _parent) {
|
|
throw SQL.UnexpectedSmiEvent(UnexpectedEventType.RowAvailable);
|
|
}
|
|
_parent.RowAvailable( rowData );
|
|
}
|
|
|
|
// Called when any statement completes on server (DONE token)
|
|
internal override void StatementCompleted( int rowsAffected ) {
|
|
if (null == _parent) {
|
|
throw SQL.UnexpectedSmiEvent(UnexpectedEventType.StatementCompleted);
|
|
}
|
|
_parent.StatementCompleted( rowsAffected );
|
|
}
|
|
|
|
// Called when a transaction is commited (ENVCHANGE token)
|
|
internal override void TransactionCommitted( long transactionId ) {
|
|
if (null == _parent) {
|
|
throw SQL.UnexpectedSmiEvent(UnexpectedEventType.TransactionCommitted);
|
|
}
|
|
_parent.TransactionCommitted( transactionId );
|
|
}
|
|
|
|
// Called when a transaction is commited (ENVCHANGE token)
|
|
internal override void TransactionDefected( long transactionId ) {
|
|
if (null == _parent) {
|
|
throw SQL.UnexpectedSmiEvent(UnexpectedEventType.TransactionDefected);
|
|
}
|
|
_parent.TransactionDefected( transactionId );
|
|
}
|
|
|
|
// Called when a transaction is commited (ENVCHANGE token)
|
|
internal override void TransactionEnlisted( long transactionId ) {
|
|
if (null == _parent) {
|
|
throw SQL.UnexpectedSmiEvent(UnexpectedEventType.TransactionEnlisted);
|
|
}
|
|
_parent.TransactionEnlisted( transactionId );
|
|
}
|
|
|
|
// Called when a transaction is forcibly ended in the server, not requested
|
|
// by the provider's batch (ENVCHANGE token)
|
|
internal override void TransactionEnded( long transactionId ) {
|
|
if (null == _parent) {
|
|
throw SQL.UnexpectedSmiEvent(UnexpectedEventType.TransactionEnded);
|
|
}
|
|
_parent.TransactionEnded( transactionId );
|
|
}
|
|
|
|
// Called when a transaction is rolled back (ENVCHANGE token)
|
|
internal override void TransactionRolledBack( long transactionId ) {
|
|
if (null == _parent) {
|
|
throw SQL.UnexpectedSmiEvent(UnexpectedEventType.TransactionRolledBack);
|
|
}
|
|
_parent.TransactionRolledBack( transactionId );
|
|
}
|
|
|
|
// Called when a transaction is started (ENVCHANGE token)
|
|
internal override void TransactionStarted( long transactionId ) {
|
|
if (null == _parent) {
|
|
throw SQL.UnexpectedSmiEvent(UnexpectedEventType.TransactionStarted);
|
|
}
|
|
_parent.TransactionStarted( transactionId );
|
|
}
|
|
}
|
|
}
|
|
|