Skip to content

Commit e7485e3

Browse files
committed
Implement GetTextReader and GetFieldValue<TextReader>. #631
MySqlDataReader.GetTextReader will throw InvalidCastException for a NULL field value, instead of returning a TextReader for an empty string. This makes GetTextReader and GetFieldValue<TextReader> consistent (and matches npgsql), but is different from Connector/NET and SqlClient.
1 parent 6600c75 commit e7485e3

File tree

2 files changed

+27
-9
lines changed

2 files changed

+27
-9
lines changed

src/MySqlConnector/MySql.Data.MySqlClient/MySqlDataReader.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,9 @@ public override long GetChars(int ordinal, long dataOffset, char[] buffer, int b
212212
public override Stream GetStream(int ordinal) => GetResultSet().GetCurrentRow().GetStream(ordinal);
213213
public Stream GetStream(string name) => GetStream(GetOrdinal(name));
214214

215+
public override TextReader GetTextReader(int ordinal) => new StringReader(GetString(ordinal));
216+
public TextReader GetTextReader(string name) => new StringReader(GetString(name));
217+
215218
public override string GetString(int ordinal) => GetResultSet().GetCurrentRow().GetString(ordinal);
216219
public string GetString(string name) => GetString(GetOrdinal(name));
217220

@@ -263,6 +266,8 @@ public override T GetFieldValue<T>(int ordinal)
263266
{
264267
if (typeof(T) == typeof(DateTimeOffset))
265268
return (T) Convert.ChangeType(GetDateTimeOffset(ordinal), typeof(T));
269+
if (typeof(T) == typeof(TextReader) || typeof(T) == typeof(StringReader))
270+
return (T) (object) GetTextReader(ordinal);
266271

267272
return base.GetFieldValue<T>(ordinal);
268273
}

tests/SideBySide/DataTypes.cs

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Data.Common;
33
using System.Globalization;
4+
using System.IO;
45
using System.Linq;
56
using System.Reflection;
67
using System.Threading.Tasks;
@@ -343,6 +344,13 @@ public void QueryDecimal(string column, object[] expected)
343344
public void QueryString(string column, string[] expected)
344345
{
345346
DoQuery("strings", column, "VARCHAR", expected, reader => reader.GetString(0));
347+
#if !BASELINE
348+
DoQuery("strings", column, "VARCHAR", expected, reader => reader.GetTextReader(0), matchesDefaultType: false, assertEqual: (e, a) =>
349+
{
350+
using (var actualReader = (TextReader) a)
351+
Assert.Equal(e, actualReader.ReadToEnd());
352+
}, getFieldValueType: typeof(TextReader));
353+
#endif
346354
}
347355
const string c_251ByteString = "This string has exactly 251 characters in it. The encoded length is stored as 0xFC 0xFB 0x00. 0xFB (i.e., 251) is the sentinel byte indicating \"this field is null\". Incorrectly interpreting the (decoded) length as the sentinel byte would corrupt data.";
348356

@@ -1345,9 +1353,11 @@ private void DoQuery(
13451353
object baselineCoercedNullValue = null,
13461354
bool omitWhereTest = false,
13471355
bool matchesDefaultType = true,
1348-
MySqlConnection connection = null)
1356+
MySqlConnection connection = null,
1357+
Action<object, object> assertEqual = null,
1358+
Type getFieldValueType = null)
13491359
{
1350-
DoQuery<GetValueWhenNullException>(table, column, dataTypeName, expected, getValue, baselineCoercedNullValue, omitWhereTest, matchesDefaultType, connection);
1360+
DoQuery<GetValueWhenNullException>(table, column, dataTypeName, expected, getValue, baselineCoercedNullValue, omitWhereTest, matchesDefaultType, connection, assertEqual, getFieldValueType);
13511361
}
13521362

13531363
// NOTE: baselineCoercedNullValue is to work around inconsistencies in mysql-connector-net; DBNull.Value will
@@ -1361,10 +1371,13 @@ private void DoQuery<TException>(
13611371
object baselineCoercedNullValue = null,
13621372
bool omitWhereTest = false,
13631373
bool matchesDefaultType = true,
1364-
MySqlConnection connection = null)
1374+
MySqlConnection connection = null,
1375+
Action<object, object> assertEqual = null,
1376+
Type getFieldValueType = null)
13651377
where TException : Exception
13661378
{
13671379
connection = connection ?? Connection;
1380+
assertEqual = assertEqual ?? Assert.Equal;
13681381
using (var cmd = connection.CreateCommand())
13691382
{
13701383
cmd.CommandText = $"select {column} from datatypes_{table} order by rowid";
@@ -1389,34 +1402,34 @@ private void DoQuery<TException>(
13891402
}
13901403
else
13911404
{
1392-
Assert.Equal(value, getValue(reader));
1405+
assertEqual(value, getValue(reader));
13931406

13941407
// test `reader.GetValue` and `reader.GetFieldType` if value matches default type
13951408
if (matchesDefaultType)
13961409
{
1397-
Assert.Equal(value, reader.GetValue(0));
1410+
assertEqual(value, reader.GetValue(0));
13981411
Assert.Equal(value.GetType(), reader.GetFieldType(0));
13991412
Assert.Equal(value.GetType(), reader.GetFieldType(column.Replace("`", "")));
14001413
}
14011414

14021415
// test `reader.GetFieldValue<value.GetType()>`
14031416
var syncMethod = typeof(MySqlDataReader)
14041417
.GetMethod("GetFieldValue")
1405-
.MakeGenericMethod(value.GetType());
1406-
Assert.Equal(value, syncMethod.Invoke(reader, new object[] { 0 }));
1418+
.MakeGenericMethod(getFieldValueType ?? value.GetType());
1419+
assertEqual(value, syncMethod.Invoke(reader, new object[] { 0 }));
14071420

14081421
// test `reader.GetFieldValueAsync<value.GetType()>`
14091422
var asyncMethod = typeof(MySqlDataReader)
14101423
.GetMethod("GetFieldValueAsync", new[] { typeof(int) })
1411-
.MakeGenericMethod(value.GetType());
1424+
.MakeGenericMethod(getFieldValueType ?? value.GetType());
14121425
var asyncMethodValue = asyncMethod.Invoke(reader, new object[] { 0 });
14131426
var asyncMethodGetAwaiter = asyncMethodValue.GetType()
14141427
.GetMethod("GetAwaiter");
14151428
var asyncMethodGetAwaiterValue = asyncMethodGetAwaiter.Invoke(asyncMethodValue, new object[] { });
14161429
var asyncMethodGetResult = asyncMethodGetAwaiterValue.GetType()
14171430
.GetMethod("GetResult");
14181431
var asyncMethodGetResultValue = asyncMethodGetResult.Invoke(asyncMethodGetAwaiterValue, new object[] { });
1419-
Assert.Equal(value, asyncMethodGetResultValue);
1432+
assertEqual(value, asyncMethodGetResultValue);
14201433
}
14211434
}
14221435
Assert.False(reader.Read());

0 commit comments

Comments
 (0)