--- title: "Performing Asynchronous Operations | Microsoft Docs" ms.custom: "" ms.date: "03/14/2017" ms.prod: sql ms.reviewer: "" ms.technology: native-client ms.topic: "reference" helpviewer_keywords: - "initialization [SQL Server Native Client]" - "database connections [SQL Server Native Client]" - "data access [SQL Server Native Client], asynchronous operations" - "connections [SQL Server Native Client]" - "asynchronous operations [SQL Server Native Client]" - "rowsets [SQL Server], initializing" - "SQLNCLI, asynchronous operations" - "SQL Server Native Client, asynchronous operations" ms.assetid: 8fbd84b4-69cb-4708-9f0f-bbdf69029bcc author: markingmyname ms.author: maghan monikerRange: ">=aps-pdw-2016||=azuresqldb-current||=azure-sqldw-latest||>=sql-server-2016||=sqlallproducts-allversions||>=sql-server-linux-2017||=azuresqldb-mi-current" --- # Performing Asynchronous Operations [!INCLUDE[appliesto-ss-asdb-asdw-pdw-md](../../../includes/appliesto-ss-asdb-asdw-pdw-md.md)] [!INCLUDE[ssNoVersion](../../../includes/ssnoversion-md.md)] allows applications to perform asynchronous database operations. Asynchronous processing enables methods to return immediately without blocking on the calling thread. This allows much of the power and flexibility of multithreading, without requiring the developer to explicitly create threads or handle synchronization. Applications request asynchronous processing when initializing a database connection, or when initializing the result from the execution of a command. ## Opening and Closing a Database Connection When using the [!INCLUDE[ssNoVersion](../../../includes/ssnoversion-md.md)] Native Client OLE DB provider, applications designed to initialize a data source object asynchronously can set the DBPROPVAL_ASYNCH_INITIALIZE bit in the DBPROP_INIT_ASYNCH property prior to calling **IDBInitialize::Initialize**. When this property is set, the provider returns immediately from the call to **Initialize** with either S_OK, if the operation has completed immediately, or DB_S_ASYNCHRONOUS, if the initialization is continuing asynchronously. Applications can query for the **IDBAsynchStatus** or [ISSAsynchStatus](../../../relational-databases/native-client-ole-db-interfaces/issasynchstatus-ole-db.md)interface on the data source object, and then call **IDBAsynchStatus::GetStatus** or[ISSAsynchStatus::WaitForAsynchCompletion](../../../relational-databases/native-client-ole-db-interfaces/issasynchstatus-waitforasynchcompletion-ole-db.md) to get the status of the initialization. In addition, the SSPROP_ISSAsynchStatus property has been added to the DBPROPSET_SQLSERVERROWSET property set. Providers that support the **ISSAsynchStatus** interface must implement this property with a value of VARIANT_TRUE. **IDBAsynchStatus::Abort** or [ISSAsynchStatus::Abort](../../../relational-databases/native-client-ole-db-interfaces/issasynchstatus-abort-ole-db.md) can be called to cancel the asynchronous **Initialize** call. The consumer must explicitly request Asynchronous Data Source Initialization. Otherwise, **IDBInitialize::Initialize** does not return until the data source object is completely initialized. > [!NOTE] > Data source objects used for connection pooling cannot call the **ISSAsynchStatus** interface in the [!INCLUDE[ssNoVersion](../../../includes/ssnoversion-md.md)] Native Client OLE DB provider. The **ISSAsynchStatus** interface is not exposed for pooled data source objects. > > If an application explicitly forces use of the cursor engine, **IOpenRowset::OpenRowset** and **IMultipleResults::GetResult** will not support asynchronous processing. > > In addition, the remoting proxy/stub dll (in MDAC 2.8) cannot call the **ISSAsynchStatus** interface in [!INCLUDE[ssNoVersion](../../../includes/ssnoversion-md.md)] Native Client. The **ISSAsynchStatus** interface is not exposed through remoting. > > Service Components do not support **ISSAsynchStatus**. ## Execution and Rowset Initialization Applications designed to asynchronously open the result from the execution of a command can set the DBPROPVAL_ASYNCH_INITIALIZE bit in the DBPROP_ROWSET_ASYNCH property. When setting this bit prior to calling **IDBInitialize::Initialize**, **ICommand::Execute**, **IOpenRowset::OpenRowset** or **IMultipleResults::GetResult**, the *riid* argument must be set to IID_IDBAsynchStatus, IID_ISSAsynchStatus, or IID_IUnknown. The method returns immediately with S_OK if the rowset initialization completes immediately, or with DB_S_ASYNCHRONOUS if the rowset continues initializing asynchronously, with *ppRowset* set to the requested interface on the rowset. For the [!INCLUDE[ssNoVersion](../../../includes/ssnoversion-md.md)] Native Client OLE DB provider, this interface can only be **IDBAsynchStatus** or **ISSAsynchStatus**. Until the rowset is fully initialized, this interface behaves as if it were in a suspended state, and calling **QueryInterface** for interfaces other than **IID_IDBAsynchStatus** or **IID_ISSAsynchStatus** may return E_NOINTERFACE. Unless the consumer explicitly requests asynchronous processing, the rowset is initialized synchronously. All requested interfaces are available when **IDBAsynchStaus::GetStatus** or **ISSAsynchStatus::WaitForAsynchCompletion** returns with the indication that asynchronous operation is complete. This does not necessarily mean that the rowset is fully populated, but it is complete and fully functional. If the executed command does not return a rowset, it still returns immediately with an object that supports **IDBAsynchStatus**. If you need to get multiple results from asynchronous command execution, you should: - Set the DBPROPVAL_ASYNCH_INITIALIZE bit of the DBPROP_ROWSET_ASYNCH property, before executing the command. - Call **ICommand::Execute**, and request **IMultipleResults**. The **IDBAsynchStatus** and **ISSAsynchStatus** interfaces can then be obtained by querying the multiple results interface using **QueryInterface**. When the command has finished executing, **IMultipleResults** can be used as normal, with one exception from the synchronous case: DB_S_ASYNCHRONOUS may be returned, in which case **IDBAsynchStatus** or **ISSAsynchStatus** can be used to determine when the operation is complete. ## Examples In the following example, the application calls a non-blocking method, does some other processing, and then returns to process the results. **ISSAsynchStatus::WaitForAsynchCompletion** waits on the internal event object until the asynchronously executing operation is done or the amount of time specified by *dwMilisecTimeOut* is passed. ``` // Set the DBPROPVAL_ASYNCH_INITIALIZE bit in the // DBPROP_ROWSET_ASYNCH property before calling Execute(). DBPROPSET CmdPropset[1]; DBPROP CmdProperties[1]; CmdPropset[0].rgProperties = CmdProperties; CmdPropset[0].cProperties = 1; CmdPropset[0].guidPropertySet = DBPROPSET_ROWSET; // Set asynch mode for command. CmdProperties[0].dwPropertyID = DBPROP_ROWSET_ASYNCH; CmdProperties[0].vValue.vt = VT_I4; CmdProperties[0].vValue.lVal = DBPROPVAL_ASYNCH_INITIALIZE; CmdProperties[0].dwOptions = DBPROPOPTIONS_REQUIRED; hr = pICommandProps->SetProperties(1, CmdPropset); hr = pICommand->Execute( pUnkOuter, IID_ISSAsynchStatus, pParams, pcRowsAffected, (IUnknown**)&pISSAsynchStatus); if (hr == DB_S_ASYNCHRONOUS) { // Do some work here... hr = pISSAsynchStatus->WaitForAsynchCompletion(dwMilisecTimeOut); if ( hr == S_OK) { hr = pISSAsynchStatus->QueryInterface(IID_IRowset, (void**)&pRowset); pISSAsynchStatus->Release(); } } ``` **ISSAsynchStatus::WaitForAsynchCompletion** waits on the internal event object until the asynchronously executing operation is done or the *dwMilisecTimeOut* value is passed. The following example shows asynchronous processing with multiple result sets: ``` DBPROP CmdProperties[1]; // Set asynch mode for command. CmdProperties[0].dwPropertyID = DBPROP_ROWSET_ASYNCH; CmdProperties[0].vValue.vt = VT_I4; CmdProperties[0].vValue.lVal = DBPROPVAL_ASYNCH_INITIALIZE; hr = pICommand->Execute( pUnkOuter, IID_IMultipleResults, pParams, pcRowsAffected, (IUnknown**)&pIMultipleResults); // Use GetResults for ISSAsynchStatus. hr = pIMultipleResults->GetResult(IID_ISSAsynchStatus, (void **) &pISSAsynchStatus); if (hr == DB_S_ASYNCHRONOUS) { // Do some work here... hr = pISSAsynchStatus->WaitForAsynchCompletion(dwMilisecTimeOut); if (hr == S_OK) { hr = pISSAsynchStatus->QueryInterface(IID_IRowset, (void**)&pRowset); pISSAsynchStatus->Release(); } } ``` To prevent blocking, the client can check the status of a running asynchronous operation, as in the following example: ``` // Set the DBPROPVAL_ASYNCH_INITIALIZE bit in the // DBPROP_ROWSET_ASYNCH property before calling Execute(). hr = pICommand->Execute( pUnkOuter, IID_ISSAsynchStatus, pParams, pcRowsAffected, (IUnknown**)&pISSAsynchStatus); if (hr == DB_S_ASYNCHRONOUS) { do{ // Do some work... hr = pISSAsynchStatus->GetStatus(DB_NULL_HCHAPTER, DBASYNCHOP_OPEN, NULL, NULL, &ulAsynchPhase, NULL); }while (DBASYNCHPHASE_COMPLETE != ulAsynchPhase) if SUCCEEDED(hr) { hr = pISSAsynchStatus->QueryInterface(IID_IRowset, (void**)&pRowset); } pIDBAsynchStatus->Release(); } ``` The following example demonstrates how you can cancel the currently running asynchronous operation: ``` // Set the DBPROPVAL_ASYNCH_INITIALIZE bit in the // DBPROP_ROWSET_ASYNCH property before calling Execute(). hr = pICommand->Execute( pUnkOuter, IID_ISSAsynchStatus, pParams, pcRowsAffected, (IUnknown**)&pISSAsynchStatus); if (hr == DB_S_ASYNCHRONOUS) { // Do some work... hr = pISSAsynchStatus->Abort(DB_NULL_HCHAPTER, DBASYNCHOP_OPEN); } ``` ## See Also [SQL Server Native Client Features](../../../relational-databases/native-client/features/sql-server-native-client-features.md) [Rowset Properties and Behaviors](../../../relational-databases/native-client-ole-db-rowsets/rowset-properties-and-behaviors.md) [ISSAsynchStatus (OLE DB)](../../../relational-databases/native-client-ole-db-interfaces/issasynchstatus-ole-db.md)