Creating a Dataset and Obtaining Axis Information
This function executes an MDX query statement specified by pwszQuery. IMDDataset::GetAxisInfo and IMDDataset::GetAxisRowset are called to traverse the column information for each axis in the MDX query.
HRESULT MDPQueryColumnInfo(ICommandText *pICommandText, LPCOLESTR pwszQuery)
{
HRESULT hr;
struct COLUMNDATA
{
DWORD dwLength; // length of data
DBSTATUS dwStatus; // status of column
SHORT wPadding;
BYTE bData[1]; // variable-length data
};
// Execute the query.
IMDDataset* pIMDDataset = NULL;
hr = pICommandText->SetCommandText(DBGUID_MDX, pwszQuery);
hr = pICommandText->Execute(NULL, IID_IMDDataset, NULL, NULL,
(IUnknown **)&pIMDDataset );
// Fetch and traverse the axis info.
DBCOUNTITEM cAxis;
MDAXISINFO* rgAxisInfo = NULL;
hr = pIMDDataset->GetAxisInfo( &cAxis, &rgAxisInfo );
for (DBCOUNTITEM iAxis=0; iAxis < cAxis; iAxis++)
{
// rgAxisInfo contains the array of dimensions for each axis.
for (DBCOUNTITEM iDim=0; iDim < rgAxisInfo[iAxis].cDimensions; iDim++)
{
// MDAXISINFO_GETAT(rgAxisInfo, iAxis).rgpwszDimensionNames points
// to the dimension name.
assert( MDAXISINFO_GETAT(rgAxisInfo, iAxis).rgpwszDimensionNames);
}
// Fetch the axis rowset for each axis.
IRowset* pIrowset = NULL;
hr = pIMDDataset->GetAxisRowset(NULL, iAxis,
IID_IRowset, 0, NULL, (IUnknown**)&pIRowset);
// Fetch the column info for the axis rowset.
IColumnsInfo *pIColumnsInfo = NULL;
hr = pIRowset->QueryInterface(IID_IColumnsInfo,
(void**)&pIColumnsInfo);
DBCOUNTITEM cCol;
WCHAR* pStringsBuffer = NULL;
DBCOLUMNINFO* pInfo = NULL;
hr = pIColumnsInfo->GetColumnInfo(&cCol, &pInfo, &pStringsBuffer);
// Create bindings for all columns, in same order as given by
// GetColumnInfo. Bind everything as string, and skip DBTYPE_VECTOR
// type columns.
DBBYTEOFFSET dwOffset = 0;
DBCOUNTITEM iBind = 0;
DBCOUNTITEM cBind = 0;
DBBINDING* rgBind = (DBBINDING*)CoTaskMemAlloc(
cCol*sizeof(DBBINDING));
for (DBCOUNTITEM iCol=0; iCol < cCol; iCol++)
{
// Skip columns of type _VECTOR (probably binary data).
if (pInfo[iCol].wType & DBTYPE_VECTOR)
continue;
rgBind[iBind].iOrdinal = pInfo[iCol].iOrdinal;
rgBind[iBind].obValue = dwOffset +
offsetof(COLUMNDATA,bData);
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 = pInfo[iCol].ulColumnSize;
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].bPrecision = 0;
rgBind[iBind].bScale = 0;
rgBind[iBind].wType = DBTYPE_STR;
dwOffset += rgBind[iBind].cbMaxLen +
offsetof(COLUMNDATA,bData);
iBind++;
}
cBind = iBind;
// Create the accessor.
IAccessor* pIAccessor;
hr = pIRowset->QueryInterface(IID_IAccessor, (void**)&pIAccessor);
hr = pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, cBind, rgBind,
dwOffset, phAccessor, NULL);
// Allocate a buffer for a single row of data.
DBLENGTH cbRowsize = dwOffset;
BYTE* pData = (BYTE *)CoTaskMemAlloc(cbRowSize);
while (SUCCEEDED(hr))
{
// Prepare internal buffers and get handles to the rows.
// Fetch 20 rows at a time.
DBCOUNTITEM cRowsObtained;
hr = pIRowset->GetNextRows(NULL, 0, 20, &cRowsObtained, &pRows);
// Break on EndOfRowset.
if (cRowsObtained == 0) break;
for (DBCOUNTITEM iRow=0; iRow < cRowsObtained; iRow++)
{
// Clear buffer.
memset(pData, 0, cbRowSize);
// Get the row data.
hr = pIRowset->GetData(rghRows[iRow], hAccessor, pData);
// Traverse each bound column value for a single 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);
// (WCHAR*)pColumn->bData points to the string value.
}
}
// Release the row handles.
hr = pIRowset->ReleaseRows(cRowsObtained, rghRows, NULL, NULL,
NULL);
}
// Free the accessor and rowset.
hr = pIAccessor->ReleaseAccessor(hAccessor, NULL);
hr = pIAccessor->Release();
hr = pIRowset->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;
}