This function executes an MDX query statement specified by pwszQuery. GetAxisInfo and GetAxisRowset are called to traverse the column information for each axis in the MDX query.
HRESULT MDPQueryColumnInfo(ICommandText *pICommandText, pwszQuery)
{
HRESULT hr;
struct COLUMNDATA
{
SDWORD 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
ULONG cAxis;
MDAXISINFO* rgAxisInfo = NULL;
hr = pIMDDataset->GetAxisInfo( &cAxis, &rgAxisInfo );
for (ULONG iAxis=0; iAxis < cAxis; iAxis++)
{
// rgAxisInfo contains the array of dimensions for each axis
for (ULONG iDim=0; iDim <
rgAxisInfo[iAxis].cDimensions; iDim++)
{
// rgAxisInfo[iAxis].rgpwszDimensionNames points
// to the dimension name
assert(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);
ULONG 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, skip DBTYPE_VECTOR
// type columns
ULONG dwOffset = 0;
ULONG iBind = 0;
ULONG cBind = 0;
DBBINDING* rgBind = (DBBINDING*)CoTaskMemAlloc(
cCol*sizeof(DBBINDING));
for (ULONG 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.
ULONG 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
ULONG cRowsObtained;
hr = pIRowset->GetNextRows(NULL, 0, 20, &cRowsObtained, &pRows);
// break on EndOfRowset
if (cRowsObtained == 0) break;
for (ULONG 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;
}