How to bulk copy data using IRowsetFastLoad (OLE DB)

How to Install SQL Server 2000

How To

How to bulk copy data using IRowsetFastLoad (OLE DB)

The consumer notifies SQLOLEDB of its need for bulk copying by setting the SQLOLEDB provider-specific property SSPROP_ENABLEFASTLOAD to VARIANT_TRUE. With the property set on the data source, the consumer creates a SQLOLEDB session. The new session allows the consumer access to IRowsetFastLoad.

To bulk copy data into a SQL Server table

  1. Establish a connection to the data source.

  2. Set the SQLOLEDB provider-specific data source property SSPROP_ENABLEFASTLOAD to VARIANT_TRUE. With this property set to VARIANT_TRUE, the newly created session allows the consumer access to IRowsetFastLoad.

  3. Create a session requesting the IOpenRowset interface.

  4. Call IOpenRowset::OpenRowset to open a rowset that includes all the rows from the table (in which data is to be copied using bulk-copy operation).

  5. Do the necessary bindings and create an accessor using IAccessor::CreateAccessor.

  6. Set up the memory buffer from which the data will be copied to the table.

  7. Call IRowsetFastLoad::InsertRow to bulk copy the data in to the table.

The following example illustrates the use of IRowsetFastLoad for bulk copying of the records into a table. In this example, 10 records will be added to the table IRFLTable. You need to create the table IRFLTable in the database.

CREATE TABLE IRFLTable (col_vchar varchar(30))

#define DBINITCONSTANTS

#include <oledb.h>
#include <oledberr.h>
#include <stdio.h>
#include <stddef.h>  //for offsetof
#include <sqloledb.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"server ";
WCHAR g_strTestDSN[]    = L"database";
WCHAR g_strTestUID[]    = L"login";        
WCHAR g_strTestPWD[]    = L"password";    
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(void);

// How to lay out each column in memory.
struct COLUMNDATA {
    SDWORD            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;
    BOOL                fResults = FALSE;
                        //OLE initialized?
    BOOL                fInitialized = FALSE;
                        //One property set for initializing.
    DBPROPSET           rgPropertySets[1];
                        //Properties within above property set.
    DBPROP              rgDBProperties[g_cOPTION]; 
                        //Property count.
    ULONG               ulPropCount  = 0;
                        //# of initialization properties.
    ULONG               cOptions =     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_strTestDSN, 
                 &rgDBProperties[0]);
    SetupOption(DBPROP_AUTH_USERID, 
                g_strTestUID,  
                &rgDBProperties[1]);
    SetupOption(DBPROP_AUTH_PASSWORD, 
                g_strTestPWD,  
                &rgDBProperties[2]);
    SetupOption(DBPROP_INIT_DATASOURCE, 
                g_strTestLOC,  
                &rgDBProperties[3]);

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

    //Get IRowsetFastLoad and insert data into IRFLTable.
    if(FAILED(hr = FastLoadData()))
        goto cleanup;
        
cleanup:
    //Free 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");

    return(0);
    }
//--------------------------------------------------------------
HRESULT  FastLoadData(void)
{
    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;
    CHAR              strData[] = "Show me the money!";

    TableID.eKind = DBKIND_NAME;
    TableID.uName.pwszName = new WCHAR[wcslen(g_wszTable)+2];
    wcscpy(TableID.uName.pwszName, g_wszTable);

    //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;

    //Next set up an accessor for the data.

    //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];  
    pcolData = (COLUMNDATA*)pData;
    pcolData->dwLength = strlen("Show the data") + 1;
    pcolData->dwStatus =  0;
    memcpy(&(pcolData->bData), "Show the data", 
                            strlen("Show me 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));
    }