public void SqlStream_ExecuteNonQuery_Enumerates_Entire_Stream() { int actual = 0; int expected = 100; var connection = new Mock<ISqlStreamConnection>(); connection.Setup(c => c.ExecuteNonQuery(It.IsAny<SqlCommand>())).Callback<SqlCommand>((cmd) => { var stream = cmd.Parameters["@stream"].Value as SqlStructuredParameterWrapper<StreamSchema>; Assert.IsNotNull(stream, "@stream parameter cannot be null."); foreach (var item in stream) actual++; }); using (SqlStream<StreamSchema> target = new SqlStream<StreamSchema>(connection.Object, SqlStreamBehavior.CloseConnection, 10)) { target.Parameters.Add("@userid", SqlDbType.Int).Value = 1; target.Parameters.AddStructured<StreamSchema>("@stream", "dbo.StreamUDT", target) .Map(src => src.Id, "Id", SqlDbType.Int) .Map(src => src.ProductName, "ProductName", SqlDbType.VarChar, 255) .Map(src => Convert.ToDecimal(src.Price), "Price", SqlDbType.Decimal, 9, 3); for (int i = 0; i < expected; i++) { target.Write(new StreamSchema { Id = i, ProductName = String.Format("Product {0}", i), Price = (i + 1.0) - 0.01 }); //simulate I/O Thread.Sleep(3); } } Assert.AreEqual(expected, actual, "Data wasn't streamed."); }
public long GetChars(long dataIndex, char[] buffer, int bufferIndex, int length) { if (_xmlReader == null) { SqlStream sqlStream = new SqlStream(_columnOrdinal, _reader, true /* addByteOrderMark */, false /* processAllRows*/, false /*advanceReader*/); _xmlReader = sqlStream.ToXmlReader(); _strWriter = new StringWriter((System.IFormatProvider)null); XmlWriterSettings writerSettings = new XmlWriterSettings(); writerSettings.CloseOutput = true; // close the memory stream when done writerSettings.ConformanceLevel = ConformanceLevel.Fragment; _xmlWriter = XmlWriter.Create(_strWriter, writerSettings); } int charsToSkip = 0; int cnt = 0; if (dataIndex < _charsRemoved) { throw ADP.NonSeqByteAccess(dataIndex, _charsRemoved, ADP.GetChars); } else if (dataIndex > _charsRemoved) { charsToSkip = (int)(dataIndex - _charsRemoved); } // If buffer parameter is null, we have to return -1 since there is no way for us to know the // total size up front without reading and converting the XML. if (buffer == null) { return (long)(-1); } StringBuilder strBldr = _strWriter.GetStringBuilder(); while (!_xmlReader.EOF) { if (strBldr.Length >= (length + charsToSkip)) { break; } // Can't call _xmlWriter.WriteNode here, since it reads all of the data in before returning the first char. // Do own implementation of WriteNode instead that reads just enough data to return the required number of chars //_xmlWriter.WriteNode(_xmlReader, true); // _xmlWriter.Flush(); WriteXmlElement(); if (charsToSkip > 0) { // Aggressively remove the characters we want to skip to avoid growing StringBuilder size too much cnt = strBldr.Length < charsToSkip ? strBldr.Length : charsToSkip; strBldr.Remove(0, cnt); charsToSkip -= cnt; _charsRemoved += (long)cnt; } } if (charsToSkip > 0) { cnt = strBldr.Length < charsToSkip ? strBldr.Length : charsToSkip; strBldr.Remove(0, cnt); charsToSkip -= cnt; _charsRemoved += (long)cnt; } if (strBldr.Length == 0) { return 0; } // At this point charsToSkip must be 0 Debug.Assert(charsToSkip == 0); cnt = strBldr.Length < length ? strBldr.Length : length; for (int i = 0; i < cnt; i++) { buffer[bufferIndex + i] = strBldr[i]; } // Remove the characters we have already returned strBldr.Remove(0, cnt); _charsRemoved += (long)cnt; return (long)cnt; }
private XmlReader CompleteXmlReader(SqlDataReader ds) { XmlReader reader = null; SmiExtendedMetaData[] internalSmiMetaData = ds.GetInternalSmiMetaData(); if (((internalSmiMetaData != null) && (internalSmiMetaData.Length == 1)) && (((internalSmiMetaData[0].SqlDbType == SqlDbType.NText) || (internalSmiMetaData[0].SqlDbType == SqlDbType.NVarChar)) || (internalSmiMetaData[0].SqlDbType == SqlDbType.Xml))) { try { reader = new SqlStream(ds, true, internalSmiMetaData[0].SqlDbType != SqlDbType.Xml).ToXmlReader(); } catch (Exception exception) { if (ADP.IsCatchableExceptionType(exception)) { ds.Close(); } throw; } } if (reader == null) { ds.Close(); throw SQL.NonXmlResult(); } return reader; }
public long GetChars(long dataIndex, char[] buffer, int bufferIndex, int length) { if (_xmlReader == null) { SqlStream sqlStream = new SqlStream(_columnOrdinal, _reader, true /* addByteOrderMark */, false /* processAllRows*/, false /*advanceReader*/); _xmlReader = sqlStream.ToXmlReader(); _strWriter = new StringWriter((System.IFormatProvider)null); XmlWriterSettings writerSettings = new XmlWriterSettings(); writerSettings.CloseOutput = true; // close the memory stream when done writerSettings.ConformanceLevel = ConformanceLevel.Fragment; _xmlWriter = XmlWriter.Create(_strWriter, writerSettings); } int charsToSkip = 0; int cnt = 0; if (dataIndex < _charsRemoved) { throw ADP.NonSeqByteAccess(dataIndex, _charsRemoved, nameof(GetChars)); } else if (dataIndex > _charsRemoved) { charsToSkip = (int)(dataIndex - _charsRemoved); } // If buffer parameter is null, we have to return -1 since there is no way for us to know the // total size up front without reading and converting the XML. if (buffer == null) { return((long)(-1)); } StringBuilder strBldr = _strWriter.GetStringBuilder(); while (!_xmlReader.EOF) { if (strBldr.Length >= (length + charsToSkip)) { break; } // Can't call _xmlWriter.WriteNode here, since it reads all of the data in before returning the first char. // Do own implementation of WriteNode instead that reads just enough data to return the required number of chars //_xmlWriter.WriteNode(_xmlReader, true); // _xmlWriter.Flush(); WriteXmlElement(); if (charsToSkip > 0) { // Aggressively remove the characters we want to skip to avoid growing StringBuilder size too much cnt = strBldr.Length < charsToSkip ? strBldr.Length : charsToSkip; strBldr.Remove(0, cnt); charsToSkip -= cnt; _charsRemoved += (long)cnt; } } if (charsToSkip > 0) { cnt = strBldr.Length < charsToSkip ? strBldr.Length : charsToSkip; strBldr.Remove(0, cnt); charsToSkip -= cnt; _charsRemoved += (long)cnt; } if (strBldr.Length == 0) { return(0); } // At this point charsToSkip must be 0 Debug.Assert(charsToSkip == 0); cnt = strBldr.Length < length ? strBldr.Length : length; for (int i = 0; i < cnt; i++) { buffer[bufferIndex + i] = strBldr[i]; } // Remove the characters we have already returned strBldr.Remove(0, cnt); _charsRemoved += (long)cnt; return((long)cnt); }
public void SqlStream_Integration_Test_With_Output_Parameter() { int actual = 0; int expected = 100; using (SqlStream<StreamSchema> target = new SqlStream<StreamSchema>(new SqlStreamConnection("Server=(local);Database=tempdb;Trusted_Connection=Yes;"), SqlStreamBehavior.CloseConnection, 10)) { target.StoredProcedureName = "dbo.TVPTestProc"; target.Parameters.AddStructured<StreamSchema>("@stream", "dbo.StreamSchema", target) .Map(src => src.Id, "Id", SqlDbType.Int) .Map(src => src.ProductName, "ProductName", SqlDbType.VarChar, 255) .Map(src => Convert.ToDecimal(src.Price), "Price", SqlDbType.Decimal, 9, 3); target.Parameters.Add("@userid", SqlDbType.Int).Value = 1; var output = target.Parameters.Add("@resultCount", SqlDbType.Int); output.Direction = ParameterDirection.InputOutput; output.Value = 0; for (int i = 0; i < expected; i++) { target.Write(new StreamSchema { Id = i, ProductName = String.Format("Product {0}", i), Price = (i + 1.0) - 0.01 }); } // need to wait for Close() or Dispose() before checking output parameters target.Close(); actual = Convert.ToInt32(output.Value); } Assert.AreEqual(expected, actual, "Data wasn't streamed."); }