Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / Data / Microsoft / SqlServer / Server / sqlpipe.cs / 1305376 / sqlpipe.cs
//------------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// [....]
// [....]
// daltodov
//-----------------------------------------------------------------------------
namespace Microsoft.SqlServer.Server {
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Data.Sql;
using System.Data.Common;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.Diagnostics;
// SqlPipe
// Abstraction of TDS data/message channel exposed to user.
public sealed class SqlPipe {
SmiContext _smiContext;
SmiRecordBuffer _recordBufferSent; // Last recordBuffer sent to pipe (for push model SendEnd).
SqlMetaData[] _metaDataSent; // Metadata of last resultset started (for push model). Overloaded to indicate if push started or not (non-null/null)
SmiEventSink_Default _eventSink; // Eventsink to use when calling SmiContext entrypoints
bool _isBusy; // Is this pipe currently handling an operation?
bool _hadErrorInResultSet; // true if an exception was thrown from within various bodies; used to control cleanup during SendResultsEnd
internal SqlPipe( SmiContext smiContext ) {
_smiContext = smiContext;
_eventSink = new SmiEventSink_Default();
}
//
// Public methods
//
public void ExecuteAndSend( SqlCommand command ) {
SetPipeBusy( );
try {
EnsureNormalSendValid( "ExecuteAndSend" );
if ( null == command ) {
throw ADP.ArgumentNull( "command" );
}
SqlConnection connection = command.Connection;
// if the command doesn't have a connection set up, try to set one up on it's behalf
if ( null == connection ) {
using ( SqlConnection newConnection = new SqlConnection( "Context Connection=true" ) ) {
newConnection.Open( );
// use try-finally to restore command's connection property to it's original state
try {
command.Connection = newConnection;
command.ExecuteToPipe( _smiContext );
}
finally {
command.Connection = null;
}
}
}
else {
// validate connection state
if ( ConnectionState.Open != connection.State ) {
throw ADP.ClosedConnectionError();
}
// validate connection is current scope's connection
SqlInternalConnectionSmi internalConnection = connection.InnerConnection as SqlInternalConnectionSmi;
if ( null == internalConnection ) {
throw SQL.SqlPipeCommandHookedUpToNonContextConnection( );
}
command.ExecuteToPipe( _smiContext );
}
}
finally {
ClearPipeBusy( );
}
}
// Equivalent to TSQL PRINT statement -- sends an info-only message.
public void Send( string message ) {
ADP.CheckArgumentNull(message, "message");
if ( SmiMetaData.MaxUnicodeCharacters < message.Length ) {
throw SQL.SqlPipeMessageTooLong( message.Length );
}
SetPipeBusy( );
try {
EnsureNormalSendValid( "Send" );
_smiContext.SendMessageToPipe( message, _eventSink );
// Handle any errors that are reported.
_eventSink.ProcessMessagesAndThrow();
}
finally {
ClearPipeBusy( );
}
}
// Send results from SqlDataReader
public void Send( SqlDataReader reader ) {
ADP.CheckArgumentNull(reader, "reader");
SetPipeBusy( );
try {
EnsureNormalSendValid( "Send" );
do {
SmiExtendedMetaData[] columnMetaData = reader.GetInternalSmiMetaData();
if (null != columnMetaData && 0 != columnMetaData.Length) { // SQLBUDT #340528 -- don't send empty results.
using ( SmiRecordBuffer recordBuffer = _smiContext.CreateRecordBuffer(columnMetaData, _eventSink) ) {
_eventSink.ProcessMessagesAndThrow(); // Handle any errors that are reported.
_smiContext.SendResultsStartToPipe( recordBuffer, _eventSink );
_eventSink.ProcessMessagesAndThrow(); // Handle any errors that are reported.
try {
while( reader.Read( ) ) {
if (SmiContextFactory.Instance.NegotiatedSmiVersion >= SmiContextFactory.KatmaiVersion) {
ValueUtilsSmi.FillCompatibleSettersFromReader(_eventSink, recordBuffer, new List(columnMetaData), reader);
}
else {
ValueUtilsSmi.FillCompatibleITypedSettersFromReader(_eventSink, recordBuffer, columnMetaData, reader);
}
_smiContext.SendResultsRowToPipe( recordBuffer, _eventSink );
_eventSink.ProcessMessagesAndThrow(); // Handle any errors that are reported.
}
}
finally {
_smiContext.SendResultsEndToPipe( recordBuffer, _eventSink );
_eventSink.ProcessMessagesAndThrow(); // Handle any errors that are reported.
}
}
}
}
while ( reader.NextResult( ) );
}
finally {
ClearPipeBusy( );
}
}
public void Send( SqlDataRecord record ) {
ADP.CheckArgumentNull(record, "record");
SetPipeBusy( );
try {
EnsureNormalSendValid( "Send" );
if (0 != record.FieldCount) { // SQLBUDT #340564 -- don't send empty records.
SmiRecordBuffer recordBuffer;
if (record.RecordContext == _smiContext) {
recordBuffer = record.RecordBuffer;
} else { // SendResultsRowToPipe() only takes a RecordBuffer created by an SmiContext
SmiExtendedMetaData[] columnMetaData = record.InternalGetSmiMetaData();
recordBuffer = _smiContext.CreateRecordBuffer(columnMetaData, _eventSink);
if (SmiContextFactory.Instance.NegotiatedSmiVersion >= SmiContextFactory.KatmaiVersion) {
ValueUtilsSmi.FillCompatibleSettersFromRecord(_eventSink, recordBuffer, columnMetaData, record, null /* no default values */);
}
else {
ValueUtilsSmi.FillCompatibleITypedSettersFromRecord(_eventSink, recordBuffer, columnMetaData, record);
}
}
_smiContext.SendResultsStartToPipe( recordBuffer, _eventSink );
_eventSink.ProcessMessagesAndThrow(); // Handle any errors that are reported.
// If SendResultsStartToPipe succeeded, then SendResultsEndToPipe must be called.
try {
_smiContext.SendResultsRowToPipe( recordBuffer, _eventSink );
_eventSink.ProcessMessagesAndThrow(); // Handle any errors that are reported.
}
finally {
_smiContext.SendResultsEndToPipe( recordBuffer, _eventSink );
_eventSink.ProcessMessagesAndThrow(); // Handle any errors that are reported.
}
}
}
finally {
ClearPipeBusy( );
}
}
public void SendResultsStart( SqlDataRecord record ) {
ADP.CheckArgumentNull(record, "record");
SetPipeBusy( );
try {
EnsureNormalSendValid( "SendResultsStart" );
SmiRecordBuffer recordBuffer = record.RecordBuffer;
if (record.RecordContext == _smiContext) {
recordBuffer = record.RecordBuffer;
} else {
recordBuffer = _smiContext.CreateRecordBuffer(record.InternalGetSmiMetaData(), _eventSink); // Only MetaData needed for sending start
}
_smiContext.SendResultsStartToPipe( recordBuffer, _eventSink );
// Handle any errors that are reported.
_eventSink.ProcessMessagesAndThrow();
// remember sent buffer info so it can be used in send row/end.
_recordBufferSent = recordBuffer;
_metaDataSent = record.InternalGetMetaData();
}
finally {
ClearPipeBusy( );
}
}
public void SendResultsRow( SqlDataRecord record ) {
ADP.CheckArgumentNull(record, "record");
SetPipeBusy( );
try {
EnsureResultStarted( "SendResultsRow" );
if ( _hadErrorInResultSet ) {
throw SQL.SqlPipeErrorRequiresSendEnd();
}
// Assume error state unless cleared below
_hadErrorInResultSet = true;
SmiRecordBuffer recordBuffer;
if (record.RecordContext == _smiContext) {
recordBuffer = record.RecordBuffer;
} else {
SmiExtendedMetaData[] columnMetaData = record.InternalGetSmiMetaData();
recordBuffer = _smiContext.CreateRecordBuffer(columnMetaData, _eventSink);
if (SmiContextFactory.Instance.NegotiatedSmiVersion >= SmiContextFactory.KatmaiVersion) {
ValueUtilsSmi.FillCompatibleSettersFromRecord(_eventSink, recordBuffer, columnMetaData, record, null /* no default values */);
}
else {
ValueUtilsSmi.FillCompatibleITypedSettersFromRecord(_eventSink, recordBuffer, columnMetaData, record);
}
}
_smiContext.SendResultsRowToPipe( recordBuffer, _eventSink );
// Handle any errors that are reported.
_eventSink.ProcessMessagesAndThrow();
// We successfully traversed the send, clear error state
_hadErrorInResultSet = false;
}
finally {
ClearPipeBusy( );
}
}
public void SendResultsEnd( ) {
SetPipeBusy( );
try {
EnsureResultStarted( "SendResultsEnd" );
_smiContext.SendResultsEndToPipe( _recordBufferSent, _eventSink );
// Once end called down to native code, assume end of resultset
_metaDataSent = null;
_recordBufferSent = null;
_hadErrorInResultSet = false;
// Handle any errors that are reported.
_eventSink.ProcessMessagesAndThrow();
}
finally {
ClearPipeBusy( );
}
}
// This isn't speced, but it may not be a bad idea to implement...
public bool IsSendingResults {
get {
return null != _metaDataSent;
}
}
internal void OnOutOfScope( ) {
_metaDataSent = null;
_recordBufferSent = null;
_hadErrorInResultSet = false;
_isBusy = false;
}
// Pipe busy status.
// Ensures user code cannot call any APIs while a send is in progress.
//
// Public methods must call this method before sending anything to the unmanaged pipe.
// Once busy status is set, it must clear before returning from the calling method
// ( i.e. clear should be in a finally block).
private void SetPipeBusy( ) {
if ( _isBusy ) {
throw SQL.SqlPipeIsBusy( );
}
_isBusy = true;
}
// Clear the pipe's busy status.
private void ClearPipeBusy( ) {
_isBusy = false;
}
//
// State validation
// One of the Ensure* validation methods should appear at the top of every public method
//
// Default validation method
// Ensures Pipe is not currently transmitting a push-model resultset
private void EnsureNormalSendValid( string methodName ) {
if ( IsSendingResults ) {
throw SQL.SqlPipeAlreadyHasAnOpenResultSet( methodName );
}
}
private void EnsureResultStarted( string methodName ) {
if ( !IsSendingResults ) {
throw SQL.SqlPipeDoesNotHaveAnOpenResultSet( methodName );
}
}
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- EventBuilder.cs
- Unit.cs
- CngKey.cs
- BitmapSource.cs
- StorageInfo.cs
- AutoCompleteStringCollection.cs
- MimeWriter.cs
- ProxyWebPartManager.cs
- EventLogPermissionHolder.cs
- ProcessModuleDesigner.cs
- CollectionConverter.cs
- ContextMenuStrip.cs
- Attachment.cs
- TypedAsyncResult.cs
- XmlSchemaAttributeGroup.cs
- OrderedEnumerableRowCollection.cs
- CacheMemory.cs
- PkcsMisc.cs
- RightsManagementEncryptedStream.cs
- XmlComplianceUtil.cs
- DataSysAttribute.cs
- sqlpipe.cs
- MultipartIdentifier.cs
- SBCSCodePageEncoding.cs
- ADMembershipProvider.cs
- CallbackCorrelationInitializer.cs
- GPPOINTF.cs
- Pair.cs
- UnknownWrapper.cs
- BatchParser.cs
- XmlWriterSettings.cs
- OdbcTransaction.cs
- DataGridViewColumnEventArgs.cs
- DataControlCommands.cs
- ColorAnimationUsingKeyFrames.cs
- Blend.cs
- EncoderFallback.cs
- XmlAttributeCollection.cs
- EventItfInfo.cs
- PolygonHotSpot.cs
- BehaviorEditorPart.cs
- FilteredAttributeCollection.cs
- SchemaTableOptionalColumn.cs
- InheritanceRules.cs
- PreparingEnlistment.cs
- CodeDirectiveCollection.cs
- DetailsViewPagerRow.cs
- SecurityResources.cs
- FloaterParaClient.cs
- WS2007FederationHttpBindingElement.cs
- CaseCqlBlock.cs
- ParentUndoUnit.cs
- IntersectQueryOperator.cs
- OrderedDictionaryStateHelper.cs
- SystemWebSectionGroup.cs
- BinHexEncoder.cs
- WebPartEditorOkVerb.cs
- SafePEFileHandle.cs
- RelationshipConstraintValidator.cs
- Instrumentation.cs
- XmlSchemaSimpleContentRestriction.cs
- DataServiceClientException.cs
- OpacityConverter.cs
- Variant.cs
- GroupQuery.cs
- WindowsListView.cs
- AmbientLight.cs
- CompilerScopeManager.cs
- PropertyManager.cs
- Stacktrace.cs
- FormViewDeleteEventArgs.cs
- Button.cs
- HashCoreRequest.cs
- DefaultParameterValueAttribute.cs
- FormsAuthenticationUserCollection.cs
- EventTrigger.cs
- TableLayoutPanel.cs
- ApplicationTrust.cs
- FilteredReadOnlyMetadataCollection.cs
- MemberInfoSerializationHolder.cs
- SplayTreeNode.cs
- EntityKeyElement.cs
- DataSourceXmlElementAttribute.cs
- DefaultEvaluationContext.cs
- ItemContainerPattern.cs
- SerTrace.cs
- EncryptRequest.cs
- NamespaceList.cs
- DataGridTableCollection.cs
- ThemeConfigurationDialog.cs
- Graphics.cs
- EventLogPropertySelector.cs
- TraceLevelHelper.cs
- ComponentRenameEvent.cs
- BinaryMessageEncodingElement.cs
- RenderOptions.cs
- XmlILOptimizerVisitor.cs
- SQLBytesStorage.cs
- BlockExpression.cs
- HtmlTitle.cs