Skip to content

Commit

Permalink
Merge branch 'dotnet:main' into Move-to-shared-SqlSer
Browse files Browse the repository at this point in the history
  • Loading branch information
Kaur-Parminder authored Dec 21, 2021
2 parents 0e2dafd + d4f69fd commit 04593ff
Show file tree
Hide file tree
Showing 10 changed files with 332 additions and 74 deletions.
2 changes: 1 addition & 1 deletion doc/snippets/Microsoft.Data.SqlClient/SqlDataReader.xml
Original file line number Diff line number Diff line change
Expand Up @@ -532,7 +532,7 @@
<format type="text/markdown"><![CDATA[
## Remarks
For the <xref:Microsoft.Data.SqlClient.SqlDataReader.GetSchemaTable%2A> method returns metadata about each column in the following order:
The <xref:Microsoft.Data.SqlClient.SqlDataReader.GetSchemaTable%2A> method returns the following metadata about each column:
|DataReader column|Description|
|-----------------------|-----------------|
Expand Down
12 changes: 12 additions & 0 deletions src/Microsoft.Data.SqlClient/netcore/src/.editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# editorconfig.org

# top-most EditorConfig file
root = false

[*.cs]

# IDE0090: Use 'new(...)'
csharp_style_implicit_object_creation_when_type_is_apparent = false

# IDE0063: Use simple 'using' statement
csharp_prefer_simple_using_statement = false
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ private SqlBuffer(SqlBuffer value)
_object = value._object;
}

internal bool IsEmpty => (StorageType.Empty == _type);
internal bool IsEmpty => _type == StorageType.Empty;

internal bool IsNull => _isNull;

Expand Down Expand Up @@ -386,7 +386,6 @@ internal Guid Guid
return ((SqlGuid)_object).Value;
}
return (Guid)Value;

}
set
{
Expand Down Expand Up @@ -1336,13 +1335,13 @@ private void ThrowIfNull()
// where typeof(T) == typeof(field)
// 1) RyuJIT will recognize the pattern of (T)(object)T as being redundant and eliminate
// the T and object casts leaving T, so while this looks like it will put every value type instance in a box the
// enerated assembly will be short and direct
// generated assembly will be short and direct
// 2) another jit may not recognize the pattern and should emit the code as seen. this will box and then unbox the
// value type which is no worse than the mechanism that this code replaces
// where typeof(T) != typeof(field)
// the jit will emit all the cast operations as written. this will put the value into a box and then attempt to
// cast it, because it is an object even no conversions are use and this will generate the desired InvalidCastException
// so users cannot widen a short to an int preserving external expectations
// cast it, because it is an object no conversions are used and this will generate the desired InvalidCastException
// for example users cannot widen a short to an int preserving external expectations

internal T ByteAs<T>()
{
Expand Down Expand Up @@ -1386,4 +1385,4 @@ internal T SingleAs<T>()
return (T)(object)_value._single;
}
}
}// namespace
}
Original file line number Diff line number Diff line change
Expand Up @@ -87,14 +87,9 @@ internal class SharedState

private Task _currentTask;
private Snapshot _snapshot;

private CancellationTokenSource _cancelAsyncOnCloseTokenSource;
private CancellationToken _cancelAsyncOnCloseToken;

// Used for checking if the Type parameter provided to GetValue<T> is an INullable
internal static readonly Type _typeofINullable = typeof(INullable);
private static readonly Type s_typeofSqlString = typeof(SqlString);

private SqlSequentialStream _currentStream;
private SqlSequentialTextReader _currentTextReader;

Expand Down Expand Up @@ -2955,7 +2950,7 @@ private T GetFieldValueFromSqlBufferInternal<T>(SqlBuffer data, _SqlMetaData met
{
// If its a SQL Type or Nullable UDT
object rawValue = GetSqlValueFromSqlBufferInternal(data, metaData);
if (typeof(T) == s_typeofSqlString)
if (typeof(T) == typeof(SqlString))
{
// Special case: User wants SqlString, but we have a SqlXml
// SqlXml can not be typecast into a SqlString, but we need to support SqlString on XML Types - so do a manual conversion
Expand Down Expand Up @@ -2986,6 +2981,7 @@ private T GetFieldValueFromSqlBufferInternal<T>(SqlBuffer data, _SqlMetaData met
}
catch (InvalidCastException) when (data.IsNull)
{
// If the value was actually null, then we should throw a SqlNullValue instead
throw SQL.SqlNullValue();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ internal sealed partial class TdsParser
{
private static int _objectTypeCount; // EventSource counter
private readonly SqlClientLogger _logger = new SqlClientLogger();
private readonly string _typeName;

internal readonly int _objectID = Interlocked.Increment(ref _objectTypeCount);
internal int ObjectID => _objectID;
Expand Down Expand Up @@ -194,7 +193,6 @@ internal TdsParser(bool MARS, bool fAsynchronous)

_physicalStateObj = TdsParserStateObjectFactory.Singleton.CreateTdsParserStateObject(this);
DataClassificationVersion = TdsEnums.DATA_CLASSIFICATION_NOT_ENABLED;
_typeName = GetType().Name;
}

internal SqlInternalConnectionTds Connection
Expand Down Expand Up @@ -963,7 +961,7 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake(bool encrypt, bool trus
if (!string.IsNullOrEmpty(warningMessage))
{
// This logs console warning of insecure protocol in use.
_logger.LogWarning(_typeName, MethodBase.GetCurrentMethod().Name, warningMessage);
_logger.LogWarning(GetType().Name, MethodBase.GetCurrentMethod().Name, warningMessage);
}

// create a new packet encryption changes the internal packet size
Expand Down Expand Up @@ -11094,15 +11092,21 @@ private Task WriteUnterminatedSqlValue(object value, MetaType type, int actualLe
{
Debug.Assert(actualLength == 16, "Invalid length for guid type in com+ object");
Span<byte> b = stackalloc byte[16];
SqlGuid sqlGuid = (SqlGuid)value;

if (sqlGuid.IsNull)
if (value is Guid guid)
{
b.Clear(); // this is needed because initlocals may be supressed in framework assemblies meaning the memory is not automaticaly zeroed
FillGuidBytes(guid, b);
}
else
{
FillGuidBytes(sqlGuid.Value, b);
SqlGuid sqlGuid = (SqlGuid)value;
if (sqlGuid.IsNull)
{
b.Clear(); // this is needed because initlocals may be supressed in framework assemblies meaning the memory is not automaticaly zeroed
}
else
{
FillGuidBytes(sqlGuid.Value, b);
}
}
stateObj.WriteByteSpan(b);
break;
Expand Down
9 changes: 9 additions & 0 deletions src/Microsoft.Data.SqlClient/netfx/src/.editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# editorconfig.org

# top-most EditorConfig file
root = false

[*.cs]

# IDE0090: Use 'new(...)'
csharp_style_implicit_object_creation_when_type_is_apparent = false
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ internal enum StorageType
Int16,
Int32,
Int64,
Guid,
Money,
Single,
String,
Expand Down Expand Up @@ -94,6 +95,8 @@ internal struct Storage
[FieldOffset(0)]
internal long _int64; // also used to store Money, UtcDateTime, Date , and Time
[FieldOffset(0)]
internal Guid _guid;
[FieldOffset(0)]
internal float _single;
[FieldOffset(0)]
internal TimeInfo _timeInfo;
Expand Down Expand Up @@ -123,7 +126,7 @@ private SqlBuffer(SqlBuffer value)
_object = value._object;
}

internal bool IsEmpty => StorageType.Empty == _type;
internal bool IsEmpty => _type == StorageType.Empty;

internal bool IsNull => _isNull;

Expand Down Expand Up @@ -216,16 +219,16 @@ internal decimal Decimal
// Only removing trailing zeros from a decimal part won't hit its value!
if (_value._numericInfo._scale > 0)
{
int zeroCnt = FindTrailingZerosAndPrec((uint)_value._numericInfo._data1, (uint)_value._numericInfo._data2,
(uint)_value._numericInfo._data3, (uint)_value._numericInfo._data4,
int zeroCnt = FindTrailingZerosAndPrec((uint)_value._numericInfo._data1, (uint)_value._numericInfo._data2,
(uint)_value._numericInfo._data3, (uint)_value._numericInfo._data4,
_value._numericInfo._scale, out int precision);

int minScale = _value._numericInfo._scale - zeroCnt; // minimum possible sacle after removing the trailing zeros.

if (zeroCnt > 0 && minScale <= 28 && precision <= 29)
{
SqlDecimal sqlValue = new(_value._numericInfo._precision, _value._numericInfo._scale, _value._numericInfo._positive,
_value._numericInfo._data1, _value._numericInfo._data2,
SqlDecimal sqlValue = new(_value._numericInfo._precision, _value._numericInfo._scale, _value._numericInfo._positive,
_value._numericInfo._data1, _value._numericInfo._data2,
_value._numericInfo._data3, _value._numericInfo._data4);

int integral = precision - minScale;
Expand Down Expand Up @@ -373,9 +376,23 @@ internal Guid Guid
{
get
{
// TODO: It is possible to further optimize this, by storing the data from the wire without constructing a SqlGuid first, however we're already twice as fast!
ThrowIfNull();
return SqlGuid.Value;
if (StorageType.Guid == _type)
{
return _value._guid;
}
else if (StorageType.SqlGuid == _type)
{
return ((SqlGuid)_object).Value;
}
return (Guid)Value;
}
set
{
Debug.Assert(IsEmpty, "setting value a second time?");
_type = StorageType.Guid;
_value._guid = value;
_isNull = false;
}
}

Expand Down Expand Up @@ -481,7 +498,7 @@ internal string String
}
}

// use static list of format strings indexed by scale for perf!
// use static list of format strings indexed by scale for perf
private static readonly string[] s_katmaiDateTimeOffsetFormatByScale = new string[] {
"yyyy-MM-dd HH:mm:ss zzz",
"yyyy-MM-dd HH:mm:ss.f zzz",
Expand Down Expand Up @@ -757,9 +774,13 @@ internal SqlGuid SqlGuid
{
get
{
if (StorageType.SqlGuid == _type)
if (StorageType.Guid == _type)
{
return (SqlGuid)_object;
return new SqlGuid(_value._guid);
}
else if (StorageType.SqlGuid == _type)
{
return IsNull ? SqlGuid.Null : (SqlGuid)_object;
}
return (SqlGuid)SqlValue; // anything else we haven't thought of goes through boxing.
}
Expand Down Expand Up @@ -901,6 +922,8 @@ internal object SqlValue
return SqlInt32;
case StorageType.Int64:
return SqlInt64;
case StorageType.Guid:
return SqlGuid;
case StorageType.Money:
return SqlMoney;
case StorageType.Single:
Expand Down Expand Up @@ -956,6 +979,10 @@ internal object SqlValue
}
}


// these variables store pre-boxed bool values to be used when returning a boolean
// in a object typed location, if these are not used a new value is boxed each time
// one is needed which leads to a lot of garbage which needs to be collected
private static readonly object s_cachedTrueObject = true;
private static readonly object s_cachedFalseObject = false;

Expand All @@ -972,7 +999,7 @@ internal object Value
case StorageType.Empty:
return DBNull.Value;
case StorageType.Boolean:
return Boolean ? s_cachedTrueObject : s_cachedFalseObject;
return Boolean ? s_cachedTrueObject : s_cachedFalseObject; // return pre-boxed values for perf
case StorageType.Byte:
return Byte;
case StorageType.DateTime:
Expand All @@ -987,6 +1014,8 @@ internal object Value
return Int32;
case StorageType.Int64:
return Int64;
case StorageType.Guid:
return Guid;
case StorageType.Money:
return Decimal;
case StorageType.Single:
Expand Down Expand Up @@ -1048,6 +1077,8 @@ internal Type GetTypeFromStorageType(bool isSqlType)
return typeof(SqlInt32);
case StorageType.Int64:
return typeof(SqlInt64);
case StorageType.Guid:
return typeof(SqlGuid);
case StorageType.Money:
return typeof(SqlMoney);
case StorageType.Single:
Expand Down Expand Up @@ -1087,6 +1118,8 @@ internal Type GetTypeFromStorageType(bool isSqlType)
return typeof(int);
case StorageType.Int64:
return typeof(long);
case StorageType.Guid:
return typeof(Guid);
case StorageType.Money:
return typeof(decimal);
case StorageType.Single:
Expand Down Expand Up @@ -1309,5 +1342,59 @@ private void ThrowIfNull()
throw new SqlNullValueException();
}
}
// [Field]As<T> method explanation:
// these methods are used to bridge generic to non-generic access to value type fields on the storage struct
// where typeof(T) == typeof(field)
// 1) RyuJIT will recognize the pattern of (T)(object)T as being redundant and eliminate
// the T and object casts leaving T, so while this looks like it will put every value type instance in a box the
// generated assembly will be short and direct
// 2) another jit may not recognize the pattern and should emit the code as seen. this will box and then unbox the
// value type which is no worse than the mechanism that this code replaces
// where typeof(T) != typeof(field)
// the jit will emit all the cast operations as written. this will put the value into a box and then attempt to
// cast it, because it is an object no conversions are used and this will generate the desired InvalidCastException
// for example users cannot widen a short to an int preserving external expectations

internal T ByteAs<T>()
{
ThrowIfNull();
return (T)(object)_value._byte;
}

internal T BooleanAs<T>()
{
ThrowIfNull();
return (T)(object)_value._boolean;
}

internal T Int32As<T>()
{
ThrowIfNull();
return (T)(object)_value._int32;
}

internal T Int16As<T>()
{
ThrowIfNull();
return (T)(object)_value._int16;
}

internal T Int64As<T>()
{
ThrowIfNull();
return (T)(object)_value._int64;
}

internal T DoubleAs<T>()
{
ThrowIfNull();
return (T)(object)_value._double;
}

internal T SingleAs<T>()
{
ThrowIfNull();
return (T)(object)_value._single;
}
}
}
Loading

0 comments on commit 04593ff

Please sign in to comment.