diff --git a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Contracts/DbCellValue.cs b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Contracts/DbCellValue.cs index 258c0548..343ebeb3 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Contracts/DbCellValue.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Contracts/DbCellValue.cs @@ -27,6 +27,12 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts /// internal object RawObject { get; set; } + /// + /// The internal ID for the row. Should be used when directly referencing the row for edit + /// or other purposes. + /// + public long RowId { get; set; } + /// /// Copies the values of this DbCellValue into another DbCellValue (or child object) /// @@ -38,6 +44,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts other.DisplayValue = DisplayValue; other.IsNull = IsNull; other.RawObject = RawObject; + other.RowId = RowId; } } } diff --git a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/DataStorage/IFileStreamReader.cs b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/DataStorage/IFileStreamReader.cs index 38a609a7..1ecc5c0b 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/DataStorage/IFileStreamReader.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/DataStorage/IFileStreamReader.cs @@ -14,6 +14,6 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage /// public interface IFileStreamReader : IDisposable { - IList ReadRow(long offset, IEnumerable columns); + IList ReadRow(long offset, long rowId, IEnumerable columns); } } diff --git a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/DataStorage/ServiceBufferFileStreamReader.cs b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/DataStorage/ServiceBufferFileStreamReader.cs index 0b5275c3..aea7a5c0 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/DataStorage/ServiceBufferFileStreamReader.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/DataStorage/ServiceBufferFileStreamReader.cs @@ -30,13 +30,15 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage #region Member Variables + private delegate FileStreamReadResult ReadMethod(long fileOffset, long rowId, DbColumnWrapper column); + private byte[] buffer; private readonly QueryExecutionSettings executionSettings; private readonly Stream fileStream; - private readonly Dictionary> readMethods; + private readonly Dictionary readMethods; #endregion @@ -63,37 +65,37 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage buffer = new byte[DefaultBufferSize]; // Create the methods that will be used to read back - readMethods = new Dictionary> + readMethods = new Dictionary { - {typeof(string), (o, col) => ReadString(o)}, - {typeof(short), (o, col) => ReadInt16(o)}, - {typeof(int), (o, col) => ReadInt32(o)}, - {typeof(long), (o, col) => ReadInt64(o)}, - {typeof(byte), (o, col) => ReadByte(o)}, - {typeof(char), (o, col) => ReadChar(o)}, - {typeof(bool), (o, col) => ReadBoolean(o)}, - {typeof(double), (o, col) => ReadDouble(o)}, - {typeof(float), (o, col) => ReadSingle(o)}, - {typeof(decimal), (o, col) => ReadDecimal(o)}, + {typeof(string), (o, id, col) => ReadString(o, id)}, + {typeof(short), (o, id, col) => ReadInt16(o, id)}, + {typeof(int), (o, id, col) => ReadInt32(o, id)}, + {typeof(long), (o, id, col) => ReadInt64(o, id)}, + {typeof(byte), (o, id, col) => ReadByte(o, id)}, + {typeof(char), (o, id, col) => ReadChar(o, id)}, + {typeof(bool), (o, id, col) => ReadBoolean(o, id)}, + {typeof(double), (o, id, col) => ReadDouble(o, id)}, + {typeof(float), (o, id, col) => ReadSingle(o, id)}, + {typeof(decimal), (o, id, col) => ReadDecimal(o, id)}, {typeof(DateTime), ReadDateTime}, - {typeof(DateTimeOffset), (o, col) => ReadDateTimeOffset(o)}, - {typeof(TimeSpan), (o, col) => ReadTimeSpan(o)}, - {typeof(byte[]), (o, col) => ReadBytes(o)}, + {typeof(DateTimeOffset), (o, id, col) => ReadDateTimeOffset(o, id)}, + {typeof(TimeSpan), (o, id, col) => ReadTimeSpan(o, id)}, + {typeof(byte[]), (o, id, col) => ReadBytes(o, id)}, - {typeof(SqlString), (o, col) => ReadString(o)}, - {typeof(SqlInt16), (o, col) => ReadInt16(o)}, - {typeof(SqlInt32), (o, col) => ReadInt32(o)}, - {typeof(SqlInt64), (o, col) => ReadInt64(o)}, - {typeof(SqlByte), (o, col) => ReadByte(o)}, - {typeof(SqlBoolean), (o, col) => ReadBoolean(o)}, - {typeof(SqlDouble), (o, col) => ReadDouble(o)}, - {typeof(SqlSingle), (o, col) => ReadSingle(o)}, - {typeof(SqlDecimal), (o, col) => ReadSqlDecimal(o)}, + {typeof(SqlString), (o, id, col) => ReadString(o, id)}, + {typeof(SqlInt16), (o, id, col) => ReadInt16(o, id)}, + {typeof(SqlInt32), (o, id, col) => ReadInt32(o, id)}, + {typeof(SqlInt64), (o, id, col) => ReadInt64(o, id)}, + {typeof(SqlByte), (o, id, col) => ReadByte(o, id)}, + {typeof(SqlBoolean), (o, id, col) => ReadBoolean(o, id)}, + {typeof(SqlDouble), (o, id, col) => ReadDouble(o, id)}, + {typeof(SqlSingle), (o, id, col) => ReadSingle(o, id)}, + {typeof(SqlDecimal), (o, id, col) => ReadSqlDecimal(o, id)}, {typeof(SqlDateTime), ReadDateTime}, - {typeof(SqlBytes), (o, col) => ReadBytes(o)}, - {typeof(SqlBinary), (o, col) => ReadBytes(o)}, - {typeof(SqlGuid), (o, col) => ReadGuid(o)}, - {typeof(SqlMoney), (o, col) => ReadMoney(o)}, + {typeof(SqlBytes), (o, id, col) => ReadBytes(o, id)}, + {typeof(SqlBinary), (o, id, col) => ReadBytes(o, id)}, + {typeof(SqlGuid), (o, id, col) => ReadGuid(o, id)}, + {typeof(SqlMoney), (o, id, col) => ReadMoney(o, id)}, }; } @@ -103,9 +105,10 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage /// Reads a row from the file, based on the columns provided /// /// Offset into the file where the row starts + /// Internal ID of the row to set for all cells in this row /// The columns that were encoded /// The objects from the row, ready for output to the client - public IList ReadRow(long fileOffset, IEnumerable columns) + public IList ReadRow(long fileOffset, long rowId, IEnumerable columns) { // Initialize for the loop long currentFileOffset = fileOffset; @@ -119,7 +122,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage if (column.IsSqlVariant) { // For SQL Variant columns, the type is written first in string format - FileStreamReadResult sqlVariantTypeResult = ReadString(currentFileOffset); + FileStreamReadResult sqlVariantTypeResult = ReadString(currentFileOffset, rowId); currentFileOffset += sqlVariantTypeResult.TotalLength; string sqlVariantType = (string)sqlVariantTypeResult.Value.RawObject; @@ -146,13 +149,13 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage } // Use the right read function for the type to read the data from the file - Func readFunc; + ReadMethod readFunc; if(!readMethods.TryGetValue(colType, out readFunc)) { // Treat everything else as a string readFunc = readMethods[typeof(string)]; } - FileStreamReadResult result = readFunc(currentFileOffset, column); + FileStreamReadResult result = readFunc(currentFileOffset, rowId, column); currentFileOffset += result.TotalLength; results.Add(result.Value); } @@ -183,6 +186,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage /// . /// /// Offset into the file to read from + /// Internal ID of the row to set on all cells in this row /// Function to use to convert the buffer to the target type /// /// If provided, this function will be used to determine if the value is null @@ -190,10 +194,13 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage /// Optional function to use to convert the object to a string. /// The expected type of the cell. Used to keep the code honest /// The object, a display value, and the length of the value + its length - private FileStreamReadResult ReadCellHelper(long offset, Func convertFunc, Func isNullFunc = null, Func toStringFunc = null) + private FileStreamReadResult ReadCellHelper(long offset, long rowId, + Func convertFunc, + Func isNullFunc = null, + Func toStringFunc = null) { LengthResult length = ReadLength(offset); - DbCellValue result = new DbCellValue(); + DbCellValue result = new DbCellValue {RowId = rowId}; if (isNullFunc == null ? length.ValueLength == 0 : isNullFunc(length.TotalLength)) { @@ -218,61 +225,67 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage /// Reads a short from the file at the offset provided /// /// Offset into the file to read the short from + /// Internal ID of the row that will be stored in the cell /// A short - internal FileStreamReadResult ReadInt16(long fileOffset) + internal FileStreamReadResult ReadInt16(long fileOffset, long rowId) { - return ReadCellHelper(fileOffset, length => BitConverter.ToInt16(buffer, 0)); + return ReadCellHelper(fileOffset, rowId, length => BitConverter.ToInt16(buffer, 0)); } /// /// Reads a int from the file at the offset provided /// /// Offset into the file to read the int from + /// Internal ID of the row that will be stored in the cell /// An int - internal FileStreamReadResult ReadInt32(long fileOffset) + internal FileStreamReadResult ReadInt32(long fileOffset, long rowId) { - return ReadCellHelper(fileOffset, length => BitConverter.ToInt32(buffer, 0)); + return ReadCellHelper(fileOffset, rowId, length => BitConverter.ToInt32(buffer, 0)); } /// /// Reads a long from the file at the offset provided /// /// Offset into the file to read the long from + /// Internal ID of the row that will be stored in the cell /// A long - internal FileStreamReadResult ReadInt64(long fileOffset) + internal FileStreamReadResult ReadInt64(long fileOffset, long rowId) { - return ReadCellHelper(fileOffset, length => BitConverter.ToInt64(buffer, 0)); + return ReadCellHelper(fileOffset, rowId, length => BitConverter.ToInt64(buffer, 0)); } /// /// Reads a byte from the file at the offset provided /// /// Offset into the file to read the byte from + /// Internal ID of the row that will be stored in the cell /// A byte - internal FileStreamReadResult ReadByte(long fileOffset) + internal FileStreamReadResult ReadByte(long fileOffset, long rowId) { - return ReadCellHelper(fileOffset, length => buffer[0]); + return ReadCellHelper(fileOffset, rowId, length => buffer[0]); } /// /// Reads a char from the file at the offset provided /// /// Offset into the file to read the char from + /// Internal ID of the row that will be stored in the cell /// A char - internal FileStreamReadResult ReadChar(long fileOffset) + internal FileStreamReadResult ReadChar(long fileOffset, long rowId) { - return ReadCellHelper(fileOffset, length => BitConverter.ToChar(buffer, 0)); + return ReadCellHelper(fileOffset, rowId, length => BitConverter.ToChar(buffer, 0)); } /// /// Reads a bool from the file at the offset provided /// /// Offset into the file to read the bool from + /// Internal ID of the row that will be stored in the cell /// A bool - internal FileStreamReadResult ReadBoolean(long fileOffset) + internal FileStreamReadResult ReadBoolean(long fileOffset, long rowId) { // Override the stringifier with numeric values if the user prefers that - return ReadCellHelper(fileOffset, length => buffer[0] == 0x1, + return ReadCellHelper(fileOffset, rowId, length => buffer[0] == 0x1, toStringFunc: val => executionSettings.DisplayBitAsNumber ? val ? "1" : "0" : val.ToString()); @@ -282,20 +295,22 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage /// Reads a single from the file at the offset provided /// /// Offset into the file to read the single from + /// Internal ID of the row that will be stored in the cell /// A single - internal FileStreamReadResult ReadSingle(long fileOffset) + internal FileStreamReadResult ReadSingle(long fileOffset, long rowId) { - return ReadCellHelper(fileOffset, length => BitConverter.ToSingle(buffer, 0)); + return ReadCellHelper(fileOffset, rowId, length => BitConverter.ToSingle(buffer, 0)); } /// /// Reads a double from the file at the offset provided /// /// Offset into the file to read the double from + /// Internal ID of the row that will be stored in the cell /// A double - internal FileStreamReadResult ReadDouble(long fileOffset) + internal FileStreamReadResult ReadDouble(long fileOffset, long rowId) { - return ReadCellHelper(fileOffset, length => BitConverter.ToDouble(buffer, 0)); + return ReadCellHelper(fileOffset, rowId, length => BitConverter.ToDouble(buffer, 0)); } /// @@ -303,9 +318,9 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage /// /// Offset into the file to read the SqlDecimal from /// A SqlDecimal - internal FileStreamReadResult ReadSqlDecimal(long offset) + internal FileStreamReadResult ReadSqlDecimal(long offset, long rowId) { - return ReadCellHelper(offset, length => + return ReadCellHelper(offset, rowId, length => { int[] arrInt32 = new int[(length - 3) / 4]; Buffer.BlockCopy(buffer, 3, arrInt32, 0, length - 3); @@ -318,9 +333,9 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage /// /// Offset into the file to read the decimal from /// A decimal - internal FileStreamReadResult ReadDecimal(long offset) + internal FileStreamReadResult ReadDecimal(long offset, long rowId) { - return ReadCellHelper(offset, length => + return ReadCellHelper(offset, rowId, length => { int[] arrInt32 = new int[length / 4]; Buffer.BlockCopy(buffer, 0, arrInt32, 0, length); @@ -332,11 +347,12 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage /// Reads a DateTime from the file at the offset provided /// /// Offset into the file to read the DateTime from + /// Internal ID of the row that will be stored in the cell /// Column metadata, used for determining what precision to output /// A DateTime - internal FileStreamReadResult ReadDateTime(long offset, DbColumnWrapper col) + internal FileStreamReadResult ReadDateTime(long offset, long rowId, DbColumnWrapper col) { - return ReadCellHelper(offset, length => + return ReadCellHelper(offset, rowId, length => { long ticks = BitConverter.ToInt64(buffer, 0); return new DateTime(ticks); @@ -379,12 +395,13 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage /// Reads a DateTimeOffset from the file at the offset provided /// /// Offset into the file to read the DateTimeOffset from + /// Internal ID of the row that will be stored in the cell /// A DateTimeOffset - internal FileStreamReadResult ReadDateTimeOffset(long offset) + internal FileStreamReadResult ReadDateTimeOffset(long offset, long rowId) { // DateTimeOffset is represented by DateTime.Ticks followed by TimeSpan.Ticks // both as Int64 values - return ReadCellHelper(offset, length => { + return ReadCellHelper(offset, rowId, length => { long dtTicks = BitConverter.ToInt64(buffer, 0); long dtOffset = BitConverter.ToInt64(buffer, 8); return new DateTimeOffset(new DateTime(dtTicks), new TimeSpan(dtOffset)); @@ -395,10 +412,11 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage /// Reads a TimeSpan from the file at the offset provided /// /// Offset into the file to read the TimeSpan from + /// Internal ID of the row that will be stored in the cell /// A TimeSpan - internal FileStreamReadResult ReadTimeSpan(long offset) + internal FileStreamReadResult ReadTimeSpan(long offset, long rowId) { - return ReadCellHelper(offset, length => + return ReadCellHelper(offset, rowId, length => { long ticks = BitConverter.ToInt64(buffer, 0); return new TimeSpan(ticks); @@ -409,10 +427,11 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage /// Reads a string from the file at the offset provided /// /// Offset into the file to read the string from + /// Internal ID of the row that will be stored in the cell /// A string - internal FileStreamReadResult ReadString(long offset) + internal FileStreamReadResult ReadString(long offset, long rowId) { - return ReadCellHelper(offset, length => + return ReadCellHelper(offset, rowId, length => length > 0 ? Encoding.Unicode.GetString(buffer, 0, length) : string.Empty, totalLength => totalLength == 1); @@ -422,10 +441,11 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage /// Reads bytes from the file at the offset provided /// /// Offset into the file to read the bytes from + /// Internal ID of the row that will be stored in the cell /// A byte array - internal FileStreamReadResult ReadBytes(long offset) + internal FileStreamReadResult ReadBytes(long offset, long rowId) { - return ReadCellHelper(offset, length => + return ReadCellHelper(offset, rowId, length => { byte[] output = new byte[length]; Buffer.BlockCopy(buffer, 0, output, 0, length); @@ -446,10 +466,11 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage /// Reads the bytes that make up a GUID at the offset provided /// /// Offset into the file to read the bytes from + /// Internal ID of the row that will be stored in the cell /// A guid type object - internal FileStreamReadResult ReadGuid(long offset) + internal FileStreamReadResult ReadGuid(long offset, long rowId) { - return ReadCellHelper(offset, length => + return ReadCellHelper(offset, rowId, length => { byte[] output = new byte[length]; Buffer.BlockCopy(buffer, 0, output, 0, length); @@ -462,10 +483,11 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage /// into a /// /// Offset into the file to read the value + /// Internal ID of the row that will be stored in the cell /// A sql money type object - internal FileStreamReadResult ReadMoney(long offset) + internal FileStreamReadResult ReadMoney(long offset, long rowId) { - return ReadCellHelper(offset, length => + return ReadCellHelper(offset, rowId, length => { int[] arrInt32 = new int[length / 4]; Buffer.BlockCopy(buffer, 0, arrInt32, 0, length); diff --git a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/ResultSet.cs b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/ResultSet.cs index 2c7747d1..8bd2681e 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/ResultSet.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/ResultSet.cs @@ -214,7 +214,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution using (IFileStreamReader fileStreamReader = fileStreamFactory.GetReader(outputFileName)) { - return fileStreamReader.ReadRow(fileOffsets[rowId], Columns); + return fileStreamReader.ReadRow(fileOffsets[rowId], rowId, Columns); } } @@ -255,13 +255,14 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution { // Iterate over all the rows and process them into a list of string builders // ReSharper disable once AccessToDisposedClosure The lambda is used immediately in string.Join call - IEnumerable rowValues = fileOffsets.Select(rowOffset => fileStreamReader.ReadRow(rowOffset, Columns)[0].DisplayValue); + IEnumerable rowValues = fileOffsets.Select(rowOffset => fileStreamReader.ReadRow(rowOffset, 0, Columns)[0].DisplayValue); string singleString = string.Join(string.Empty, rowValues); DbCellValue cellValue = new DbCellValue { DisplayValue = singleString, IsNull = false, - RawObject = singleString + RawObject = singleString, + RowId = 0 }; rows = new[] { new[] { cellValue } }; } @@ -272,7 +273,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution // Iterate over the rows we need and process them into output // ReSharper disable once AccessToDisposedClosure The lambda is used immediately in .ToArray call - rows = rowOffsets.Select(rowOffset => fileStreamReader.ReadRow(rowOffset, Columns).ToArray()).ToArray(); + rows = rowOffsets.Select((offset, id) => fileStreamReader.ReadRow(offset, id, Columns).ToArray()).ToArray(); } } // Retrieve the subset of the results as per the request @@ -313,7 +314,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution using (IFileStreamReader fileStreamReader = fileStreamFactory.GetReader(outputFileName)) { // Determine the format and get the first col/row of XML - content = fileStreamReader.ReadRow(0, Columns)[0].DisplayValue; + content = fileStreamReader.ReadRow(0, 0, Columns)[0].DisplayValue; if (specialAction.ExpectYukonXMLShowPlan) { @@ -482,7 +483,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution // Iterate over the rows that are in the selected row set for (long i = rowStartIndex; i < rowEndIndex; ++i) { - var row = fileReader.ReadRow(fileOffsets[i], Columns); + var row = fileReader.ReadRow(fileOffsets[i], i, Columns); fileWriter.WriteRow(row, Columns); } if (successHandler != null) diff --git a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/QueryExecution/DataStorage/ServiceBufferFileStreamReaderWriterTests.cs b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/QueryExecution/DataStorage/ServiceBufferFileStreamReaderWriterTests.cs index 526220da..b71cf285 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/QueryExecution/DataStorage/ServiceBufferFileStreamReaderWriterTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/QueryExecution/DataStorage/ServiceBufferFileStreamReaderWriterTests.cs @@ -116,12 +116,13 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage [SuppressMessage("ReSharper", "UnusedParameter.Local")] private static string VerifyReadWrite(int valueLength, T value, Func writeFunc, - Func readFunc, + Func readFunc, QueryExecutionSettings overrideSettings = null) { // Setup: Create a mock file stream byte[] storage = new byte[8192]; overrideSettings = overrideSettings ?? new QueryExecutionSettings(); + const long rowId = 100; // If: // ... I write a type T to the writer @@ -135,7 +136,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage FileStreamReadResult outValue; using (ServiceBufferFileStreamReader reader = new ServiceBufferFileStreamReader(new MemoryStream(storage), overrideSettings)) { - outValue = readFunc(reader); + outValue = readFunc(reader, rowId); } // Then: @@ -143,6 +144,9 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage Assert.Equal(valueLength, outValue.TotalLength); Assert.NotNull(outValue.Value); + // ... The id we set should be stored in the returned db cell value + Assert.Equal(rowId, outValue.Value.RowId); + return outValue.Value.DisplayValue; } @@ -154,7 +158,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage [InlineData(short.MinValue)] // Negative two byte number public void Int16(short value) { - VerifyReadWrite(sizeof(short) + 1, value, (writer, val) => writer.WriteInt16(val), reader => reader.ReadInt16(0)); + VerifyReadWrite(sizeof(short) + 1, value, (writer, val) => writer.WriteInt16(val), (reader, rowId) => reader.ReadInt16(0, rowId)); } [Theory] @@ -167,7 +171,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage [InlineData(int.MinValue)] // Negative four byte number public void Int32(int value) { - VerifyReadWrite(sizeof(int) + 1, value, (writer, val) => writer.WriteInt32(val), reader => reader.ReadInt32(0)); + VerifyReadWrite(sizeof(int) + 1, value, (writer, val) => writer.WriteInt32(val), (reader, rowId) => reader.ReadInt32(0, rowId)); } [Theory] @@ -182,7 +186,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage [InlineData(long.MinValue)] // Negative eight byte number public void Int64(long value) { - VerifyReadWrite(sizeof(long) + 1, value, (writer, val) => writer.WriteInt64(val), reader => reader.ReadInt64(0)); + VerifyReadWrite(sizeof(long) + 1, value, (writer, val) => writer.WriteInt64(val), (reader, rowId) => reader.ReadInt64(0, rowId)); } [Theory] @@ -190,7 +194,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage [InlineData(10)] public void Byte(byte value) { - VerifyReadWrite(sizeof(byte) + 1, value, (writer, val) => writer.WriteByte(val), reader => reader.ReadByte(0)); + VerifyReadWrite(sizeof(byte) + 1, value, (writer, val) => writer.WriteByte(val), (reader, rowId) => reader.ReadByte(0, rowId)); } [Theory] @@ -199,7 +203,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage [InlineData((char)0x9152)] // Test something in the UTF-16 space public void Char(char value) { - VerifyReadWrite(sizeof(char) + 1, value, (writer, val) => writer.WriteChar(val), reader => reader.ReadChar(0)); + VerifyReadWrite(sizeof(char) + 1, value, (writer, val) => writer.WriteChar(val), (reader, rowId) => reader.ReadChar(0, rowId)); } [Theory] @@ -211,7 +215,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage { string displayValue = VerifyReadWrite(sizeof(bool) + 1, value, (writer, val) => writer.WriteBoolean(val), - reader => reader.ReadBoolean(0), + (reader, rowId) => reader.ReadBoolean(0, rowId), new QueryExecutionSettings {DisplayBitAsNumber = preferNumeric} ); @@ -238,7 +242,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage [InlineData(float.NegativeInfinity)] public void Single(float value) { - VerifyReadWrite(sizeof(float) + 1, value, (writer, val) => writer.WriteSingle(val), reader => reader.ReadSingle(0)); + VerifyReadWrite(sizeof(float) + 1, value, (writer, val) => writer.WriteSingle(val), (reader, rowId) => reader.ReadSingle(0, rowId)); } [Theory] @@ -255,7 +259,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage [InlineData(double.MaxValue)] public void Double(double value) { - VerifyReadWrite(sizeof(double) + 1, value, (writer, val) => writer.WriteDouble(val), reader => reader.ReadDouble(0)); + VerifyReadWrite(sizeof(double) + 1, value, (writer, val) => writer.WriteDouble(val), (reader, rowId) => reader.ReadDouble(0, rowId)); } [Fact] @@ -270,7 +274,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage foreach (SqlDecimal value in testValues) { int valueLength = 4 + value.BinData.Length; - VerifyReadWrite(valueLength, value, (writer, val) => writer.WriteSqlDecimal(val), reader => reader.ReadSqlDecimal(0)); + VerifyReadWrite(valueLength, value, (writer, val) => writer.WriteSqlDecimal(val), (reader, rowId) => reader.ReadSqlDecimal(0, rowId)); } } @@ -287,7 +291,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage foreach (decimal value in testValues) { int valueLength = decimal.GetBits(value).Length*4 + 1; - VerifyReadWrite(valueLength, value, (writer, val) => writer.WriteDecimal(val), reader => reader.ReadDecimal(0)); + VerifyReadWrite(valueLength, value, (writer, val) => writer.WriteDecimal(val), (reader, rowId) => reader.ReadDecimal(0, rowId)); } } @@ -306,7 +310,8 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage foreach (DateTime value in testValues) { - string displayValue = VerifyReadWrite(sizeof(long) + 1, value, (writer, val) => writer.WriteDateTime(val), reader => reader.ReadDateTime(0, col)); + string displayValue = VerifyReadWrite(sizeof(long) + 1, value, (writer, val) => writer.WriteDateTime(val), + (reader, rowId) => reader.ReadDateTime(0, rowId, col)); // Make sure the display value does not have a time string Assert.True(Regex.IsMatch(displayValue, @"^[\d]{4}-[\d]{2}-[\d]{2}$")); @@ -328,7 +333,8 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage foreach (DateTime value in testValues) { - string displayValue = VerifyReadWrite(sizeof(long) + 1, value, (writer, val) => writer.WriteDateTime(val), reader => reader.ReadDateTime(0, col)); + string displayValue = VerifyReadWrite(sizeof(long) + 1, value, (writer, val) => writer.WriteDateTime(val), + (reader, rowId) => reader.ReadDateTime(0, rowId, col)); // Make sure the display value has a time string with 3 milliseconds Assert.True(Regex.IsMatch(displayValue, @"^[\d]{4}-[\d]{2}-[\d]{2} [\d]{2}:[\d]{2}:[\d]{2}\.[\d]{3}$")); @@ -361,7 +367,8 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage foreach (DateTime value in testValues) { - string displayValue = VerifyReadWrite(sizeof(long) + 1, value, (writer, val) => writer.WriteDateTime(val), reader => reader.ReadDateTime(0, col)); + string displayValue = VerifyReadWrite(sizeof(long) + 1, value, (writer, val) => writer.WriteDateTime(val), + (reader, rowId) => reader.ReadDateTime(0, rowId, col)); // Make sure the display value has a time string with variable number of milliseconds Assert.True(Regex.IsMatch(displayValue, @"^[\d]{4}-[\d]{2}-[\d]{2} [\d]{2}:[\d]{2}:[\d]{2}")); @@ -387,7 +394,8 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage foreach (DateTime value in testValues) { - string displayValue = VerifyReadWrite(sizeof(long) + 1, value, (writer, val) => writer.WriteDateTime(val), reader => reader.ReadDateTime(0, col)); + string displayValue = VerifyReadWrite(sizeof(long) + 1, value, (writer, val) => writer.WriteDateTime(val), + (reader, rowId) => reader.ReadDateTime(0, rowId, col)); // Make sure the display value has a time string with 0 milliseconds Assert.True(Regex.IsMatch(displayValue, @"^[\d]{4}-[\d]{2}-[\d]{2} [\d]{2}:[\d]{2}:[\d]{2}$")); @@ -409,7 +417,8 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage foreach (DateTime value in testValues) { - string displayValue = VerifyReadWrite(sizeof(long) + 1, value, (writer, val) => writer.WriteDateTime(val), reader => reader.ReadDateTime(0, col)); + string displayValue = VerifyReadWrite(sizeof(long) + 1, value, (writer, val) => writer.WriteDateTime(val), + (reader, rowId) => reader.ReadDateTime(0, rowId, col)); // Make sure the display value has a time string with 7 milliseconds Assert.True(Regex.IsMatch(displayValue, @"^[\d]{4}-[\d]{2}-[\d]{2} [\d]{2}:[\d]{2}:[\d]{2}\.[\d]{7}$")); @@ -428,7 +437,8 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage }; foreach (DateTimeOffset value in testValues) { - VerifyReadWrite(sizeof(long)*2 + 1, value, (writer, val) => writer.WriteDateTimeOffset(val), reader => reader.ReadDateTimeOffset(0)); + VerifyReadWrite(sizeof(long)*2 + 1, value, (writer, val) => writer.WriteDateTimeOffset(val), + (reader, rowId) => reader.ReadDateTimeOffset(0, rowId)); } } @@ -443,7 +453,8 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage }; foreach (TimeSpan value in testValues) { - VerifyReadWrite(sizeof(long) + 1, value, (writer, val) => writer.WriteTimeSpan(val), reader => reader.ReadTimeSpan(0)); + VerifyReadWrite(sizeof(long) + 1, value, (writer, val) => writer.WriteTimeSpan(val), + (reader, rowId) => reader.ReadTimeSpan(0, rowId)); } } @@ -481,7 +492,8 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage } string value = sb.ToString(); int lengthLength = length == 0 || length > 255 ? 5 : 1; - VerifyReadWrite(sizeof(char)*length + lengthLength, value, (writer, val) => writer.WriteString(value), reader => reader.ReadString(0)); + VerifyReadWrite(sizeof(char)*length + lengthLength, value, (writer, val) => writer.WriteString(value), + (reader, rowId) => reader.ReadString(0, rowId)); } [Fact] @@ -519,7 +531,8 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage byte[] value = sb.ToArray(); int lengthLength = length == 0 || length > 255 ? 5 : 1; int valueLength = sizeof(byte)*length + lengthLength; - VerifyReadWrite(valueLength, value, (writer, val) => writer.WriteBytes(value), reader => reader.ReadBytes(0)); + VerifyReadWrite(valueLength, value, (writer, val) => writer.WriteBytes(value), + (reader, rowId) => reader.ReadBytes(0, rowId)); } [Fact] @@ -534,7 +547,8 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage }; foreach (Guid guid in guids) { - VerifyReadWrite(guid.ToByteArray().Length + 1, new SqlGuid(guid), (writer, val) => writer.WriteGuid(guid), reader => reader.ReadGuid(0)); + VerifyReadWrite(guid.ToByteArray().Length + 1, new SqlGuid(guid), (writer, val) => writer.WriteGuid(guid), + (reader, rowId) => reader.ReadGuid(0, rowId)); } } @@ -549,7 +563,8 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage }; foreach (SqlMoney money in monies) { - VerifyReadWrite(sizeof(decimal) + 1, money, (writer, val) => writer.WriteMoney(money), reader => reader.ReadMoney(0)); + VerifyReadWrite(sizeof(decimal) + 1, money, (writer, val) => writer.WriteMoney(money), + (reader, rowId) => reader.ReadMoney(0, rowId)); } } }