Skip to content

Commit

Permalink
Fix | Perform Null check for SqlErrors in SqlException (dotnet#698)
Browse files Browse the repository at this point in the history
  • Loading branch information
cheenamalhotra authored and TrayanZapryanov committed Aug 31, 2020
1 parent be08e14 commit bddefe8
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 127 deletions.
26 changes: 18 additions & 8 deletions doc/snippets/Microsoft.Data.SqlClient/SqlException.xml
Expand Up @@ -85,7 +85,9 @@ catch (Exception ex) {
For information about the warning and informational messages sent by SQL Server, see the Troubleshooting section of the SQL Server documentation.
This is a wrapper for the <xref:Microsoft.Data.SqlClient.SqlError.Class%2A> property of the first <xref:Microsoft.Data.SqlClient.SqlError> in the <xref:Microsoft.Data.SqlClient.SqlException.Errors%2A> property.
If <xref:Microsoft.Data.SqlClient.SqlException.Errors%2A> is `null`, the [`default`](https://docs.microsoft.com/dotnet/csharp/language-reference/builtin-types/default-values) value for `byte` is returned.
## Examples
Expand Down Expand Up @@ -161,7 +163,9 @@ catch (Exception ex) {
The line numbering starts at 1; if 0 is returned, the line number is not applicable.
This is a wrapper for the <xref:Microsoft.Data.SqlClient.SqlError.LineNumber%2A> property of the first <xref:Microsoft.Data.SqlClient.SqlError> in the <xref:Microsoft.Data.SqlClient.SqlException.Errors%2A> property.
If <xref:Microsoft.Data.SqlClient.SqlException.Errors%2A> is `null`, the [`default`](https://docs.microsoft.com/dotnet/csharp/language-reference/builtin-types/default-values) value for `int` is returned.
## Examples
Expand Down Expand Up @@ -190,7 +194,11 @@ catch (Exception ex) {
<format type="text/markdown"><![CDATA[
## Remarks
This is a wrapper for the <xref:Microsoft.Data.SqlClient.SqlError.Number%2A> property of the first <xref:Microsoft.Data.SqlClient.SqlError> in the <xref:Microsoft.Data.SqlClient.SqlException.Errors%2A> property. For more information on SQL Server engine errors, see [Database Engine Events and Errors](/sql/relational-databases/errors-events/database-engine-events-and-errors).
This is a wrapper for the <xref:Microsoft.Data.SqlClient.SqlError.Number%2A> property of the first <xref:Microsoft.Data.SqlClient.SqlError> in the <xref:Microsoft.Data.SqlClient.SqlException.Errors%2A> property.
If <xref:Microsoft.Data.SqlClient.SqlException.Errors%2A> is `null`, the [`default`](https://docs.microsoft.com/dotnet/csharp/language-reference/builtin-types/default-values) value for `int` is returned.
For more information on SQL Server engine errors, see [Database Engine Events and Errors](/sql/relational-databases/errors-events/database-engine-events-and-errors).
Expand All @@ -215,8 +223,9 @@ catch (Exception ex) {
<format type="text/markdown"><![CDATA[
## Remarks
This is a wrapper for the <xref:Microsoft.Data.SqlClient.SqlError.Procedure%2A> property of the first <xref:Microsoft.Data.SqlClient.SqlError> in the <xref:Microsoft.Data.SqlClient.SqlException.Errors%2A> property.
This is a wrapper for the <xref:Microsoft.Data.SqlClient.SqlError.Procedure%2A> property of the first <xref:Microsoft.Data.SqlClient.SqlError> in the <xref:Microsoft.Data.SqlClient.SqlException.Errors%2A> property.
If <xref:Microsoft.Data.SqlClient.SqlException.Errors%2A> is `null`, the [`default`](https://docs.microsoft.com/dotnet/csharp/language-reference/builtin-types/default-values) value for `string` is returned.
## Examples
Expand All @@ -241,7 +250,8 @@ catch (Exception ex) {
## Remarks
This is a wrapper for the <xref:Microsoft.Data.SqlClient.SqlError.Server%2A> property of the first <xref:Microsoft.Data.SqlClient.SqlError> in the <xref:Microsoft.Data.SqlClient.SqlException.Errors%2A> property.
If <xref:Microsoft.Data.SqlClient.SqlException.Errors%2A> is `null`, the [`default`](https://docs.microsoft.com/dotnet/csharp/language-reference/builtin-types/default-values) value for `string` is returned.
## Examples
Expand All @@ -266,7 +276,6 @@ catch (Exception ex) {
## Remarks
This is a wrapper for the <xref:Microsoft.Data.SqlClient.SqlError.Source%2A> property of the first <xref:Microsoft.Data.SqlClient.SqlError> in the <xref:Microsoft.Data.SqlClient.SqlException.Errors%2A> property.
## Examples
Expand All @@ -291,7 +300,8 @@ catch (Exception ex) {
## Remarks
This is a wrapper for the <xref:Microsoft.Data.SqlClient.SqlError.State%2A> property of the first <xref:Microsoft.Data.SqlClient.SqlError> in the <xref:Microsoft.Data.SqlClient.SqlException.Errors%2A> property.
If <xref:Microsoft.Data.SqlClient.SqlException.Errors%2A> is `null`, the [`default`](https://docs.microsoft.com/dotnet/csharp/language-reference/builtin-types/default-values) value for `byte` is returned.
## Examples
Expand Down
Expand Up @@ -9,34 +9,23 @@ namespace Microsoft.Data.SqlClient
/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlError.xml' path='docs/members[@name="SqlError"]/SqlError/*' />
public sealed class SqlError
{
private string _source = TdsEnums.SQL_PROVIDER_NAME;
private int _number;
private byte _state;
private byte _errorClass;
private string _server;
private string _message;
private string _procedure;
private int _lineNumber;
private int _win32ErrorCode;
private Exception _exception;

internal SqlError(int infoNumber, byte errorState, byte errorClass, string server, string errorMessage, string procedure, int lineNumber, uint win32ErrorCode, Exception exception = null)
: this(infoNumber, errorState, errorClass, server, errorMessage, procedure, lineNumber, exception)
{
_win32ErrorCode = (int)win32ErrorCode;
Win32ErrorCode = (int)win32ErrorCode;
}

internal SqlError(int infoNumber, byte errorState, byte errorClass, string server, string errorMessage, string procedure, int lineNumber, Exception exception = null)
{
_number = infoNumber;
_state = errorState;
_errorClass = errorClass;
_server = server;
_message = errorMessage;
_procedure = procedure;
_lineNumber = lineNumber;
_win32ErrorCode = 0;
_exception = exception;
Number = infoNumber;
State = errorState;
Class = errorClass;
Server = server;
Message = errorMessage;
Procedure = procedure;
LineNumber = lineNumber;
Win32ErrorCode = 0;
Exception = exception;
if (errorClass != 0)
{
SqlClientEventSource.Log.TraceEvent("<sc.SqlError.SqlError|ERR> infoNumber={0}, errorState={1}, errorClass={2}, errorMessage='{3}', procedure='{4}', lineNumber={5}", infoNumber, (int)errorState, (int)errorClass, errorMessage, procedure ?? "None", (int)lineNumber);
Expand All @@ -49,65 +38,35 @@ internal SqlError(int infoNumber, byte errorState, byte errorClass, string serve
// way back to SqlException. If the user needs a call stack, they can obtain it on SqlException.
public override string ToString()
{
return typeof(SqlError).ToString() + ": " + _message; // since this is sealed so we can change GetType to typeof
return typeof(SqlError).ToString() + ": " + Message; // since this is sealed so we can change GetType to typeof
}

/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlError.xml' path='docs/members[@name="SqlError"]/Source/*' />
public string Source
{
get { return _source; }
}
public string Source { get; private set; } = TdsEnums.SQL_PROVIDER_NAME;

/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlError.xml' path='docs/members[@name="SqlError"]/Number/*' />
public int Number
{
get { return _number; }
}
public int Number { get; private set; }

/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlError.xml' path='docs/members[@name="SqlError"]/State/*' />
public byte State
{
get { return _state; }
}
public byte State { get; private set; }

/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlError.xml' path='docs/members[@name="SqlError"]/Class/*' />
public byte Class
{
get { return _errorClass; }
}
public byte Class { get; private set; }

/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlError.xml' path='docs/members[@name="SqlError"]/Server/*' />
public string Server
{
get { return _server; }
}
public string Server { get; private set; }

/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlError.xml' path='docs/members[@name="SqlError"]/Message/*' />
public string Message
{
get { return _message; }
}
public string Message { get; private set; }

/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlError.xml' path='docs/members[@name="SqlError"]/Procedure/*' />
public string Procedure
{
get { return _procedure; }
}
public string Procedure { get; private set; }

/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlError.xml' path='docs/members[@name="SqlError"]/LineNumber/*' />
public int LineNumber
{
get { return _lineNumber; }
}
public int LineNumber { get; private set; }

internal int Win32ErrorCode
{
get { return _win32ErrorCode; }
}
internal int Win32ErrorCode { get; private set; }

internal Exception Exception
{
get { return _exception; }
}
internal Exception Exception { get; private set; }
}
}
Expand Up @@ -89,7 +89,7 @@ public Guid ClientConnectionId
/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlException.xml' path='docs/members[@name="SqlException"]/Class/*' />
public byte Class
{
get { return Errors.Count > 0 ? this.Errors[0].Class : default; }
get { return Errors.Count > 0 ? Errors[0].Class : default; }
}

/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlException.xml' path='docs/members[@name="SqlException"]/LineNumber/*' />
Expand Down Expand Up @@ -125,7 +125,7 @@ public byte State
/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlException.xml' path='docs/members[@name="SqlException"]/Source/*' />
override public string Source
{
get { return Errors.Count > 0 ? Errors[0].Source : default; }
get { return TdsEnums.SQL_PROVIDER_NAME; }
}

/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlException.xml' path='docs/members[@name="SqlException"]/ToString/*' />
Expand Down
Expand Up @@ -6,109 +6,108 @@

namespace Microsoft.Data.SqlClient
{
/// <include file='..\..\..\..\..\..\..\doc\snippets\Microsoft.Data.SqlClient\SqlError.xml' path='docs/members[@name="SqlError"]/SqlError/*' />
/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlError.xml' path='docs/members[@name="SqlError"]/SqlError/*' />
[Serializable]
public sealed class SqlError
{

// bug fix - MDAC 48965 - missing source of exception
private string source = TdsEnums.SQL_PROVIDER_NAME;
private int number;
private byte state;
private byte errorClass;
[System.Runtime.Serialization.OptionalFieldAttribute(VersionAdded = 2)]
private string server;
private string message;
private string procedure;
private int lineNumber;
[System.Runtime.Serialization.OptionalFieldAttribute(VersionAdded = 4)]
private int win32ErrorCode;
private readonly string _source = TdsEnums.SQL_PROVIDER_NAME;
private readonly int _number;
private readonly byte _state;
private readonly byte _errorClass;
[System.Runtime.Serialization.OptionalField(VersionAdded = 2)]
private readonly string _server;
private readonly string _message;
private readonly string _procedure;
private readonly int _lineNumber;
[System.Runtime.Serialization.OptionalField(VersionAdded = 4)]
private readonly int _win32ErrorCode;

internal SqlError(int infoNumber, byte errorState, byte errorClass, string server, string errorMessage, string procedure, int lineNumber, uint win32ErrorCode)
: this(infoNumber, errorState, errorClass, server, errorMessage, procedure, lineNumber)
{
this.win32ErrorCode = (int)win32ErrorCode;
_win32ErrorCode = (int)win32ErrorCode;
}

internal SqlError(int infoNumber, byte errorState, byte errorClass, string server, string errorMessage, string procedure, int lineNumber)
{
this.number = infoNumber;
this.state = errorState;
this.errorClass = errorClass;
this.server = server;
this.message = errorMessage;
this.procedure = procedure;
this.lineNumber = lineNumber;
_number = infoNumber;
_state = errorState;
_errorClass = errorClass;
_server = server;
_message = errorMessage;
_procedure = procedure;
_lineNumber = lineNumber;
if (errorClass != 0)
{
SqlClientEventSource.Log.TraceEvent("<sc.SqlError.SqlError|ERR> infoNumber={0}, errorState={1}, errorClass={2}, errorMessage='{3}', procedure='{4}', lineNumber={5}", infoNumber, (int)errorState, (int)errorClass, errorMessage, procedure ?? "None", (int)lineNumber);
}
this.win32ErrorCode = 0;
_win32ErrorCode = 0;
}

/// <include file='..\..\..\..\..\..\..\doc\snippets\Microsoft.Data.SqlClient\SqlError.xml' path='docs/members[@name="SqlError"]/ToString/*' />
/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlError.xml' path='docs/members[@name="SqlError"]/ToString/*' />
// bug fix - MDAC #49280 - SqlError does not implement ToString();
// I did not include an exception stack because the correct exception stack is only available
// on SqlException, and to obtain that the SqlError would have to have backpointers all the
// way back to SqlException. If the user needs a call stack, they can obtain it on SqlException.
public override string ToString()
{
//return this.GetType().ToString() + ": " + this.message;
return typeof(SqlError).ToString() + ": " + this.message; // since this is sealed so we can change GetType to typeof
//return GetType().ToString() + ": " + message;
return typeof(SqlError).ToString() + ": " + _message; // since this is sealed so we can change GetType to typeof
}

/// <include file='..\..\..\..\..\..\..\doc\snippets\Microsoft.Data.SqlClient\SqlError.xml' path='docs/members[@name="SqlError"]/Source/*' />
/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlError.xml' path='docs/members[@name="SqlError"]/Source/*' />
// bug fix - MDAC #48965 - missing source of exception
public string Source
{
get { return this.source; }
get { return _source; }
}

/// <include file='..\..\..\..\..\..\..\doc\snippets\Microsoft.Data.SqlClient\SqlError.xml' path='docs/members[@name="SqlError"]/Number/*' />
/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlError.xml' path='docs/members[@name="SqlError"]/Number/*' />
public int Number
{
get { return this.number; }
get { return _number; }
}

/// <include file='..\..\..\..\..\..\..\doc\snippets\Microsoft.Data.SqlClient\SqlError.xml' path='docs/members[@name="SqlError"]/State/*' />
/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlError.xml' path='docs/members[@name="SqlError"]/State/*' />
public byte State
{
get { return this.state; }
get { return _state; }
}

/// <include file='..\..\..\..\..\..\..\doc\snippets\Microsoft.Data.SqlClient\SqlError.xml' path='docs/members[@name="SqlError"]/Class/*' />
/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlError.xml' path='docs/members[@name="SqlError"]/Class/*' />
public byte Class
{
get { return this.errorClass; }
get { return _errorClass; }
}

/// <include file='..\..\..\..\..\..\..\doc\snippets\Microsoft.Data.SqlClient\SqlError.xml' path='docs/members[@name="SqlError"]/Server/*' />
/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlError.xml' path='docs/members[@name="SqlError"]/Server/*' />
public string Server
{
get { return this.server; }
get { return _server; }
}

/// <include file='..\..\..\..\..\..\..\doc\snippets\Microsoft.Data.SqlClient\SqlError.xml' path='docs/members[@name="SqlError"]/Message/*' />
/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlError.xml' path='docs/members[@name="SqlError"]/Message/*' />
public string Message
{
get { return this.message; }
get { return _message; }
}

/// <include file='..\..\..\..\..\..\..\doc\snippets\Microsoft.Data.SqlClient\SqlError.xml' path='docs/members[@name="SqlError"]/Procedure/*' />
/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlError.xml' path='docs/members[@name="SqlError"]/Procedure/*' />
public string Procedure
{
get { return this.procedure; }
get { return _procedure; }
}

/// <include file='..\..\..\..\..\..\..\doc\snippets\Microsoft.Data.SqlClient\SqlError.xml' path='docs/members[@name="SqlError"]/LineNumber/*' />
/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlError.xml' path='docs/members[@name="SqlError"]/LineNumber/*' />
public int LineNumber
{
get { return this.lineNumber; }
get { return _lineNumber; }
}

internal int Win32ErrorCode
{
get { return this.win32ErrorCode; }
get { return _win32ErrorCode; }
}
}
}

0 comments on commit bddefe8

Please sign in to comment.