Compartir a través de


Copiar datos de forma masiva mediante IRowsetFastLoad (OLE DB)

En este ejemplo se muestra el uso de IRowsetFastLoad para la copia masiva de los registros en una tabla.

El consumidor notifica a SQLOLEDB su necesidad de realizar una copia masiva estableciendo la propiedad SSPROP_ENABLEFASTLOAD específica del proveedor SQLOLEDB en VARIANT_TRUE. Con la propiedad establecida en el origen de datos, el consumidor crea una sesión SQLOLEDB. La nueva sesión permite el acceso del consumidor a IRowsetFastLoad.

Tiene a su disposición un ejemplo completo donde se muestra el uso de IRowsetFastLoad para la copia masiva de los registros en una tabla. En este ejemplo, se agregan 10 registros a la tabla IRFLTable. Es necesario crear la tabla IRFLTable en la base de datos.

Este ejemplo requiere la base de datos de ejemplo AdventureWorks que se puede descargar de la página principal que muestra ejemplos y proyectos de la comunidad de Microsoft SQL Server.

Nota de seguridadNota de seguridad

Siempre que sea posible, utilice la autenticación de Windows. Si la autenticación de Windows no está disponible, solicite a los usuarios que escriban sus credenciales en tiempo de ejecución. No guarde las credenciales en un archivo. Si tiene que conservar las credenciales, debería cifrarlas con la API de criptografía de Win32.

Para realizar una copia masiva de datos en una tabla de SQL Server

  1. Establezca una conexión con el origen de datos.

  2. Establezca la propiedad de origen de datos SSPROP_ENABLEFASTLOAD específica del proveedor SQLOLEDB en VARIANT_TRUE. Con esta propiedad establecida en VARIANT_TRUE, la sesión recién creada permite el acceso del consumidor a IRowsetFastLoad.

  3. Cree una sesión que solicite la interfaz IOpenRowset.

  4. Llame a IOpenRowset::OpenRowset para abrir un conjunto de filas que incluya todas las filas de la tabla (donde los datos se copiarán mediante una operación de copia masiva).

  5. Realice los enlaces necesarios y cree un descriptor de acceso mediante IAccessor::CreateAccessor.

  6. Configure el búfer de memoria desde el que los datos se copiarán en la tabla.

  7. Llame a IRowsetFastLoad::InsertRow para realizar la copia masiva de los datos en la tabla.

Ejemplo

En este ejemplo, se agregan 10 registros a la tabla IRFLTable. Es necesario crear la tabla IRFLTable en la base de datos. Este ejemplo no es compatible con IA64.

Ejecute la primera lista de código (Transact-SQL) para crear la tabla utilizada por la aplicación.

Compile con ole32.lib oleaut32.lib y ejecute la siguiente lista de código C++. Esta aplicación se conecta a la instancia predeterminada de SQL Server del equipo. En algunos sistemas operativos Windows, deberá cambiar (localhost) o (local) al nombre de la instancia de SQL Server. Para conectarse a una instancia con nombre, cambie la cadena de conexión de L"(local)" a L"(local)\\name", donde "name" es la instancia con nombre. De forma predeterminada, SQL Server Express se instala en una instancia con nombre. Asegúrese de que la variable de entorno INCLUDE incluye el directorio que contiene sqlncli.h.

Ejecute la tercera lista de código (Transact-SQL) para eliminar la tabla utilizada por la aplicación.

USE AdventureWorks
GO

IF EXISTS (SELECT name FROM sysobjects WHERE name = 'IRFLTable')
     DROP TABLE IRFLTable
GO

CREATE TABLE IRFLTable (col_vchar varchar(30))

// compile with: ole32.lib oleaut32.lib
#define DBINITCONSTANTS
#define OLEDBVER 0x0250   // to include correct interfaces

#include <oledb.h>
#include <oledberr.h>
#include <stdio.h>
#include <stddef.h>   // for offsetof
#include <sqlncli.h>

// @type UWORD    | 2 byte unsigned integer.
typedef unsigned short UWORD;

// @type SDWORD   | 4 byte signed integer.
typedef signed long SDWORD;

WCHAR g_wszTable[] = L"IRFLTable";
WCHAR g_strTestLOC[100] = L"localhost";
WCHAR g_strTestDBName[] = L"AdventureWorks";
const UWORD g_cOPTION = 4;
const UWORD MAXPROPERTIES = 5;
const ULONG DEFAULT_CBMAXLENGTH = 20;
IMalloc* g_pIMalloc = NULL;
IDBInitialize* g_pIDBInitialize = NULL;

// Given an ICommand pointer, properties, and query, a rowsetpointer is returned.
HRESULT CreateSessionCommand( DBPROPSET* rgPropertySets, ULONG ulcPropCount, CLSID clsidProv );

// Use to set properties and execute a given query.
HRESULT ExecuteQuery ( IDBCreateCommand* pIDBCreateCommand,
                       WCHAR* pwszQuery,
                       DBPROPSET* rgPropertySets,
                       ULONG ulcPropCount, 
                       LONG* pcRowsAffected,
                       IRowset** ppIRowset,
                       BOOL fSuccessOnly = TRUE );

// Use to set up options for call to IDBInitialize::Initialize.
void SetupOption ( DBPROPID PropID, WCHAR *wszVal, DBPROP * pDBProp );

// Sets fastload property on/off for session.
HRESULT SetFastLoadProperty(BOOL fSet);

// IRowsetFastLoad inserting data.
HRESULT FastLoadData();

// How to lay out each column in memory.
struct COLUMNDATA {
   DBLENGTH dwLength;   // Length of data (not space allocated).
   DWORD dwStatus;   // Status of column.
   BYTE bData[1];   // Store data here as a variant.
};

#define COLUMN_ALIGNVAL 8

#define ROUND_UP(Size, Amount)(((DWORD)(Size) + ((Amount)-1)) & ~((Amount)-1))

int main() {
   HRESULT hr = NOERROR;
   HRESULT hr2 = NOERROR;

   // OLE initialized?
   BOOL fInitialized = FALSE;

   // One property set for initializing.
   DBPROPSET rgPropertySets[1];

   // Properties within above property set.
   DBPROP rgDBProperties[g_cOPTION]; 

   IDBCreateCommand* pIDBCreateCommand = NULL;
   IRowset* pIRowset = NULL;
   DBPROPSET* rgProperties = NULL;
   IAccessor* pIAccessor = NULL;

   // Basic initialization.
   if ( FAILED(CoInitialize(NULL)) )
      goto cleanup;
   else
      fInitialized = TRUE;

   hr = CoGetMalloc(MEMCTX_TASK, &g_pIMalloc);
   if ((!g_pIMalloc) || FAILED(hr))
      goto cleanup;

   // Set up property set for call to IDBInitialize in CreateSessionCommand.
   rgPropertySets[0].rgProperties = rgDBProperties;
   rgPropertySets[0].cProperties = g_cOPTION;
   rgPropertySets[0].guidPropertySet = DBPROPSET_DBINIT;

   SetupOption(DBPROP_INIT_CATALOG, g_strTestDBName, &rgDBProperties[0]);

   SetupOption(DBPROP_AUTH_INTEGRATED, L"SSPI", &rgDBProperties[1]);

   SetupOption(DBPROP_INIT_DATASOURCE, g_strTestLOC, &rgDBProperties[3]);

   if (!SUCCEEDED( hr = CreateSessionCommand(rgPropertySets, 1, CLSID_SQLNCLI11)))
      goto cleanup;

   // Get IRowsetFastLoad and insert data into IRFLTable.
   if (FAILED(hr = FastLoadData()))
      goto cleanup;

cleanup:
   // Release memory.
   if (rgProperties && rgProperties->rgProperties)
      delete [](rgProperties->rgProperties);
   if (rgProperties)
      delete []rgProperties;
   if (pIDBCreateCommand)
      pIDBCreateCommand->Release();

   if (pIAccessor)
      pIAccessor->Release();

   if (pIRowset)
      pIRowset->Release();
   if (g_pIMalloc)
      g_pIMalloc->Release();

   if (g_pIDBInitialize) {    
      hr2 = g_pIDBInitialize->Uninitialize();
      if (FAILED(hr2))
         printf("Uninitialize failed\n");
   }

   if (fInitialized)
      CoUninitialize();

   if (SUCCEEDED(hr))
      printf("Test completed successfully.\n\n");
   else
      printf("Test failed.\n\n");
}

HRESULT FastLoadData() {
   HRESULT hr = E_FAIL;
   HRESULT hr2 = E_FAIL;
   DBID TableID;

   IDBCreateSession* pIDBCreateSession = NULL;
   IOpenRowset* pIOpenRowsetFL = NULL;
   IRowsetFastLoad* pIFastLoad = NULL;

   IAccessor* pIAccessor = NULL;
   HACCESSOR hAccessor = 0;
   DBBINDSTATUS oneStatus = 0;

   DBBINDING oneBinding;
   ULONG ulOffset = 0;
   TableID.uName.pwszName = NULL;
   LONG i = 0;
   void* pData = NULL;
   COLUMNDATA* pcolData = NULL;

   TableID.eKind = DBKIND_NAME;
   // if ( !(TableID.uName.pwszName = new WCHAR[wcslen(g_wszTable) + 2]) )
   LPOLESTR x = TableID.uName.pwszName = new WCHAR[wcslen(g_wszTable) + 2];
   if (!x)
      return E_FAIL;
   wcsncpy_s(TableID.uName.pwszName, wcslen(g_wszTable) + 2, g_wszTable, wcslen(g_wszTable)+1);
   TableID.uName.pwszName[wcslen(g_wszTable)+1] = (WCHAR) NULL;

   // Get the fastload pointer.
   if (FAILED(hr = SetFastLoadProperty(TRUE)))
      goto cleanup;

   if ( FAILED( hr = 
      g_pIDBInitialize->QueryInterface( IID_IDBCreateSession, (void **) &pIDBCreateSession )))
      goto cleanup;

   if ( FAILED( hr = 
      pIDBCreateSession->CreateSession( NULL, IID_IOpenRowset, (IUnknown **) &pIOpenRowsetFL )))
      goto cleanup;

   // Get IRowsetFastLoad initialized to use the test table.
   if (FAILED(hr = 
      pIOpenRowsetFL->OpenRowset(NULL, 
                                 &TableID, 
                                 NULL, 
                                 IID_IRowsetFastLoad, 
                                 0, 
                                 NULL, 
                                 (LPUNKNOWN *)&pIFastLoad)))
      goto cleanup;

   // Set up custom bindings.
   oneBinding.dwPart = DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS;
   oneBinding.iOrdinal = 1;
   oneBinding.pTypeInfo = NULL;
   oneBinding.obValue = ulOffset + offsetof(COLUMNDATA,bData);
   oneBinding.obLength = ulOffset + offsetof(COLUMNDATA,dwLength);
   oneBinding.obStatus = ulOffset + offsetof(COLUMNDATA,dwStatus);
   oneBinding.cbMaxLen = 30;   // Size of varchar column.
   oneBinding.pTypeInfo = NULL;
   oneBinding.pObject = NULL;
   oneBinding.pBindExt = NULL;
   oneBinding.dwFlags = 0;
   oneBinding.eParamIO = DBPARAMIO_NOTPARAM;
   oneBinding.dwMemOwner = DBMEMOWNER_CLIENTOWNED;
   oneBinding.bPrecision= 0;   
   oneBinding.bScale = 0;  
   oneBinding.wType = DBTYPE_STR;  
   ulOffset = oneBinding.cbMaxLen + offsetof(COLUMNDATA, bData);
   ulOffset = ROUND_UP( ulOffset, COLUMN_ALIGNVAL );

   if ( FAILED( hr = 
      pIFastLoad->QueryInterface(IID_IAccessor, (void **) &pIAccessor))) 
      return hr;

   if (FAILED(hr = pIAccessor->CreateAccessor( DBACCESSOR_ROWDATA, 
                                               1, 
                                               &oneBinding, 
                                               ulOffset, 
                                               &hAccessor, 
                                               &oneStatus)))
      return hr;

   // Set up memory buffer.
   pData = new BYTE[40];
   if (!(pData /* = new BYTE[40]*/ )) {
      hr = E_FAIL;
      goto cleanup;
   }

   pcolData = (COLUMNDATA*)pData;
   pcolData->dwLength = (SDWORD)strlen("Show the data") + 1;
   pcolData->dwStatus = 0;
   memcpy(&(pcolData->bData), "Show the data", strlen("Show the data") + 1);

   for ( i = 0 ; i < 10 ; i++ )
      if (FAILED(hr = pIFastLoad->InsertRow(hAccessor, pData)))
         goto cleanup;

   if (FAILED(hr = pIFastLoad->Commit(TRUE)))
      printf("Error on IRFL::Commit\n");

cleanup:
   if (FAILED(hr2 = SetFastLoadProperty(FALSE)))
      printf("SetFastLoadProperty(FALSE) failed with %x", hr2);

   if (pIAccessor && hAccessor)
      if (FAILED(pIAccessor->ReleaseAccessor(hAccessor, NULL)))
         hr = E_FAIL;

   if (pIAccessor)
      pIAccessor->Release();

   if (pIFastLoad)
      pIFastLoad->Release();

   if (pIOpenRowsetFL)
      pIOpenRowsetFL->Release();

   if (pIDBCreateSession)
      pIDBCreateSession->Release();

   if (TableID.uName.pwszName)
      delete []TableID.uName.pwszName;

   return hr;
}

HRESULT SetFastLoadProperty(BOOL fSet) {
   HRESULT hr = S_OK;
   IDBProperties* pIDBProps = NULL;
   DBPROP rgProps[1];
   DBPROPSET PropSet;

   VariantInit(&rgProps[0].vValue);

   rgProps[0].dwOptions = DBPROPOPTIONS_REQUIRED;
   rgProps[0].colid = DB_NULLID;
   rgProps[0].vValue.vt = VT_BOOL;
   rgProps[0].dwPropertyID = SSPROP_ENABLEFASTLOAD;

   if (fSet == TRUE)
      rgProps[0].vValue.boolVal = VARIANT_TRUE;
   else
      rgProps[0].vValue.boolVal = VARIANT_FALSE;

   PropSet.rgProperties = rgProps;
   PropSet.cProperties = 1;
   PropSet.guidPropertySet = DBPROPSET_SQLSERVERDATASOURCE;

   if (SUCCEEDED(hr = g_pIDBInitialize->QueryInterface(IID_IDBProperties, (LPVOID *)&pIDBProps)))
      hr = pIDBProps->SetProperties(1, &PropSet);

   VariantClear(&rgProps[0].vValue); 

   if (pIDBProps)
      pIDBProps->Release();

   return hr;
}

HRESULT CreateSessionCommand( DBPROPSET* rgPropertySets,// @parm [in] property sets
                              ULONG ulcPropCount,   // @parm [in] count of prop sets.
                              CLSID clsidProv) {  // @parm [in] Provider CLSID.

   HRESULT hr = NOERROR;
   IDBCreateSession* pIDBCreateSession = NULL;
   IDBProperties* pIDBProperties = NULL;
   UWORD i = 0, j = 0;   // indexes.

   if (ulcPropCount && !rgPropertySets) {
      hr = E_INVALIDARG;
      return hr;
   }

   if (!SUCCEEDED(hr = CoCreateInstance(clsidProv, 
                                        NULL,CLSCTX_INPROC_SERVER,
                                        IID_IDBInitialize,
                                        (void **)&g_pIDBInitialize)))
      goto CLEANUP;

   if (!SUCCEEDED(hr = g_pIDBInitialize->QueryInterface( IID_IDBProperties,
                                                         (void **)&pIDBProperties)))
      goto CLEANUP;

   if (!SUCCEEDED(hr = pIDBProperties->SetProperties(ulcPropCount, rgPropertySets)))
      goto CLEANUP;

   if (!SUCCEEDED(hr = g_pIDBInitialize->Initialize())) {
      printf("Call to initialize failed.\n");
      goto CLEANUP;
   }

CLEANUP:
   if (pIDBProperties)
      pIDBProperties->Release();
   if (pIDBCreateSession)
      pIDBCreateSession->Release();

   for (i = 0 ; i < ulcPropCount ; i++)
      for (j = 0 ; j < rgPropertySets[i].cProperties ; j++)
         VariantClear(&(rgPropertySets[i].rgProperties[j]).vValue);
   return hr;
}

void SetupOption (DBPROPID PropID, WCHAR *wszVal, DBPROP * pDBProp ) {
   pDBProp->dwPropertyID = PropID;
   pDBProp->dwOptions = DBPROPOPTIONS_REQUIRED;
   pDBProp->colid = DB_NULLID;
   pDBProp->vValue.vt = VT_BSTR;
   pDBProp->vValue.bstrVal = SysAllocStringLen(wszVal, wcslen(wszVal));
}

USE AdventureWorks
GO

IF EXISTS (SELECT name FROM sysobjects WHERE name = 'IRFLTable')
     DROP TABLE IRFLTable
GO