From 406b17de3ecfd9d4abdb18f0e4ddf493bc8367ea Mon Sep 17 00:00:00 2001 From: Wraith2 Date: Sat, 26 Jan 2019 22:12:30 +0000 Subject: [PATCH] change GetFieldValueFromSqlBufferInternal to check for XmlReader add SqlTypeWorkarounds xml reader creation overload for TextReader add DataStream test for GetFielvdValue for value and null Commit migrated from https://github.com/dotnet/corefx/commit/b4792140f978c102e9c104db6972d41646d12c98 --- .../src/System/Data/SqlClient/SqlDataReader.cs | 60 +++++++++++++++++----- .../src/System/Data/SqlTypes/SqlTypeWorkarounds.cs | 11 ++++ .../SQL/DataStreamTest/DataStreamTest.cs | 2 + 3 files changed, 61 insertions(+), 12 deletions(-) diff --git a/src/libraries/System.Data.SqlClient/src/System/Data/SqlClient/SqlDataReader.cs b/src/libraries/System.Data.SqlClient/src/System/Data/SqlClient/SqlDataReader.cs index e66d5cd..a509e71 100644 --- a/src/libraries/System.Data.SqlClient/src/System/Data/SqlClient/SqlDataReader.cs +++ b/src/libraries/System.Data.SqlClient/src/System/Data/SqlClient/SqlDataReader.cs @@ -2588,10 +2588,10 @@ namespace System.Data.SqlClient // If its a SQL Type or Nullable UDT object rawValue = GetSqlValueFromSqlBufferInternal(data, metaData); - // 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 if (typeofT == s_typeofSqlString) { + // 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 SqlXml xmlValue = rawValue as SqlXml; if (xmlValue != null) { @@ -2610,22 +2610,58 @@ namespace System.Data.SqlClient } else { - // Otherwise Its a CLR or non-Nullable UDT - try + if (typeof(XmlReader) == typeofT) { - return (T)GetValueFromSqlBufferInternal(data, metaData); + if (metaData.metaType.SqlDbType != SqlDbType.Xml) + { + throw SQL.XmlReaderNotSupportOnColumnType(metaData.column); + } + else + { + object clrValue = null; + if (!data.IsNull) + { + clrValue = GetValueFromSqlBufferInternal(data, metaData); + } + if (clrValue is null) // covers IsNull and when there is data which is present but is a clr null somehow + { + return (T)(object)SqlTypeWorkarounds.SqlXmlCreateSqlXmlReader( + new MemoryStream(Array.Empty(), writable: false), + closeInput: true + ); + } + else if (clrValue.GetType() == typeof(string)) + { + return (T)(object)SqlTypeWorkarounds.SqlXmlCreateSqlXmlReader( + new StringReader(clrValue as string), + closeInput: true + ); + } + else + { + // try the type cast to throw the invalid cast exception and inform the user what types they're trying to use and that why it is wrong + return (T)clrValue; + } + } } - catch (InvalidCastException) + else { - if (data.IsNull) + try { - // If the value was actually null, then we should throw a SqlNullValue instead - throw SQL.SqlNullValue(); + return (T)GetValueFromSqlBufferInternal(data, metaData); } - else + catch (InvalidCastException) { - // Legitimate InvalidCast, rethrow - throw; + if (data.IsNull) + { + // If the value was actually null, then we should throw a SqlNullValue instead + throw SQL.SqlNullValue(); + } + else + { + // Legitimate InvalidCast, rethrow + throw; + } } } } diff --git a/src/libraries/System.Data.SqlClient/src/System/Data/SqlTypes/SqlTypeWorkarounds.cs b/src/libraries/System.Data.SqlClient/src/System/Data/SqlTypes/SqlTypeWorkarounds.cs index 1757441..0e18a0d 100644 --- a/src/libraries/System.Data.SqlClient/src/System/Data/SqlTypes/SqlTypeWorkarounds.cs +++ b/src/libraries/System.Data.SqlClient/src/System/Data/SqlTypes/SqlTypeWorkarounds.cs @@ -37,6 +37,17 @@ namespace System.Data.SqlTypes return XmlReader.Create(stream, settingsToUse); } + + internal static XmlReader SqlXmlCreateSqlXmlReader(TextReader textReader, bool closeInput = false, bool async = false) + { + Debug.Assert(closeInput || !async, "Currently we do not have pre-created settings for !closeInput+async"); + + XmlReaderSettings settingsToUse = closeInput ? + (async ? s_defaultXmlReaderSettingsAsyncCloseInput : s_defaultXmlReaderSettingsCloseInput) : + s_defaultXmlReaderSettings; + + return XmlReader.Create(textReader, settingsToUse); + } #endregion #region Work around inability to access SqlDateTime.ToDateTime diff --git a/src/libraries/System.Data.SqlClient/tests/ManualTests/SQL/DataStreamTest/DataStreamTest.cs b/src/libraries/System.Data.SqlClient/tests/ManualTests/SQL/DataStreamTest/DataStreamTest.cs index add701b..4354954 100644 --- a/src/libraries/System.Data.SqlClient/tests/ManualTests/SQL/DataStreamTest/DataStreamTest.cs +++ b/src/libraries/System.Data.SqlClient/tests/ManualTests/SQL/DataStreamTest/DataStreamTest.cs @@ -294,6 +294,8 @@ namespace System.Data.SqlClient.ManualTesting.Tests rdr.GetFieldValue(15); rdr.GetFieldValue(14); rdr.GetFieldValue(15); + rdr.GetFieldValue(14); + rdr.GetFieldValue(15); rdr.Read(); Assert.True(rdr.IsDBNullAsync(11).Result, "FAILED: IsDBNull was false for a null value"); -- 2.7.4