MDAC 2.5 SDK - OLE DB Programmer's Reference
Chapter 27: OLE DB for OLAP Code Samples
MDPDataset is used to get the cell data for an MDX query specified by pwszQuery, compute the cell data coordinates, and call IMDDataset::GetCellData for each cell in the dataset.
//
HRESULT MDPDataset(ICommandText *pICommandText, pwszQuery)
{
HRESULT hr;
struct COLUMNDATA
{
SDWORD dwLength; // length of data (not space allocated)
DBSTATUS dwStatus; // status of column
VARIANT var; // variant value
};
// Execute the MDX query.
IMDDataset* pIMDDataset = NULL;
hr = pICommandText->SetCommandText(DBGUID_MDX, pwszQuery);
hr = pICommandText->Execute(NULL, IID_IMDDataset, NULL, NULL,
(IUnknown **)&pIMDDataset ));
// Fetch the axis info to compute the coordinates.
ULONG cAxis;
MDAXISINFO* rgAxisInfo = NULL;
hr = pIMDDataset->GetAxisInfo( &cAxis, &rgAxisInfo );
// Calculate the coordinate "offset factors". These are used to
// translate from a point in cell space to a set of axis coordinates.
// Example, consider a dataset with three axes and the following
// number of coordinates for each axis:
// {x,y,z} = {3,4,5}
// rgAxisOffset[2] = 3*4
// rgAxisOffset[1] = 3
// rgAxisOffset[0] = 1
// Thus, where p represents the cell's ordinal value:
// z = p % 12
// y = (p - z*12) % 3
// x = (p - z*12 - y*3)
// And,
// p = x + 3*y + 12*z
ULONG cAxisTuple;
ULONG iOffset = 1;
ULONG ulMaxCoord = 0;
ULONG rgAxisOffset[MAX_DIMS]; // array of offset multipliers
// For all axes, excluding slicer axis...
for (ULONG iAxis=0; iAxis < cAxis-1; iAxis++)
{
rgAxisOffset[iAxis] = iOffset;
cAxisTuple = rgAxisInfo[iAxis].cCoordinates;
iOffset *= cAxisTuple;
}
ulMaxCoord = iOffset;
ULONG cSliceCoord = rgAxisOffset[cAxis-1]
// Bind to the column values for each cell.
IColumnsInfo *pIColumnsInfo = NULL;
hr = pIMDDataset->QueryInterface(IID_IColumnsInfo,
(void**)&pIColumnsInfo);
ULONG cCol;
WCHAR* pStringsBuffer = NULL;
DBCOLUMNINFO* pInfo = NULL;
hr = pIColumnsInfo->GetColumnInfo(&cCol, &pInfo, &pStringsBuffer);
// Create bindings for each cell's columns, ordered as returned by
// GetColumnInfo. Bind everything as Variant.
dwOffset = 0;
ULONG iBind = 0;
ULONG cBind = 0;
for (ULONG iCol=0; iCol < cCol; iCol++)
{
rgBind[iBind].iOrdinal = pInfo[iCol].iOrdinal;
rgBind[iBind].obValue = dwOffset +
offsetof(COLUMNDATA,var);
rgBind[iBind].obLength = dwOffset +
offsetof(COLUMNDATA,dwLength);
rgBind[iBind].obStatus = dwOffset +
offsetof(COLUMNDATA,dwStatus);
rgBind[iBind].pTypeInfo = NULL;
rgBind[iBind].pObject = NULL;
rgBind[iBind].pBindExt = NULL;
rgBind[iBind].cbMaxLen = sizeof(VARIANT);
rgBind[iBind].dwFlags = 0;
rgBind[iBind].eParamIO = DBPARAMIO_NOTPARAM;
rgBind[iBind].dwPart = DBPART_VALUE |
DBPART_LENGTH |
DBPART_STATUS;
rgBind[iBind].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
rgBind[iBind].wType = DBTYPE_VARIANT;
rgBind[iBind].bPrecision = 0;
rgBind[iBind].bScale = 0;
dwOffset += rgBind[iBind].cbMaxLen + offsetof(COLUMNDATA,var);
iBind++;
}
cBind = iBind;
// Create the accessor.
IAccessor* pIAccessor;
hr = pIMDDataset->QueryInterface(IID_IAccessor, void**)&pIAccessor);
// Note that the value of dwOffset contains the size of a cell.
// Failure to specify this value will result in an error.
hr = pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, cBind, rgBind,
dwOffset, phAccessor, NULL);
pIAccessor->Release();
pIColumnsInfo->Release();
// Allocate a buffer for a single cell in a slice.
ULONG cbRowsize = dwOffset;
pData = (BYTE*)CoTaskMemAlloc(cbRowSize);
// Fetch each cell in the dataset.
for (ULONG ulCellCoord=0; ulCellCoord < ulMaxCoord; ulCellCoord++)
{
// Populate cell buffer.
hr = pIMDDataset->GetCellData(hAccessor, ulCellCoord, ulCellCoord,
pData);
// Traverse each bound cell property value for a single cell "row."
// Use pColumn to access each column's data values.
for (iBind=0; iBind < cBind; iBind++)
{
// Advance to the column value.
(COLUMNDATA*)pColumn = (COLUMNDATA *)(pData +
rgBind[iBind].obLength);
// pColumn->var points to the variant value.
}
}
// Free the accessor and rowset.
hr = pIAccessor->ReleaseAccessor(hAccessor, NULL);
hr = pIAccessor->Release();
hr = pIColumnsInfo->Release();
// Free the row data and bindings.
CoTaskMemFree(pData);
CoTaskMemFree(rgBind);
// Free the column info.
CoTaskMemFree(pInfo);
CoTaskMemFree(pwszStringsBuffer);
hr = pIMDDataset->FreeAxisInfo(cAxis, rgAxisInfo);
hr = pIMDDataset->Release();
return hr;
}