home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 32 / IOPROG_32.ISO / SOFT / SqlEval7 / MSOLAP / samples / Samples.exe / CppOlapDemo / OLAPTab.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-10-30  |  47.7 KB  |  1,414 lines

  1. //-----------------------------------------------------------------------------
  2. // Microsoft OLE DB QLAPDEMO Sample
  3. // Copyright (C) 1995-1998 Microsoft Corporation
  4. //
  5. // File: OLAPTab.cpp
  6. //
  7. // This file implements the class OLAPTab.
  8. //
  9. //-----------------------------------------------------------------------------
  10.  
  11. #include "OLAP.h"
  12.  
  13. /////////////////////////////////////////////////////////////////////////////////////
  14. OLAPTab::OLAPTab( LPTSTR  pFormat, TCHAR  tDelimeter )
  15.  
  16. // Constructor for the OLAPTab
  17. /////////////////////////////////////////////////////////////////////////////////////
  18. {
  19.     m_tDelimeter = tDelimeter;
  20.     m_cColumns   = Set(pFormat);
  21. }
  22.  
  23. /////////////////////////////////////////////////////////////////////////////////////
  24. OLAPTab::~OLAPTab()
  25.  
  26. // Destructor for the OLAPTab
  27. /////////////////////////////////////////////////////////////////////////////////////
  28. {
  29. }
  30.  
  31. //////////////////////////////////////////////////////////////////////////////////////
  32. LONG     OLAPTab::First( TCHAR*  string, TCHAR**  text, TCHAR**  next )
  33.  
  34. // 
  35. //////////////////////////////////////////////////////////////////////////////////////
  36. {
  37.     assert ( string && text && next );
  38.  
  39.     *text = string;
  40.     *next = _tcschr( *text, m_tDelimeter );
  41.  
  42.     if ( *next ) *(*next) = 0;
  43.     
  44.     return (*next) ? *next - *text : _tcslen(*text);
  45. }
  46.  
  47.  
  48. //////////////////////////////////////////////////////////////////////////////////////
  49. LONG     OLAPTab::Next( TCHAR**  text, TCHAR**  next )
  50.  
  51. // 
  52. //////////////////////////////////////////////////////////////////////////////////////
  53. {
  54.     assert ( text && next );
  55.  
  56.     LONG  length;
  57.  
  58.     if ( *next ) {
  59.         *text = *next + 1;
  60.         *next = _tcschr( *text, m_tDelimeter );
  61.  
  62.         if ( *next ) {
  63.             *(*next) = 0;
  64.             length   = *next - *text;
  65.         }
  66.         else {
  67.             length = _tcslen(*text);
  68.         }
  69.     }
  70.     else {
  71.         length = 0;
  72.     }
  73.     return length;
  74. }
  75.  
  76.  
  77. /////////////////////////////////////////////////////////////////////////////////////
  78. LONG  OLAPTab::Set( LPTSTR  tstrFormat )
  79.  
  80. // Set the format for output
  81. /////////////////////////////////////////////////////////////////////////////////////
  82. {
  83.     m_cColumns   = 0;
  84.  
  85.     memset( m_pColumnLen, 0, sizeof(m_pColumnLen) );
  86.     memset( m_pColumnStr, 0, sizeof(m_pColumnStr) );
  87.  
  88.     if ( tstrFormat ) {
  89.         _tcsncpy( m_pColumnBuffer, tstrFormat, OLAP_APP_MAX_STRING_LEN );
  90.         m_pColumnBuffer[OLAP_APP_MAX_STRING_LEN-1] = 0;
  91.  
  92.         TCHAR*  pText;
  93.         TCHAR*  pNext;
  94.         LONG    lLength = First( m_pColumnBuffer, &pText, &pNext );
  95.  
  96.         for ( LONG  i = 0; i < OLAP_APP_MAX_COLUMNS; i++ ) {
  97.             if ( !lLength ) break;
  98.  
  99.             m_pColumnLen[m_cColumns] = lLength;
  100.             m_pColumnStr[m_cColumns] = pText;
  101.             m_cColumns++;
  102.  
  103.             lLength = Next( &pText, &pNext );
  104.         }
  105.     }
  106.     return m_cColumns;
  107. }
  108.  
  109.  
  110.  
  111. /////////////////////////////////////////////////////////////////////////////////////
  112. HRESULT     OLAPTab::PrintPropertiesInfo( IDBCreateSession*  pIDBSource, DWORD  dwFlags )
  113.  
  114. // Print session properties.
  115. /////////////////////////////////////////////////////////////////////////////////////
  116. {
  117.     if ( !pIDBSource ) return E_FAIL;
  118.  
  119.     IDBProperties*  pIDBProperties = NULL;
  120.  
  121.     DBPROPIDSET        rgPropertyIDSets[1];
  122.     ULONG             cPropertyInfoSets  = 0, i, j, k;
  123.     DBPROPINFOSET*    rgPropertyInfoSets = NULL;
  124.     OLECHAR*        pDescBuffer        = NULL; 
  125.  
  126.     // Get propirties interface
  127.     HRESULT hr = pIDBSource->QueryInterface( IID_IDBProperties, (void**) &pIDBProperties );
  128.     if ( FAILED(hr) || !pIDBProperties ) 
  129.         goto CLEANUP;
  130.  
  131.     // Get propirties info
  132.     hr = pIDBProperties->GetPropertyInfo( 0, 
  133.                                           rgPropertyIDSets, 
  134.                                           &cPropertyInfoSets,
  135.                                           &rgPropertyInfoSets,
  136.                                           &pDescBuffer );
  137.     if ( FAILED(hr) || !cPropertyInfoSets ) 
  138.         goto CLEANUP;
  139.  
  140.     _tprintf( TEXT("\n") );
  141.     PrintColumnCaption( 0, 45, TEXT("Description") );
  142.     PrintColumnCaption( 1, 25, TEXT("Group") );
  143.     PrintColumnCaption( 2, 12, TEXT("Type") );
  144.     PrintColumnCaption( 3, OLAP_APP_MAX_COLUMN_STR, TEXT("Value") );
  145.  
  146.     _tprintf( TEXT("\n") );
  147.     PrintColumnDelimiter( 0, 11);
  148.     PrintColumnDelimiter( 1, 5 );
  149.     PrintColumnDelimiter( 2, 4 );
  150.     PrintColumnDelimiter( 3, 5 );
  151.  
  152.     for ( i = 0; i < cPropertyInfoSets; i++ ) {
  153.         for ( j = 0, k = 0; j < rgPropertyInfoSets[i].cPropertyInfos; j++ ) {
  154.             if ( !(rgPropertyInfoSets[i].rgPropertyInfos[j].dwFlags & dwFlags) ) 
  155.                 continue;
  156.  
  157.             k++;
  158.  
  159.             _tprintf( TEXT("\n") );
  160.             PrintColumnString( 0, rgPropertyInfoSets[i].rgPropertyInfos[j].pwszDescription );
  161.  
  162.  
  163.             if ( rgPropertyInfoSets[i].rgPropertyInfos[j].dwFlags & DBPROPFLAGS_NOTSUPPORTED ) {
  164.                 PrintColumnString( 1, TEXT("Not Supported") );
  165.             }
  166.             else if ( rgPropertyInfoSets[i].rgPropertyInfos[j].dwFlags & DBPROPFLAGS_COLUMN ) {
  167.                 PrintColumnString( 1, TEXT("Column") );
  168.             }
  169.             else if ( rgPropertyInfoSets[i].rgPropertyInfos[j].dwFlags & DBPROPFLAGS_DATASOURCE ) {
  170.                 PrintColumnString( 1, TEXT("Data Source") );
  171.             }
  172.             else if ( rgPropertyInfoSets[i].rgPropertyInfos[j].dwFlags & DBPROPFLAGS_DATASOURCECREATE ) {
  173.                 PrintColumnString( 1, TEXT("Data Source Creation") );
  174.             }
  175.             else if ( rgPropertyInfoSets[i].rgPropertyInfos[j].dwFlags & DBPROPFLAGS_DATASOURCEINFO ) {
  176.                 PrintColumnString( 1, TEXT("Data Source Information") );
  177.             }
  178.             else if ( rgPropertyInfoSets[i].rgPropertyInfos[j].dwFlags & DBPROPFLAGS_DBINIT ) {
  179.                 PrintColumnString( 1, TEXT("Initialization") );
  180.             }
  181.             else if ( rgPropertyInfoSets[i].rgPropertyInfos[j].dwFlags & DBPROPFLAGS_INDEX ) {
  182.                 PrintColumnString( 1, TEXT("Index") );
  183.             }
  184.             else if ( (rgPropertyInfoSets[i].rgPropertyInfos[j].dwFlags & DBPROPFLAGS_ROWSET)   && 
  185.                       (rgPropertyInfoSets[i].rgPropertyInfos[j].dwFlags & DBPROPFLAGS_COLUMNOK)  ) {
  186.                 PrintColumnString( 1, TEXT("Rowset & Column OK") );
  187.             }
  188.             else if ( rgPropertyInfoSets[i].rgPropertyInfos[j].dwFlags & DBPROPFLAGS_ROWSET ) {
  189.                 PrintColumnString( 1, TEXT("Rowset") );
  190.             }
  191.             else if ( rgPropertyInfoSets[i].rgPropertyInfos[j].dwFlags & DBPROPFLAGS_SESSION ) {
  192.                 PrintColumnString( 1, TEXT("Session") );
  193.             }
  194.             else if ( rgPropertyInfoSets[i].rgPropertyInfos[j].dwFlags & DBPROPFLAGS_TABLE ) {
  195.                 PrintColumnString( 1, TEXT("Table") );
  196.             }
  197.  
  198.  
  199.             if ( (rgPropertyInfoSets[i].rgPropertyInfos[j].dwFlags & DBPROPFLAGS_READ)  &&
  200.                  (rgPropertyInfoSets[i].rgPropertyInfos[j].dwFlags & DBPROPFLAGS_WRITE)  ) {
  201.                 PrintColumnString( 2, TEXT("Read/Write") );
  202.             }
  203.             else if ( rgPropertyInfoSets[i].rgPropertyInfos[j].dwFlags & DBPROPFLAGS_READ ) {
  204.                 PrintColumnString( 2, TEXT("Read") );
  205.             }
  206.             else if ( rgPropertyInfoSets[i].rgPropertyInfos[j].dwFlags & DBPROPFLAGS_WRITE ) {
  207.                 PrintColumnString( 2, TEXT("Write") );
  208.             }
  209.             if ( rgPropertyInfoSets[i].rgPropertyInfos[j].dwFlags & DBPROPFLAGS_REQUIRED ) {
  210.                 PrintColumnString( 2, TEXT("Required") );
  211.             }
  212.  
  213.             DBPROPIDSET        rgPropertyIDSets[1];
  214.             ULONG            cPropertySets  = 0;
  215.             DBPROPSET*        rgPropertySets = NULL;
  216.  
  217.             rgPropertyIDSets[0].rgPropertyIDs   = &rgPropertyInfoSets[i].rgPropertyInfos[j].dwPropertyID;
  218.             rgPropertyIDSets[0].cPropertyIDs    = 1;
  219.             rgPropertyIDSets[0].guidPropertySet = rgPropertyInfoSets[i].guidPropertySet;
  220.  
  221.  
  222.             // Get property value.
  223.             hr = pIDBProperties->GetProperties ( 1, 
  224.                                                  rgPropertyIDSets,
  225.                                                  &cPropertySets,
  226.                                                  &rgPropertySets );
  227.  
  228.  
  229.             if ( FAILED(hr) || !cPropertySets || !rgPropertySets[0].cProperties ) 
  230.                 continue;
  231.  
  232.             PrintColumnVariant( 3 ,&rgPropertySets[0].rgProperties[0].vValue );
  233.  
  234.             // Clean property data.
  235.             if ( rgPropertySets ) {
  236.                 VariantClear( &rgPropertySets[0].rgProperties[0].vValue );
  237.                 CoTaskMemFree(rgPropertySets[0].rgProperties);
  238.                 CoTaskMemFree(rgPropertySets);
  239.             }
  240.         }
  241.         // Clean info data.
  242.         if ( rgPropertyInfoSets[i].rgPropertyInfos ) 
  243.             CoTaskMemFree(rgPropertyInfoSets[i].rgPropertyInfos);
  244.  
  245.         if ( k ) _tprintf( TEXT("\n") );
  246.     }
  247.  
  248. CLEANUP:
  249.     if ( rgPropertyInfoSets ) CoTaskMemFree(rgPropertyInfoSets);
  250.     if ( pDescBuffer        ) CoTaskMemFree(pDescBuffer);
  251.  
  252.     if ( pIDBProperties ) pIDBProperties->Release();
  253.  
  254.  
  255.     return S_OK;
  256. }
  257.  
  258.  
  259. /////////////////////////////////////////////////////////////////////////////////////
  260. HRESULT     OLAPTab::PrintSchemaRowset( IDBCreateCommand*  pIDBSession, LPTSTR  pSchema, GUID*  pGuid )
  261.  
  262. // Print schema.
  263. /////////////////////////////////////////////////////////////////////////////////////
  264. {
  265.     if ( !pIDBSession ) return E_FAIL;
  266.  
  267.     static struct Info {
  268.         const GUID*   pGuid;
  269.         const TCHAR*  pName;
  270.         const TCHAR*  pShortName;
  271.     } rgInfo[] = {
  272.         { &DBSCHEMA_CATALOGS,     TEXT("Catalogs"),    TEXT("C")   },
  273.         { &DBSCHEMA_SCHEMATA,     TEXT("Schemas"),     TEXT("S")   },
  274.         { &MDSCHEMA_CUBES,         TEXT("Cubes"),       TEXT("Cub") },
  275.         { &MDSCHEMA_MEASURES,     TEXT("Measures"),    TEXT("M")   },
  276.         { &MDSCHEMA_DIMENSIONS,     TEXT("Dimensions"),  TEXT("Dim") },
  277.         { &MDSCHEMA_HIERARCHIES, TEXT("Hierarchies"), TEXT("H")   },
  278.         { &MDSCHEMA_LEVELS,         TEXT("Levels"),      TEXT("L")   },
  279.         { &MDSCHEMA_PROPERTIES,     TEXT("Properties"),  TEXT("P")   },
  280.         { &MDSCHEMA_MEMBERS,     TEXT("Members"),     TEXT("Mem") },
  281.     };
  282.  
  283.     ULONG  i;
  284.  
  285.     if ( !pGuid && pSchema ) {
  286.         for ( i = 0; i < NUMELEM(rgInfo); i++ ) {
  287.             if ( !OLAP_strcmp(rgInfo[i].pName,OLAP_ALL,pSchema,OLAP_ALL)     ||
  288.                  !OLAP_strcmp(rgInfo[i].pShortName,OLAP_ALL,pSchema,OLAP_ALL) ) {
  289.                 pGuid = (GUID*) rgInfo[i].pGuid;
  290.                 break;
  291.             }
  292.         }
  293.     }
  294.     if ( !pGuid ) pGuid = (GUID*) rgInfo[0].pGuid;
  295.  
  296.     // Check if this supported.
  297.     IDBSchemaRowset*  pIDBSchemaRowset    = NULL;
  298.     IRowset*          pIRowset            = NULL;
  299.  
  300.     ULONG             cSchemas;
  301.     GUID*             pSchemaGuids         = NULL;
  302.     ULONG*            rgRestrictionSupport = NULL;
  303.  
  304.     // Get Schema interface
  305.     HRESULT     hr = pIDBSession->QueryInterface( IID_IDBSchemaRowset, (void**) &pIDBSchemaRowset );
  306.     if ( FAILED(hr) || !pIDBSchemaRowset ) 
  307.         goto CLEANUP;
  308.  
  309.     hr = pIDBSchemaRowset->GetSchemas( &cSchemas, &pSchemaGuids, &rgRestrictionSupport );
  310.     if ( FAILED(hr) && !cSchemas ) 
  311.         goto CLEANUP;
  312.  
  313.     for ( i = 0; i < cSchemas; i++ ) {
  314.         if ( *pGuid == pSchemaGuids[i] )
  315.             break;
  316.     }
  317.     if ( i == cSchemas ) 
  318.         goto CLEANUP;
  319.  
  320.  
  321.     // Get rowset
  322.     hr = pIDBSchemaRowset->GetRowset( NULL,
  323.                                       *pGuid,
  324.                                       0,                // cRestrictions
  325.                                       NULL,                // rgRestrictions
  326.                                       IID_IRowset,
  327.                                       0,                // cPropertySets
  328.                                       NULL,                // rgPropertySets,
  329.                                       (IUnknown**) &pIRowset );
  330.     if ( FAILED(hr) || !pIRowset ) 
  331.         goto CLEANUP;
  332.  
  333.     PrintRowset( pIRowset );
  334.  
  335.     CLEANUP:
  336.     if ( pSchemaGuids         ) CoTaskMemFree(pSchemaGuids);
  337.     if ( rgRestrictionSupport ) CoTaskMemFree(rgRestrictionSupport);
  338.  
  339.     if ( pIDBSchemaRowset ) pIDBSchemaRowset->Release();
  340.     if ( pIRowset         ) pIRowset->Release();        
  341.  
  342.     return hr;
  343. }
  344.  
  345.  
  346. /////////////////////////////////////////////////////////////////////////////////////
  347. HRESULT     OLAPTab::PrintAxisRowset( IMDDataset*  pIMDDataset, LONG  iAxis, LPTSTR  pAxis )
  348.  
  349. // Print schema.
  350. /////////////////////////////////////////////////////////////////////////////////////
  351. {
  352.     if ( !pIMDDataset ) return E_FAIL;
  353.  
  354.     static struct Info {
  355.               LONG    iAxis;
  356.         const TCHAR*  pName;
  357.         const TCHAR*  pShortName;
  358.     } rgInfo[] = {
  359.         { 0, TEXT("Columns"), TEXT("0") },
  360.         { 1, TEXT("Rows"),    TEXT("1") },
  361.         { 2, TEXT("Pages"),   TEXT("2") },
  362.         { 3, TEXT("3"),       TEXT("3") },
  363.         { 4, TEXT("4"),       TEXT("4") },
  364.         { 5, TEXT("5"),       TEXT("5") },
  365.         { 6, TEXT("6"),       TEXT("6") },
  366.         { 7, TEXT("7"),       TEXT("7") },
  367.     };
  368.  
  369.     ULONG  i;
  370.  
  371.     if ( iAxis < 0 && pAxis ) {
  372.         for ( i = 0; i < NUMELEM(rgInfo); i++ ) {
  373.             if ( !OLAP_strcmp(rgInfo[i].pName,OLAP_ALL,pAxis,OLAP_ALL)     ||
  374.                  !OLAP_strcmp(rgInfo[i].pShortName,OLAP_ALL,pAxis,OLAP_ALL) ) {
  375.                 iAxis = rgInfo[i].iAxis;
  376.                 break;
  377.             }
  378.         }
  379.     }
  380.  
  381.     // Get Axis info
  382.     ULONG        cAxis;
  383.     MDAXISINFO*  rgAxisInfo = NULL;
  384.  
  385.     IRowset*     pIRowset = NULL;
  386.  
  387.  
  388.     HRESULT  hr = pIMDDataset->GetAxisInfo( &cAxis, &rgAxisInfo );
  389.     if ( FAILED(hr) || !cAxis ) 
  390.         goto CLEANUP;
  391.  
  392.  
  393.     // Axis not exist in query result
  394.     if ( iAxis > 0 && iAxis >= (LONG) cAxis ) 
  395.         return S_OK;
  396.  
  397.     if ( iAxis < 0 ) {
  398.         // Print all
  399.         iAxis = 0;
  400.     }
  401.     else {
  402.         // Print one
  403.         cAxis = iAxis + 1;
  404.     }
  405.  
  406.     for ( ; iAxis < (LONG) cAxis; iAxis++ ) {
  407.         // Clean rowset.
  408.         if ( pIRowset ) { pIRowset->Release(); pIRowset = NULL; }
  409.  
  410.         // Get rowset
  411.         hr = pIMDDataset->GetAxisRowset( NULL,
  412.                                          iAxis,
  413.                                          IID_IRowset,
  414.                                          0,       
  415.                                          NULL, 
  416.                                          (IUnknown**) &pIRowset );
  417.         if ( FAILED(hr) || !pIRowset ) 
  418.             goto CLEANUP;
  419.  
  420.         PrintRowset( pIRowset );
  421.  
  422.         // Format will applay for first axis.
  423.         m_cColumns = 0;   
  424.     }
  425.  
  426.     CLEANUP:
  427.     if ( rgAxisInfo ) pIMDDataset->FreeAxisInfo( cAxis, rgAxisInfo );
  428.     if ( pIRowset   ) pIRowset->Release();        
  429.  
  430.     return hr;
  431. }
  432.  
  433.  
  434. /////////////////////////////////////////////////////////////////////////////////////
  435. BOOL     OLAPTab::PrintColumnCaption( LONG  iColumn, LONG  lLength, LPTSTR  pCaption )
  436.  
  437. // Init column length and caption.
  438. /////////////////////////////////////////////////////////////////////////////////////
  439. {
  440.     if ( !lLength ) m_pColumnLen[iColumn] = 0;
  441.  
  442.     if ( iColumn < m_cColumns && m_pColumnLen[iColumn] > 0 ) {
  443.         if ( m_pColumnStr[iColumn] && *m_pColumnStr[iColumn] ) {
  444.             if ( !_stscanf( m_pColumnStr[iColumn], _TEXT("%ld"), &m_pColumnLen[iColumn] ) ) {
  445.                 m_pColumnLen[iColumn] = 0;
  446.             }
  447.         }
  448.         else {
  449.             m_pColumnLen[iColumn] = 0;
  450.         }
  451.     }
  452.     else {
  453.         if ( !m_pColumnLen[iColumn] ) m_pColumnLen[iColumn] = lLength;
  454.     }
  455.     if ( !m_pColumnLen[iColumn] ) 
  456.         return FALSE;
  457.  
  458.     PrintColumnString( iColumn, pCaption );
  459.  
  460.     return TRUE;
  461. }
  462.  
  463. /////////////////////////////////////////////////////////////////////////////////////
  464. BOOL   OLAPTab::PrintColumnDelimiter( LONG  iColumn, LONG  lLength )
  465.  
  466. // Init column length and caption.
  467. /////////////////////////////////////////////////////////////////////////////////////
  468. {
  469.     if ( !m_pColumnLen[iColumn] ) return FALSE;
  470.  
  471.     TCHAR  pBuffer[OLAP_APP_MAX_COLUMN_STR + 1];
  472.  
  473.     if ( lLength > m_pColumnLen[iColumn] )
  474.         lLength = m_pColumnLen[iColumn];
  475.  
  476.     if ( lLength > OLAP_APP_MAX_COLUMN_STR )
  477.         lLength = OLAP_APP_MAX_COLUMN_STR;
  478.  
  479.     for ( LONG  i = 0; i < lLength; i++ )
  480.          pBuffer[i] = TEXT('-');
  481.     pBuffer[i] = 0;
  482.  
  483.     // Print caption delimiters
  484.     PrintColumnString( iColumn, pBuffer );
  485.  
  486.     return TRUE;
  487. }
  488.  
  489.  
  490. /////////////////////////////////////////////////////////////////////////////////////
  491. BOOL     OLAPTab::PrintColumnString( LONG  iColumn, LPTSTR  pString )
  492.  
  493. // Init column length and caption.
  494. /////////////////////////////////////////////////////////////////////////////////////
  495. {
  496.     if ( m_pColumnLen[iColumn] ) {
  497.         if ( pString ) _tprintf( TEXT("%-*s "), m_pColumnLen[iColumn], pString );
  498.         else           _tprintf( TEXT("%-*s "), m_pColumnLen[iColumn], TEXT(" ") );
  499.  
  500.         return TRUE;
  501.     }
  502.     return FALSE;
  503. }
  504.  
  505.  
  506. /////////////////////////////////////////////////////////////////////////////////////
  507. BOOL     OLAPTab::PrintColumnVariant( LONG  iColumn, VARIANT*  pData )
  508.  
  509. // Print session properties.
  510. /////////////////////////////////////////////////////////////////////////////////////
  511. {
  512.     if ( !m_pColumnLen[iColumn] ) 
  513.         return FALSE;
  514.  
  515.     if ( !pData ) {
  516.         _tprintf( TEXT("%-*s "), m_pColumnLen[iColumn], TEXT(" ") );
  517.         return TRUE;
  518.     }
  519.  
  520.     switch ( V_VT(pData) )  {
  521.     case VT_BSTR:    
  522.     case VT_LPSTR:
  523.     case VT_LPWSTR:
  524.     case VT_BSTR    | VT_BYREF:    
  525.     case VT_LPSTR    | VT_BYREF:
  526.     case VT_LPWSTR    | VT_BYREF:     PRINT_VB(TEXT("%-*s"),V_BSTR,pData);    break;
  527.     case VT_I1:                     
  528.     case VT_I1      | VT_BYREF:     PRINT_VB(TEXT("%-*d"),V_I1,pData);      break;
  529.     case VT_UI1:                     
  530.     case VT_UI1     | VT_BYREF:     PRINT_VB(TEXT("%-*d"),V_UI1,pData);     break;
  531.     case VT_I2:                     
  532.     case VT_I2      | VT_BYREF:     PRINT_VB(TEXT("%-*d"),V_I2,pData);      break;
  533.     case VT_UI2:                     
  534.     case VT_UI2     | VT_BYREF:     PRINT_VB(TEXT("%-*d"),V_UI2,pData);     break;
  535.     case VT_BOOL:
  536.         if ( V_BOOL(pData) != VARIANT_FALSE )
  537.             PrintColumnString( iColumn, TEXT("TRUE") );
  538.         else
  539.             PrintColumnString( iColumn, TEXT("FALSE") );
  540.         break;
  541.     case VT_BOOL    | VT_BYREF:
  542.         if ( *V_BOOLREF(pData) != VARIANT_FALSE )
  543.             PrintColumnString( iColumn, TEXT("TRUE") );
  544.         else
  545.             PrintColumnString( iColumn, TEXT("FALSE") );
  546.         break;
  547.     case VT_INT:                     
  548.     case VT_INT     | VT_BYREF:     PRINT_VB(TEXT("%-*ld"),V_INT,pData);   break;
  549.     case VT_UINT:                     
  550.     case VT_UINT    | VT_BYREF:     PRINT_VB(TEXT("%-*ld"),V_UINT,pData);  break;
  551.     case VT_I4:                     
  552.     case VT_I4      | VT_BYREF:     PRINT_VB(TEXT("%-*ld"),V_I4,pData);    break;
  553.     case VT_UI4:                     
  554.     case VT_UI4     | VT_BYREF:     PRINT_VB(TEXT("%-*ld"),V_UI4,pData);   break;
  555.     case VT_R4:
  556.     case VT_R4      | VT_BYREF:     PRINT_VB(TEXT("%-*f"),V_R4,pData);     break;
  557.     case VT_R8:
  558.     case VT_R8      | VT_BYREF:     PRINT_VB(TEXT("%-*f"),V_R8,pData);     break;
  559.     }
  560.     return TRUE;
  561. }
  562.  
  563.  
  564.  
  565. /////////////////////////////////////////////////////////////////////////////////////
  566. HRESULT     OLAPTab::PrintRowset( IRowset*  pIRowset )
  567.  
  568. // Print Rowset.
  569. /////////////////////////////////////////////////////////////////////////////////////
  570. {
  571.     if ( !pIRowset ) return E_FAIL;
  572.  
  573.     ULONG          iCol, cCol, iColumn, cColumn, iBind;
  574.     IColumnsInfo*  pIColumnsInfo  = NULL;
  575.     DBCOLUMNINFO*  pInfo          = NULL;
  576.     TCHAR*         pStringsBuffer = NULL;
  577.     IAccessor*     pIAccessor     = NULL;
  578.     COLUMNDATA*    pColumn        = NULL;
  579.  
  580.     DBBINDING      rgBind[OLAP_APP_MAX_BINDINGS + 1];
  581.     BYTE           pData[OLAP_APP_MAX_STRING_LEN + 1];
  582.     ULONG          dwLength, dwDesc, dwOffset = 0;
  583.  
  584.     HACCESSOR      hAccessor = DB_NULL_HACCESSOR;
  585.  
  586.     ULONG          cRowsObtained = 0;
  587.     HROW*          pRows = NULL;
  588.     ULONG          iRow;
  589.  
  590.  
  591.     // Get Column info.
  592.     HRESULT  hr = pIRowset->QueryInterface( IID_IColumnsInfo, (void**) &pIColumnsInfo );
  593.     if ( FAILED(hr) || !pIColumnsInfo ) 
  594.         goto CLEANUP;
  595.  
  596.     hr = pIColumnsInfo->GetColumnInfo( &cCol, 
  597.                                        &pInfo,
  598.                                        &pStringsBuffer );
  599.     if ( FAILED(hr) || !cCol ) 
  600.         goto CLEANUP;
  601.  
  602.     // Start table captions
  603.     _tprintf(TEXT("\n\n"));
  604.  
  605.     // Create bindings. Bind everything as string.
  606.     for ( iCol = 0, iBind = 0, iColumn = 0; iCol < cCol; iCol++ ) {
  607.         // Skip columns of type _VECTOR.
  608.         // Probably binary data.
  609.         if ( pInfo[iCol].wType & DBTYPE_VECTOR ) {
  610.             continue;
  611.         }
  612.  
  613.  
  614.         // correct for strings.
  615.         dwDesc = (pInfo[iCol].pwszName) ? _tcslen(pInfo[iCol].pwszName) : 0;
  616.  
  617.         if ( pInfo[iCol].wType == DBTYPE_STR ) {
  618.             dwLength = max(dwDesc, pInfo[iCol].ulColumnSize);
  619.         }
  620.         else if ( pInfo[iCol].wType == DBTYPE_WSTR ) {
  621.             dwLength = max(dwDesc, pInfo[iCol].ulColumnSize/sizeof(TCHAR));
  622.         }
  623.         else if ( pInfo[iCol].wType == DBTYPE_VARIANT ) {
  624.             dwLength = max(dwDesc, OLAP_APP_MIN_COLUMN_STR);
  625.         }
  626.         else {
  627.             dwLength = max(dwDesc, OLAP_APP_MIN_COLUMN_VAL);
  628.         }
  629.         if ( dwLength > OLAP_APP_MAX_COLUMN_STR ) dwLength = OLAP_APP_MAX_COLUMN_STR;
  630.         dwLength *= sizeof(TCHAR);
  631.  
  632.         // Print column caption.
  633.         if ( !PrintColumnCaption( iColumn++, dwLength/sizeof(TCHAR), pInfo[iCol].pwszName ) )
  634.             continue;
  635.  
  636.         rgBind[iBind].iOrdinal   = pInfo[iCol].iOrdinal;
  637.         rgBind[iBind].obValue    = dwOffset + offsetof(COLUMNDATA,bData);
  638.         rgBind[iBind].obLength   = dwOffset + offsetof(COLUMNDATA,dwLength);
  639.         rgBind[iBind].obStatus   = dwOffset + offsetof(COLUMNDATA,dwStatus);
  640.         rgBind[iBind].pTypeInfo  = NULL;
  641.         rgBind[iBind].pObject    = NULL;
  642.         rgBind[iBind].pBindExt   = NULL;
  643.         rgBind[iBind].dwFlags    = 0;
  644.         rgBind[iBind].eParamIO   = DBPARAMIO_NOTPARAM;
  645.         rgBind[iBind].dwPart     = DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS;
  646.         rgBind[iBind].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
  647.         rgBind[iBind].bPrecision = 0;
  648.         rgBind[iBind].bScale     = 0;
  649.  
  650.         rgBind[iBind].cbMaxLen   = (m_pColumnLen[iColumn-1] + 1)*sizeof(TCHAR);
  651.         rgBind[iBind].wType      = DBTYPE_WSTR;
  652.  
  653.         // Keep our limits
  654.         if ( dwOffset + dwLength + offsetof(COLUMNDATA,bData) > OLAP_APP_MAX_STRING_LEN || 
  655.              iColumn == OLAP_APP_MAX_BINDINGS )
  656.             break;
  657.  
  658.         dwOffset += rgBind[iBind].cbMaxLen + offsetof(COLUMNDATA,bData);
  659.         dwOffset = ROUND_UP( dwOffset, COLUMN_ALIGNVAL );
  660.         iBind++;
  661.     }
  662.     cColumn = iColumn;
  663.  
  664.  
  665.     // Print caption delimiters
  666.     _tprintf(TEXT("\n"));
  667.  
  668.     for ( iCol = 0, iColumn = 0; iCol < cCol && iColumn < cColumn; iCol++ ) {
  669.         // Skip columns of type _VECTOR.
  670.         // Probably binary data.
  671.         if ( (pInfo[iCol].wType & DBTYPE_VECTOR) || !m_pColumnLen[iColumn++] ) {
  672.             continue;
  673.         }
  674.  
  675.         // Print caption delimiters
  676.         PrintColumnDelimiter( iColumn-1, (pInfo[iCol].pwszName) ? _tcslen(pInfo[iCol].pwszName) : rgBind[iBind].cbMaxLen/sizeof(TCHAR) );
  677.     }
  678.  
  679.     // Create the accessor.
  680.     hr = pIRowset->QueryInterface( IID_IAccessor, (void**) &pIAccessor );
  681.     if ( FAILED(hr) || !pIAccessor )
  682.         goto CLEANUP;
  683.  
  684.     hr = pIAccessor->CreateAccessor( DBACCESSOR_ROWDATA, iBind, rgBind, dwOffset, &hAccessor, NULL );
  685.     if ( FAILED(hr) )
  686.         goto CLEANUP;
  687.  
  688.     while( SUCCEEDED(hr) ) {
  689.         // Prepare internal buffers and get handles to the rows.
  690.         hr = pIRowset->GetNextRows( NULL,                // hChapter
  691.                                     0,                    // cRowsToSkip
  692.                                     NUMROWS_CHUNK,        // cRowsDesired
  693.                                     &cRowsObtained,
  694.                                     &pRows );            // filled in w/ row handles
  695.         if ( FAILED(hr) || !cRowsObtained || !pRows )
  696.             break;
  697.  
  698.         for ( iRow = 0; iRow < cRowsObtained; iRow++ ) {
  699.             // Populate our row buffer.
  700.             hr = pIRowset->GetData( pRows[iRow],
  701.                                     hAccessor,
  702.                                     pData );
  703.             if ( FAILED(hr) )
  704.                 break;
  705.  
  706.             // Print each column we're bound to.
  707.             _tprintf(TEXT("\n"));
  708.  
  709.             for ( iCol = 0, iBind = 0, iColumn = 0; iCol < cCol && iColumn < cColumn; iCol++ ) {
  710.                 // Limit to first dwLength characters.
  711.                 if ( (pInfo[iCol].wType & DBTYPE_VECTOR) || !m_pColumnLen[iColumn++] ) {
  712.                     continue;
  713.                 }
  714.  
  715.                 pColumn = (COLUMNDATA*) (pData + rgBind[iBind++].obLength);
  716.  
  717.                 if ( pColumn->dwStatus == DBSTATUS_S_ISNULL ) {
  718.                     PrintColumnString(iColumn-1,TEXT("<null>"));
  719.                 }
  720.                 else if ( pColumn->dwStatus != DBSTATUS_S_OK       && 
  721.                           pColumn->dwStatus != DBSTATUS_S_TRUNCATED ) {
  722.                     PrintColumnString(iColumn-1,TEXT("<error>"));
  723.                 }
  724.                 else {
  725.                     PrintColumnString(iColumn-1,(LPTSTR) pColumn->bData);
  726.                 }
  727.             }
  728.         }
  729.         pIRowset->ReleaseRows( cRowsObtained, pRows, NULL, NULL, NULL );
  730.         cRowsObtained = 0;
  731.     }
  732.  
  733.     CLEANUP:
  734.     if ( pRows ) CoTaskMemFree(pRows);
  735.     if ( pInfo ) CoTaskMemFree(pInfo);
  736.  
  737.     if ( pStringsBuffer ) CoTaskMemFree(pStringsBuffer);
  738.  
  739.     if ( cRowsObtained  ) pIRowset->ReleaseRows( cRowsObtained, pRows, NULL, NULL, NULL );
  740.  
  741.     if ( hAccessor != DB_NULL_HACCESSOR ) pIAccessor->ReleaseAccessor( hAccessor, NULL );
  742.  
  743.     if ( pIColumnsInfo )  pIColumnsInfo->Release();
  744.     if ( pIAccessor    )  pIAccessor->Release();
  745.  
  746.     return hr;
  747. }
  748.  
  749.  
  750. ///////////////////////////////////////////////////////////////////////////////
  751. HRESULT     OLAPTab::PrintDataset( IMDDataset*  pIMDDataset )
  752.  
  753. // Print Dataset.
  754. ///////////////////////////////////////////////////////////////////////////////
  755. {
  756.     if ( !pIMDDataset ) return E_FAIL;
  757.  
  758.     ULONG          iCell, cCell;
  759.     ULONG           iAxis, cAxis;
  760.     ULONG          iCol, cCol, iColumn, cColumn, iBind;
  761.  
  762.     MDAXISINFO*    rgAxisInfo     = NULL;
  763.  
  764.     IColumnsInfo*  pIColumnsInfo  = NULL;
  765.  
  766.     DBCOLUMNINFO*  pInfo          = NULL;
  767.     TCHAR*         pStringsBuffer = NULL;
  768.     IAccessor*     pIAccessor     = NULL;
  769.     COLUMNDATA*    pColumn        = NULL;
  770.  
  771.  
  772.     DBBINDING      rgBind[OLAP_APP_MAX_BINDINGS + 1];
  773.     BYTE           pData[OLAP_APP_MAX_STRING_LEN + 1];
  774.     ULONG          dwLength, dwDesc, dwOffset = 0;
  775.  
  776.     HACCESSOR      hAccessor = DB_NULL_HACCESSOR;
  777.  
  778.  
  779.     HRESULT  hr = pIMDDataset->GetAxisInfo( &cAxis, &rgAxisInfo );
  780.     if ( FAILED(hr) || !cAxis ) 
  781.         goto CLEANUP;
  782.  
  783.     // Calculate the total number of cells in this cellset
  784.     for ( iAxis = 0, cCell = 1; iAxis < cAxis; iAxis++ ) {
  785.         cCell *= MDAXISINFO_GETAT(rgAxisInfo,iAxis).cCoordinates;
  786.     }
  787.     if ( !cCell ) return S_OK;
  788.  
  789.  
  790.  
  791.     // Get Column info.
  792.     hr = pIMDDataset->QueryInterface( IID_IColumnsInfo, (void**) &pIColumnsInfo );
  793.     if ( FAILED(hr) || !pIColumnsInfo ) 
  794.         goto CLEANUP;
  795.  
  796.     hr = pIColumnsInfo->GetColumnInfo( &cCol, 
  797.                                        &pInfo,
  798.                                        &pStringsBuffer );
  799.     if ( FAILED(hr) || !cCol ) 
  800.         goto CLEANUP;
  801.  
  802.     // Start table captions
  803.     _tprintf(TEXT("\n\n"));
  804.  
  805.     // Create bindings. Bind everything as string.
  806.     for ( iCol = 0, iBind = 0, iColumn = 0; iCol < cCol; iCol++ ) {
  807.         // Skip columns of type _VECTOR.
  808.         // Probably binary data.
  809.         if ( pInfo[iCol].wType & DBTYPE_VECTOR ) {
  810.             continue;
  811.         }
  812.  
  813.         // correct for strings.
  814.         dwDesc = (pInfo[iCol].pwszName) ? _tcslen(pInfo[iCol].pwszName) : 0;
  815.  
  816.         if ( pInfo[iCol].wType == DBTYPE_STR ) {
  817.             dwLength = max(dwDesc, pInfo[iCol].ulColumnSize);
  818.         }
  819.         else if ( pInfo[iCol].wType == DBTYPE_WSTR ) {
  820.             dwLength = max(dwDesc, pInfo[iCol].ulColumnSize/sizeof(TCHAR));
  821.         }
  822.         else if ( pInfo[iCol].wType == DBTYPE_VARIANT ) {
  823.             dwLength = max(dwDesc, OLAP_APP_MIN_COLUMN_STR);
  824.         }
  825.         else {
  826.             dwLength = max(dwDesc, OLAP_APP_MIN_COLUMN_VAL);
  827.         }
  828.         if ( dwLength > OLAP_APP_MAX_COLUMN_STR ) dwLength = OLAP_APP_MAX_COLUMN_STR;
  829.         dwLength *= sizeof(TCHAR);
  830.  
  831.  
  832.         // Print column caption.
  833.         if ( !PrintColumnCaption( iColumn++, dwLength/sizeof(TCHAR), pInfo[iCol].pwszName ) )
  834.             continue;
  835.  
  836.         rgBind[iBind].iOrdinal   = pInfo[iCol].iOrdinal;
  837.         rgBind[iBind].obValue    = dwOffset + offsetof(COLUMNDATA,bData);
  838.         rgBind[iBind].obLength   = dwOffset + offsetof(COLUMNDATA,dwLength);
  839.         rgBind[iBind].obStatus   = dwOffset + offsetof(COLUMNDATA,dwStatus);
  840.         rgBind[iBind].pTypeInfo  = NULL;
  841.         rgBind[iBind].pObject    = NULL;
  842.         rgBind[iBind].pBindExt   = NULL;
  843.         rgBind[iBind].dwFlags    = 0;
  844.         rgBind[iBind].eParamIO   = DBPARAMIO_NOTPARAM;
  845.         rgBind[iBind].dwPart     = DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS;
  846.         rgBind[iBind].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
  847.         rgBind[iBind].bPrecision = 0;
  848.         rgBind[iBind].bScale     = 0;
  849.  
  850.         rgBind[iBind].cbMaxLen   = (m_pColumnLen[iColumn-1] + 1)*sizeof(TCHAR);
  851.         rgBind[iBind].wType      = DBTYPE_WSTR;
  852.  
  853.         // Keep our limits
  854.         if ( dwOffset + dwLength + offsetof(COLUMNDATA,bData) > OLAP_APP_MAX_STRING_LEN || 
  855.              iColumn == OLAP_APP_MAX_BINDINGS )
  856.             break;
  857.  
  858.         dwOffset += rgBind[iBind].cbMaxLen + offsetof(COLUMNDATA,bData);
  859.         dwOffset = ROUND_UP( dwOffset, COLUMN_ALIGNVAL );
  860.         iBind++;
  861.     }
  862.     cColumn = iColumn;
  863.  
  864.  
  865.     // Print caption delimiters
  866.     _tprintf(TEXT("\n"));
  867.  
  868.     for ( iCol = 0, iColumn = 0; iCol < cCol && iColumn < cColumn; iCol++ ) {
  869.         // Skip columns of type _VECTOR.
  870.         // Probably binary data.
  871.         if ( (pInfo[iCol].wType & DBTYPE_VECTOR) || !m_pColumnLen[iColumn++] ) {
  872.             continue;
  873.         }
  874.  
  875.         // Print caption delimiters
  876.         PrintColumnDelimiter( iColumn-1, (pInfo[iCol].pwszName) ? _tcslen(pInfo[iCol].pwszName) : rgBind[iBind].cbMaxLen/sizeof(TCHAR) );
  877.     }
  878.  
  879.     // Create the accessor.
  880.     hr = pIMDDataset->QueryInterface( IID_IAccessor, (void**) &pIAccessor );
  881.     if ( FAILED(hr) || !pIAccessor )
  882.         goto CLEANUP;
  883.  
  884.     hr = pIAccessor->CreateAccessor( DBACCESSOR_ROWDATA, iBind, rgBind, dwOffset, &hAccessor, NULL );
  885.     if ( FAILED(hr) )
  886.         goto CLEANUP;
  887.  
  888.  
  889.     // Prepare internal buffers and get handles to the rows.
  890.     for ( iCell = 0; iCell < cCell; iCell++) {
  891.         // Populate Cell buffer.
  892.         hr = pIMDDataset->GetCellData( hAccessor,
  893.                                        iCell,
  894.                                        iCell,
  895.                                        pData );
  896.         if ( FAILED(hr) )
  897.             break;
  898.  
  899.         // Print each column we're bound to.
  900.         _tprintf(TEXT("\n"));
  901.  
  902.         for ( iCol = 0, iBind = 0, iColumn = 0; iCol < cCol && iColumn < cColumn; iCol++ ) {
  903.             // Limit to first dwLength characters.
  904.             if ( (pInfo[iCol].wType & DBTYPE_VECTOR) || !m_pColumnLen[iColumn++] ) {
  905.                 continue;
  906.             }
  907.  
  908.             pColumn = (COLUMNDATA*) (pData + rgBind[iBind++].obLength);
  909.  
  910.             if ( pColumn->dwStatus == DBSTATUS_S_ISNULL ) {
  911.                 PrintColumnString(iColumn-1,TEXT("<null>"));
  912.             }
  913.             else if ( pColumn->dwStatus != DBSTATUS_S_OK       && 
  914.                       pColumn->dwStatus != DBSTATUS_S_TRUNCATED ) {
  915.                 PrintColumnString(iColumn-1,TEXT("<error>"));
  916.             }
  917.             else {
  918.                 PrintColumnString(iColumn-1,(LPTSTR) pColumn->bData);
  919.             }
  920.         }
  921.     }
  922.  
  923.     CLEANUP:
  924.     if ( pInfo          ) CoTaskMemFree(pInfo);
  925.     if ( pStringsBuffer ) CoTaskMemFree(pStringsBuffer);
  926.  
  927.     if ( rgAxisInfo ) pIMDDataset->FreeAxisInfo( cAxis, rgAxisInfo );
  928.  
  929.     if ( hAccessor != DB_NULL_HACCESSOR ) pIAccessor->ReleaseAccessor( hAccessor, NULL );
  930.  
  931.     if ( pIColumnsInfo )  pIColumnsInfo->Release();
  932.     if ( pIAccessor    )  pIAccessor->Release();
  933.  
  934.     return hr;
  935. }
  936.  
  937.  
  938. /////////////////////////////////////////////////////////////////////////////////////
  939. HRESULT     OLAPTab::PrintQuery( IMDDataset*  pIMDDataset )
  940.  
  941. // Print 
  942. ///////////////////////////////////////////////////////////////////////////////
  943. {
  944.     if ( !pIMDDataset ) return E_FAIL;
  945.  
  946.     // Get Axis info
  947.     LONG         iAxis, cAxis, iAxisMove, iDim, cDim, iCol;
  948.     MDAXISINFO*  rgAxisInfo = NULL;
  949.  
  950.  
  951.     COLUMNDATA*  pColumn = NULL;
  952.  
  953.     DBBINDING    rgBind[OLAP_APP_MAX_BINDINGS + 1];
  954.     BYTE         pData[OLAP_APP_MAX_STRING_LEN + 1];
  955.     ULONG        dwOffset = 0;
  956.     ULONG        iBind;
  957.  
  958.     ULONG        iRowsIndex[OLAP_APP_MAX_BINDINGS + 1];
  959.     ULONG        cRowsObtained[OLAP_APP_MAX_BINDINGS + 1];
  960.     HROW*        pRows[OLAP_APP_MAX_BINDINGS + 1];
  961.     ULONG        iColumn, cColumn, iCell, cCell, iCells = 0;
  962.  
  963.     IAccessor*   pIAccessor[OLAP_APP_MAX_BINDINGS + 1];
  964.     IRowset*     pIRowset[OLAP_APP_MAX_BINDINGS + 1];
  965.     HACCESSOR    hAccessor[OLAP_APP_MAX_BINDINGS + 1];
  966.  
  967.  
  968.     // Init arrays
  969.     memset( pIAccessor, 0, sizeof(pIAccessor) );
  970.     memset( pIRowset, 0, sizeof(pIRowset) );
  971.  
  972.     memset( hAccessor, 0, sizeof(hAccessor) );
  973.  
  974.     memset( iRowsIndex, 0, sizeof(iRowsIndex) );
  975.     memset( cRowsObtained, 0, sizeof(cRowsObtained) );
  976.     memset( pRows, 0, sizeof(pRows) );
  977.  
  978.  
  979.  
  980.     HRESULT  hr = pIMDDataset->GetAxisInfo( (ULONG*) &cAxis, &rgAxisInfo );
  981.     if ( FAILED(hr) || !cAxis ) 
  982.         goto CLEANUP;
  983.  
  984.     // Print slice
  985.     iAxis = cAxis - 1;
  986.     cDim  = MDAXISINFO_GETAT(rgAxisInfo,iAxis).cDimensions;
  987.  
  988.     if ( cDim ) {
  989.         hr = pIMDDataset->GetAxisRowset( NULL,
  990.                                          iAxis,
  991.                                          IID_IRowset,
  992.                                          0,       
  993.                                          NULL, 
  994.                                          (IUnknown**) &pIRowset[iAxis] );
  995.         if ( FAILED(hr) || !pIRowset[iAxis] ) 
  996.             goto CLEANUP;
  997.  
  998.         for ( iDim = 0, iCol = 2, iBind = 0; iDim < cDim; iDim++ ) {
  999.             // correct for strings.
  1000.             rgBind[iBind].iOrdinal   = iCol;
  1001.             rgBind[iBind].obValue    = dwOffset + offsetof(COLUMNDATA,bData);
  1002.             rgBind[iBind].obLength   = dwOffset + offsetof(COLUMNDATA,dwLength);
  1003.             rgBind[iBind].obStatus   = dwOffset + offsetof(COLUMNDATA,dwStatus);
  1004.             rgBind[iBind].pTypeInfo  = NULL;
  1005.             rgBind[iBind].pObject    = NULL;
  1006.             rgBind[iBind].pBindExt   = NULL;
  1007.             rgBind[iBind].dwFlags    = 0;
  1008.             rgBind[iBind].eParamIO   = DBPARAMIO_NOTPARAM;
  1009.             rgBind[iBind].dwPart     = DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS;
  1010.             rgBind[iBind].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
  1011.             rgBind[iBind].bPrecision = 0;
  1012.             rgBind[iBind].bScale     = 0;
  1013.  
  1014.             rgBind[iBind].cbMaxLen   = OLAP_APP_MAX_COLUMN_STR*sizeof(TCHAR);
  1015.             rgBind[iBind].wType      = DBTYPE_WSTR;
  1016.  
  1017.             // Keep our limits
  1018.             if ( dwOffset + rgBind[iBind].cbMaxLen + offsetof(COLUMNDATA,bData) > OLAP_APP_MAX_STRING_LEN || 
  1019.                  iDim == OLAP_APP_MAX_BINDINGS )
  1020.                 break;
  1021.  
  1022.             dwOffset += rgBind[iBind].cbMaxLen + offsetof(COLUMNDATA,bData);
  1023.             dwOffset = ROUND_UP( dwOffset, COLUMN_ALIGNVAL );
  1024.             iBind++;
  1025.  
  1026.             // Move to first column of next dimension.
  1027.             iCol += MDAXISINFO_GETAT(rgAxisInfo,iAxis).rgcColumns[iDim];
  1028.         }
  1029.  
  1030.         // Create the accessor.
  1031.         hr = pIRowset[iAxis]->QueryInterface( IID_IAccessor, (void**) &pIAccessor[iAxis] );
  1032.         if ( FAILED(hr) || !pIAccessor[iAxis] )
  1033.             goto CLEANUP;
  1034.  
  1035.         hr = pIAccessor[iAxis]->CreateAccessor( DBACCESSOR_ROWDATA, iBind, rgBind, dwOffset, &hAccessor[iAxis], NULL );
  1036.         if ( FAILED(hr) )
  1037.             goto CLEANUP;
  1038.  
  1039.  
  1040.         // Prepare internal buffers and get handles to the rows.
  1041.         hr = pIRowset[iAxis]->GetNextRows( NULL,              // hChapter
  1042.                                            0,                  // cRowsToSkip
  1043.                                            1,                  // cRowsDesired
  1044.                                            &cRowsObtained[iAxis],
  1045.                                            &pRows[iAxis] );  // filled in w/ row handles
  1046.         if ( FAILED(hr) || !cRowsObtained[iAxis] || !pRows[iAxis] )
  1047.             goto CLEANUP;
  1048.  
  1049.         // Populate our row buffer.
  1050.         hr = pIRowset[iAxis]->GetData( pRows[iAxis][0],
  1051.                                        hAccessor[iAxis],
  1052.                                        pData );
  1053.         if ( FAILED(hr) )
  1054.             goto CLEANUP;
  1055.  
  1056.  
  1057.         for ( iDim = 0; iDim < cDim; iDim++ ) {
  1058.             // Print dimension name,
  1059.             _tprintf(TEXT("\n%-16s: "), MDAXISINFO_GETAT(rgAxisInfo,iAxis).rgpwszDimensionNames[iDim]);
  1060.  
  1061.             // Print member unique name.
  1062.             pColumn = (COLUMNDATA*) (pData + rgBind[iDim].obLength);
  1063.  
  1064.             if ( pColumn->dwStatus == DBSTATUS_S_ISNULL ) {
  1065.                 _tprintf(TEXT("<null>"));
  1066.             }
  1067.             else if ( pColumn->dwStatus != DBSTATUS_S_OK       && 
  1068.                       pColumn->dwStatus != DBSTATUS_S_TRUNCATED ) {
  1069.                 _tprintf(TEXT("<error>"));
  1070.             }
  1071.             else {
  1072.                 _tprintf(TEXT("%s"), (LPTSTR) pColumn->bData );
  1073.             }
  1074.         }
  1075.         pIRowset[iAxis]->ReleaseRows( cRowsObtained[iAxis], pRows[iAxis], NULL, NULL, NULL );
  1076.         pIAccessor[iAxis]->ReleaseAccessor( hAccessor[iAxis], NULL );
  1077.  
  1078.         if ( pRows[iAxis] ) CoTaskMemFree(pRows[iAxis]);
  1079.  
  1080.         cRowsObtained[iAxis] = 0;
  1081.         pRows[iAxis] = NULL;
  1082.  
  1083.         hAccessor[iAxis] = DB_NULL_HACCESSOR;
  1084.  
  1085.         pIRowset[iAxis]->Release();
  1086.         pIRowset[iAxis] = NULL;
  1087.  
  1088.         pIAccessor[iAxis]->Release();
  1089.         pIAccessor[iAxis] = NULL;
  1090.     }
  1091.  
  1092.  
  1093.     // Start table
  1094.     _tprintf( TEXT("\n\n") );
  1095.         
  1096.     // Bind axes
  1097.     for ( iAxis = cAxis - 2, iColumn = 0; iAxis >= 0; iAxis-- ) {
  1098.         // Get Axis schema
  1099.         cDim  = MDAXISINFO_GETAT(rgAxisInfo,iAxis).cDimensions;
  1100.  
  1101.         hr = pIMDDataset->GetAxisRowset( NULL,
  1102.                                          iAxis,
  1103.                                          IID_IRowset,
  1104.                                          0,       
  1105.                                          NULL, 
  1106.                                          (IUnknown**) &pIRowset[iAxis] );
  1107.         if ( FAILED(hr) || !pIRowset[iAxis] ) 
  1108.             goto CLEANUP;
  1109.  
  1110.         for ( iDim = 0, iCol = 3, iBind = 0, dwOffset = 0; iDim < cDim; iDim++ ) {
  1111.             // correct for strings.
  1112.             rgBind[iBind].iOrdinal   = iCol;
  1113.             rgBind[iBind].obValue    = dwOffset + offsetof(COLUMNDATA,bData);
  1114.             rgBind[iBind].obLength   = dwOffset + offsetof(COLUMNDATA,dwLength);
  1115.             rgBind[iBind].obStatus   = dwOffset + offsetof(COLUMNDATA,dwStatus);
  1116.             rgBind[iBind].pTypeInfo  = NULL;
  1117.             rgBind[iBind].pObject    = NULL;
  1118.             rgBind[iBind].pBindExt   = NULL;
  1119.             rgBind[iBind].dwFlags    = 0;
  1120.             rgBind[iBind].eParamIO   = DBPARAMIO_NOTPARAM;
  1121.             rgBind[iBind].dwPart     = DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS;
  1122.             rgBind[iBind].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
  1123.             rgBind[iBind].bPrecision = 0;
  1124.             rgBind[iBind].bScale     = 0;
  1125.  
  1126.             rgBind[iBind].cbMaxLen   = OLAP_APP_MIN_COLUMN_STR*sizeof(TCHAR);
  1127.             rgBind[iBind].wType      = DBTYPE_WSTR;
  1128.  
  1129.             // Keep our limits
  1130.             if ( dwOffset + rgBind[iBind].cbMaxLen + offsetof(COLUMNDATA,bData) > OLAP_APP_MAX_STRING_LEN || 
  1131.                  iDim == OLAP_APP_MAX_BINDINGS )
  1132.                 break;
  1133.  
  1134.             dwOffset += rgBind[iBind].cbMaxLen + offsetof(COLUMNDATA,bData);
  1135.             dwOffset = ROUND_UP( dwOffset, COLUMN_ALIGNVAL );
  1136.             iBind++;
  1137.  
  1138.             // Move to first column of next dimension.
  1139.             iCol += MDAXISINFO_GETAT(rgAxisInfo,iAxis).rgcColumns[iDim];
  1140.  
  1141.             // Print caption for this dimension
  1142.             PrintColumnCaption( iColumn++, OLAP_APP_MIN_COLUMN_STR, MDAXISINFO_GETAT(rgAxisInfo,iAxis).rgpwszDimensionNames[iDim] );
  1143.         }
  1144.  
  1145.         // Create the accessor.
  1146.         hr = pIRowset[iAxis]->QueryInterface( IID_IAccessor, (void**) &pIAccessor[iAxis] );
  1147.         if ( FAILED(hr) || !pIAccessor[iAxis] )
  1148.             goto CLEANUP;
  1149.  
  1150.         hr = pIAccessor[iAxis]->CreateAccessor( DBACCESSOR_ROWDATA, iBind, rgBind, dwOffset, &hAccessor[iAxis], NULL );
  1151.         if ( FAILED(hr) )
  1152.             goto CLEANUP;
  1153.  
  1154.         // Move to first record in every axis.
  1155.         hr = pIRowset[iAxis]->GetNextRows( NULL,              // hChapter
  1156.                                            0,                  // cRowsToSkip
  1157.                                            1,                  // cRowsDesired
  1158.                                            &cRowsObtained[iAxis],
  1159.                                            &pRows[iAxis] );  // filled in w/ row handles
  1160.         if ( FAILED(hr) || !cRowsObtained[iAxis] || !pRows[iAxis] )
  1161.             goto CLEANUP;
  1162.  
  1163.     }
  1164.  
  1165.  
  1166.     // Data bind.
  1167.     iAxis = cAxis - 1;
  1168.     iBind = 0;
  1169.  
  1170.     rgBind[iBind].iOrdinal   = 2;
  1171.     rgBind[iBind].obValue    = offsetof(COLUMNDATA,bData);
  1172.     rgBind[iBind].obLength   = offsetof(COLUMNDATA,dwLength);
  1173.     rgBind[iBind].obStatus   = offsetof(COLUMNDATA,dwStatus);
  1174.     rgBind[iBind].pTypeInfo  = NULL;
  1175.     rgBind[iBind].pObject    = NULL;
  1176.     rgBind[iBind].pBindExt   = NULL;
  1177.     rgBind[iBind].dwFlags    = 0;
  1178.     rgBind[iBind].eParamIO   = DBPARAMIO_NOTPARAM;
  1179.     rgBind[iBind].dwPart     = DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS;
  1180.     rgBind[iBind].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
  1181.     rgBind[iBind].bPrecision = 0;
  1182.     rgBind[iBind].bScale     = 0;
  1183.  
  1184.     rgBind[iBind].cbMaxLen   = OLAP_APP_MIN_COLUMN_STR*sizeof(TCHAR);
  1185.     rgBind[iBind].wType      = DBTYPE_WSTR;
  1186.  
  1187.     dwOffset = rgBind[iBind].cbMaxLen + offsetof(COLUMNDATA,bData);
  1188.     dwOffset = ROUND_UP( dwOffset, COLUMN_ALIGNVAL );
  1189.  
  1190.     PrintColumnCaption( iColumn++, OLAP_APP_MIN_COLUMN_STR, TEXT("Value") );
  1191.  
  1192.     hr = pIMDDataset->QueryInterface( IID_IAccessor, (void**) &pIAccessor[iAxis] );
  1193.     if ( FAILED(hr) || !pIAccessor[iAxis] )
  1194.         goto CLEANUP;
  1195.  
  1196.     hr = pIAccessor[iAxis]->CreateAccessor( DBACCESSOR_ROWDATA, 1, rgBind, dwOffset, &hAccessor[iAxis], NULL );
  1197.     if ( FAILED(hr) )
  1198.         goto CLEANUP;
  1199.  
  1200.  
  1201.  
  1202.     // Axis delimeterss.
  1203.     _tprintf( TEXT("\n") );
  1204.     cColumn = iColumn;
  1205.  
  1206.     for ( iColumn = 0; iColumn < cColumn - 1; iColumn++ ) {
  1207.          PrintColumnDelimiter( iColumn, OLAP_APP_MIN_COLUMN_STR );
  1208.     }
  1209.     PrintColumnDelimiter( iColumn, 5 );
  1210.  
  1211.     iAxis = 0;
  1212.  
  1213.     iCell = 0;
  1214.     cCell = MDAXISINFO_GETAT(rgAxisInfo,iAxis).cCoordinates;
  1215.  
  1216.     iColumn = 0;
  1217.  
  1218.     // Traverse all cells of query.
  1219.     while (TRUE) {
  1220.         _tprintf(TEXT("\n"));
  1221.  
  1222.         for ( iAxis = cAxis - 2; iAxis >= 0; iAxis-- ) {
  1223.             // Populate our row buffer.
  1224.             hr = pIRowset[iAxis]->GetData( pRows[iAxis][0],
  1225.                                            hAccessor[iAxis],
  1226.                                            pData );
  1227.             if ( FAILED(hr) )
  1228.                 goto CLEANUP;
  1229.  
  1230.             cDim = MDAXISINFO_GETAT(rgAxisInfo,iAxis).cDimensions;
  1231.  
  1232.             for ( iDim = 0, dwOffset = 0; iDim < cDim; iDim++ ) {
  1233.                 // Column data
  1234.                 pColumn = (COLUMNDATA*) (pData + dwOffset);
  1235.  
  1236.                 if ( iAxis > iAxisMove ) {
  1237.                     PrintColumnString(iColumn,TEXT(" "));
  1238.                 }
  1239.                 else if ( pColumn->dwStatus == DBSTATUS_S_ISNULL ) {
  1240.                     PrintColumnString(iColumn,TEXT("<null>"));
  1241.                 }
  1242.                 else if ( pColumn->dwStatus != DBSTATUS_S_OK       && 
  1243.                           pColumn->dwStatus != DBSTATUS_S_TRUNCATED ) {
  1244.                     PrintColumnString(iColumn,TEXT("<error>"));
  1245.                 }
  1246.                 else {
  1247.                     PrintColumnString(iColumn,(LPTSTR) pColumn->bData);
  1248.                 }
  1249.                 dwOffset += OLAP_APP_MIN_COLUMN_STR*sizeof(TCHAR) + offsetof(COLUMNDATA,bData);
  1250.                 dwOffset = ROUND_UP( dwOffset, COLUMN_ALIGNVAL );
  1251.             }
  1252.         }
  1253.  
  1254.         // Populate Cell buffer.
  1255.         hr = pIMDDataset->GetCellData( hAccessor[cAxis - 1],
  1256.                                        iCells,
  1257.                                        iCells,
  1258.                                        pData );
  1259.         if ( FAILED(hr) )
  1260.             break;
  1261.  
  1262.         // Print each column we're bound to.
  1263.         pColumn = (COLUMNDATA*) pData;
  1264.  
  1265.         if ( pColumn->dwStatus == DBSTATUS_S_ISNULL ) {
  1266.             PrintColumnString(iColumn,TEXT("<null>"));
  1267.         }
  1268.         else if ( pColumn->dwStatus != DBSTATUS_S_OK       && 
  1269.                   pColumn->dwStatus != DBSTATUS_S_TRUNCATED ) {
  1270.             PrintColumnString(iColumn,TEXT("<error>"));
  1271.         }
  1272.         else {
  1273.             PrintColumnString(iColumn,(LPTSTR) pColumn->bData);
  1274.         }
  1275.  
  1276.         // Move to next tuple on current axis.
  1277.         for ( iAxisMove = 0; iAxisMove < cAxis - 1; iAxisMove++ ) {
  1278.             if ( ++iRowsIndex[iAxisMove] < MDAXISINFO_GETAT(rgAxisInfo,iAxisMove).cCoordinates ) {
  1279.                 // Free previous record
  1280.                 pIRowset[iAxisMove]->ReleaseRows( cRowsObtained[iAxisMove], pRows[iAxisMove], NULL, NULL, NULL );
  1281.                 cRowsObtained[iAxisMove] = 0;
  1282.  
  1283.                 // Next on this axis.
  1284.                 hr = pIRowset[iAxisMove]->GetNextRows( NULL,              // hChapter
  1285.                                                        0,                  // cRowsToSkip
  1286.                                                        1,                  // cRowsDesired
  1287.                                                        &cRowsObtained[iAxisMove],
  1288.                                                        &pRows[iAxisMove] );  // filled in w/ row handles
  1289.                 if ( FAILED(hr) || !cRowsObtained[iAxisMove] || !pRows[iAxisMove] )
  1290.                     goto CLEANUP;
  1291.                 break;
  1292.             }
  1293.             else {
  1294.                 // Last axis finish.
  1295.                 if ( iAxisMove == cAxis - 2 ) 
  1296.                     goto CLEANUP;
  1297.  
  1298.                 // Free previous record
  1299.                 pIRowset[iAxisMove]->ReleaseRows( cRowsObtained[iAxisMove], pRows[iAxisMove], NULL, NULL, NULL );
  1300.                 cRowsObtained[iAxisMove] = 0;
  1301.  
  1302.                 // Move to next axis.
  1303.                 hr = pIRowset[iAxisMove]->RestartPosition(0);
  1304.                 if ( FAILED(hr) )
  1305.                     goto CLEANUP;
  1306.  
  1307.                 // First on this axis.
  1308.                 hr = pIRowset[iAxisMove]->GetNextRows( NULL,              // hChapter
  1309.                                                        0,                  // cRowsToSkip
  1310.                                                        1,                  // cRowsDesired
  1311.                                                        &cRowsObtained[iAxisMove],
  1312.                                                        &pRows[iAxisMove] );  // filled in w/ row handles
  1313.                 if ( FAILED(hr) || !cRowsObtained[iAxisMove] || !pRows[iAxisMove] )
  1314.                     goto CLEANUP;
  1315.  
  1316.                 iRowsIndex[iAxisMove] = 0; 
  1317.             }
  1318.         }
  1319.         iCells++;
  1320.     }
  1321.  
  1322.     CLEANUP:
  1323.     _tprintf(TEXT("\n\n"));
  1324.  
  1325.     if ( rgAxisInfo ) pIMDDataset->FreeAxisInfo( cAxis, rgAxisInfo );
  1326.  
  1327.     for ( iAxis = 0; iAxis < cAxis; iAxis++ ) {
  1328.         if ( cRowsObtained[iAxis] ) pIRowset[iAxis]->ReleaseRows( cRowsObtained[iAxis], pRows[iAxis], NULL, NULL, NULL );
  1329.  
  1330.         if ( hAccessor[iAxis] != DB_NULL_HACCESSOR ) pIAccessor[iAxis]->ReleaseAccessor( hAccessor[iAxis], NULL );
  1331.  
  1332.         if ( pRows[iAxis] ) CoTaskMemFree(pRows[iAxis]);
  1333.  
  1334.         if ( pIRowset[iAxis]   ) pIRowset[iAxis]->Release();        
  1335.         if ( pIAccessor[iAxis] ) pIAccessor[iAxis]->Release();
  1336.     }
  1337.     return hr;
  1338. }
  1339.  
  1340.  
  1341. /////////////////////////////////////////////////////////////////////////////////////
  1342. HRESULT     OLAPTab::PrintError()
  1343.  
  1344. // Print error info
  1345. /////////////////////////////////////////////////////////////////////////////////////
  1346. {
  1347.     IErrorInfo*     pIErrorInfo    = NULL;
  1348.     IErrorRecords*  pIErrorRecords = NULL;
  1349.  
  1350.     ULONG            iRecord, cRecord = 0;
  1351.  
  1352.     BSTR            bstr = NULL;
  1353.  
  1354.     // Start error report
  1355.     _tprintf(TEXT("\nError: "));
  1356.  
  1357.     HRESULT  hr = GetErrorInfo( 0, &pIErrorInfo );
  1358.     if ( FAILED(hr) || !pIErrorInfo )
  1359.         goto CLEANUP;
  1360.  
  1361.     hr = pIErrorInfo->QueryInterface( IID_IErrorRecords, (void**) &pIErrorRecords );
  1362.     if ( FAILED(hr) || !pIErrorRecords )
  1363.         goto CLEANUP;
  1364.  
  1365.     hr = pIErrorRecords->GetRecordCount(&cRecord);
  1366.     if ( FAILED(hr) )
  1367.         goto CLEANUP;
  1368.  
  1369.  
  1370.     for ( iRecord=0; iRecord < cRecord; iRecord++ ) {
  1371.         if ( pIErrorInfo ) { pIErrorInfo->Release(); pIErrorInfo = NULL; } 
  1372.  
  1373.         hr = pIErrorRecords->GetErrorInfo( iRecord, 
  1374.                                            GetUserDefaultLCID(),
  1375.                                            &pIErrorInfo );
  1376.         if ( FAILED(hr) || !pIErrorInfo )
  1377.             goto CLEANUP;
  1378.  
  1379.  
  1380.         if ( bstr ) { SysFreeString(bstr); bstr = NULL; }
  1381.         hr = pIErrorInfo->GetSource(&bstr);
  1382.         if ( FAILED(hr) )
  1383.             goto CLEANUP;
  1384.  
  1385.         // Print error info
  1386.         _tprintf(TEXT("\n%s;"),bstr);
  1387.  
  1388.         if ( bstr ) { SysFreeString(bstr); bstr = NULL; }
  1389.         hr = pIErrorInfo->GetDescription(&bstr);
  1390.         if ( FAILED(hr) )
  1391.             goto CLEANUP;
  1392.  
  1393.         // Print error info
  1394.         _tprintf(TEXT("\n%s;"),bstr);
  1395.     }
  1396.  
  1397.     // End error report
  1398.     _tprintf(TEXT("\n\n"));
  1399.  
  1400.     CLEANUP:
  1401.     if ( bstr ) SysFreeString(bstr);
  1402.  
  1403.     if ( pIErrorInfo    ) pIErrorInfo->Release();   
  1404.     if ( pIErrorRecords ) pIErrorRecords->Release();
  1405.  
  1406.     if ( !cRecord ) {
  1407.         _tprintf(TEXT("Unknown!"));
  1408.     }
  1409.     return hr;
  1410. }
  1411.  
  1412.  
  1413.  
  1414.