Google Answers Logo
View Question
 
Q: OLE DB in c++ to connect to indexing services ( No Answer,   0 Comments )
Question  
Subject: OLE DB in c++ to connect to indexing services
Category: Computers > Software
Asked by: daver-ga
List Price: $75.00
Posted: 16 Nov 2002 06:42 PST
Expires: 16 Dec 2002 06:42 PST
Question ID: 108823
I'm using OLE DB in c++ to connect to indexing services on my machine
(Win2000 Adv Server). I am running a search query in a dialog
application I wrote, and I want the result count of the search without
looping through all the results.

I have found a little information on how to get the count in the
online help (Platform SDK: Indexing Service Aggregate Functions)
DBOP_count, but little information on how to implement it.

Request for Question Clarification by hammer-ga on 18 Nov 2002 09:45 PST
Daver,

There is more than one way to do this. Could you post a snippet of
your code, so I can see how you are connecting and what form your
results are taking?

Clarification of Question by daver-ga on 18 Nov 2002 11:00 PST
The results are stored in CString that are part of CStringArray.
Typically I am caching the first 200 results, but a result set of
several thousand is common. For performance reasons, I would like to
avoid looping through the whole result set just for the count. I can
certainly provide more code if it is useful.

I've also been experimenting with another option that I'll paste below
this one. If you think that is a more viable option, or if you think
it will be a better performing solution, we can treat it as a seperate
question. If you have an even better C++ solution, I'm a careful
listener :)


bool CQueryIndex::RunQuery(CUserCache* pUserCache, WCHAR const *
pwcRestriction)
{
   if(NULL == pUserCache)
      return false;

   pUserCache->Clear();

   WCHAR const * pwcCatalog     = L"JobSeeker"; // default: lookup
catalog
   WCHAR const * pwcMachine     = L".";         // default: local
machine
   WCHAR const * pwcColumns     = L"DocTitle,size";      // default
output column(s)
   WCHAR const * pwcSort        = 0;   
   const ULONG   cRowsAtATime   = pUserCache->RowsPerPage() + 1;
   BOOL fNoQuery                = FALSE;     // default: execute query

   // Create an ICommand object.  CIMakeICommand is a shortcut for
making an
   // ICommand.  The ADVQUERY sample shows the OLE DB equivalent.

   XInterface<ICommand> xICommand;
   HRESULT hr = CIMakeICommand( xICommand.GetPPointer(),  // result
                              1,                        // 1 scope
                              &m_dwScopeFlags,            // scope
flags
                              &m_pwcScope,            // scope path
                              &pwcCatalog,            // catalog
                              &pwcMachine );          // machine
   if ( FAILED( hr ) )
      return false;

   // Get a command tree object

   XInterface<ICommandTree> xICommandTree;
   hr = xICommand->QueryInterface( IID_ICommandTree,
                                    xICommandTree.GetQIPointer() );
   if ( FAILED( hr ) )
      return false;

   // Create an OLE DB query tree based on query parameters.

   DBCOMMANDTREE * pTree;
   hr = CITextToFullTreeEx( pwcRestriction,      // the query itself
                            m_ulDialect,         // query dialect
                            pwcColumns,          // columns to return
                            pwcSort,             // sort order, may be
0
                            0,                   // reserved
                            &pTree,              // resulting tree
                            0,                   // no custom
properties
                            0,                   // no custom
properties
                            m_lcid );            // default locale
   if ( FAILED( hr ) )
      return false;

   // If directed, don't issue the query.  Parsing it was sufficient.
   if ( fNoQuery )
   {
      xICommandTree->FreeCommandTree( &pTree );
      return S_OK;
   }

   // Set the tree in the ICommandTree.  Ownership of the tree is
transferred.
   hr = xICommandTree->SetCommandTree( &pTree, DBCOMMANDREUSE_NONE,
FALSE );
   if ( FAILED( hr ) )
   {
      xICommandTree->FreeCommandTree( &pTree );
      return false;
   }

   // Set required properties on the ICommand

   hr = SetCommandProperties( xICommand.GetPointer(),
m_fForceUseContentIndex );
   if ( FAILED( hr ) )
      return false;

   // Execute the query.  The query is complete when Execute()
returns.

   hr = xICommand->Execute( 0,            // no aggregating IUnknown
                            IID_IRowset,  // IID for interface to
return
                            0,            // no DBPARAMs
                            0,            // no rows affected
                            pUserCache->xIRowset.GetIUPointer() ); //
result
   if ( FAILED( hr ) )
   {
      // Get the real error; OLE DB permits few Execute() return codes

      ERRORINFO ErrorInfo;
      XInterface<IErrorInfo> xErrorInfo;
      HRESULT hr2 = GetOleDBErrorInfo( xICommand.GetPointer(),
                                        IID_ICommand,
                                        m_lcid,
                                        &ErrorInfo,
                                        xErrorInfo.GetPPointer() );

      // Post IErrorInfo only if we have a valid pointer to it.

      if ( SUCCEEDED( hr2 ) && !xErrorInfo.IsNull() )
          hr = ErrorInfo.hrError;

       return false;
   }

   // Create an accessor, so data can be retrieved from the rowset.
   hr = pUserCache->xIRowset->QueryInterface( IID_IAccessor,
pUserCache->xIAccessor.GetQIPointer() );
   if ( FAILED( hr ) )
      return false;

   // Perry this is the function call that fires off the query.

   // Count the number of output columns and make bindings for them.
   ULONG cColumns = 2;

   // Column iOrdinals are parallel with those passed to
CiTextToFullTree,
   // so MapColumnIDs isn't necessary.  These binding values for
dwPart,
   // dwMemOwner, and wType are the most optimal bindings for Indexing
   // Service.

   XPtr<DBBINDING> xBindings( cColumns );
   if ( xBindings.IsNull() )
      return false; // E_OUTOFMEMORY;

   memset( xBindings.Get(), 0, sizeof DBBINDING * cColumns );

   for ( ULONG i = 0; i < cColumns; i++ )
   {
      xBindings[i].iOrdinal   = 1 + i; // 1-based column number
      xBindings[i].obValue    = i * sizeof( PROPVARIANT * ); // offset
      xBindings[i].dwPart     = DBPART_VALUE; // retrieve value, not
status
      xBindings[i].dwMemOwner = DBMEMOWNER_PROVIDEROWNED; // provider
owned
      xBindings[i].wType      = DBTYPE_VARIANT | DBTYPE_BYREF; //
VARIANT *
   }

   hr = pUserCache->xIAccessor->CreateAccessor( DBACCESSOR_ROWDATA,   
 // rowdata accessor
                                                cColumns,             
 // # of columns
                                                xBindings.Get(),      
 // columns
                                                0,                    
 // ignored
                                               
&pUserCache->hAccessor, // result
                                                0 );                  
 // no status
   if ( FAILED( hr ) )
      return false;

   CString strVal;
   int iCount = 0;

   if( pUserCache->xData.IsNull() )
   {
      hr = E_OUTOFMEMORY;
      pUserCache->ReleaseAccessor();
      return false;
   }

   pUserCache->QueryStart();
   pUserCache->cRowsSoFar = 0;
   pUserCache->aHRow = new HROW[cRowsAtATime];
   pUserCache->pgrHRows = pUserCache->aHRow;
   DBCOUNTITEM cCount = pUserCache->AppendToEnd() ?
pUserCache->GetNumCache() : 1;

   DBCOUNTITEM cRowsReturned = 0;
   hr = pUserCache->xIRowset->GetNextRows( 0,              // no
chapter
                                           0,              // no rows
to skip
                                           cRowsAtATime,   // # rows
to get
                                           &cRowsReturned, // # rows
returned
                                           &pUserCache->pgrHRows);    
// resulting hrows
   if ( FAILED( hr ) )
       return false;

   for ( DBCOUNTITEM iRow = 0; iRow < cRowsReturned; iRow++ )
   {
      HRESULT hr2 = pUserCache->xIRowset->GetData(
pUserCache->aHRow[iRow],   // hrow being accessed
                                                  
pUserCache->hAccessor,     // accessor to use
                                                  
pUserCache->xData.Get() ); // resulting data
      if ( FAILED( hr2 ) )
      {
         hr = hr2;
         return cCount > 1 ? true : false;
      }
      CString& str = pUserCache->GetAt(cCount);
      str.Format("%S\n", pUserCache->xData[0]->pwszVal);
      cCount++;
   }

   if ( 0 != cRowsReturned ) // Release the HROWs retrived in
GetNextRows
   {
      pUserCache->cRowsSoFar += cRowsReturned;
      pUserCache->xIRowset->ReleaseRows( cRowsReturned, // # of rows
to release
                                         pUserCache->aHRow,         //
rows to release
                                         0,0,0);        // no options,
no refcounts, no status
   }

   // Check if all rows are now retrieved.
   if ( DB_S_ENDOFROWSET == hr || DB_S_ROWLIMITEXCEEDED == hr )
   {
      hr = S_OK; // succeeded, return S_OK from DoQuery
      pUserCache->ReleaseAccessor();
      return true;
   }

   // Check if the query aborted because it was too costly.
   if ( DB_S_STOPLIMITREACHED == hr )
   {
      hr = S_OK;
      pUserCache->ReleaseAccessor();
      return false;
   }

   if ( FAILED( hr ) )
   {
      pUserCache->ReleaseAccessor();
      return false;
   }

   return true;
}

//////////////////////////////////////////////////////////////////////////////
//// optional soloution for getting results from indexing services
/////

   IixssoQuery query;
   query.CreateDispatch("IXSSO.Query.2");

   query.SetCatalog("JobSeeker");
   query.SetColumns("DocTitle");
   query.SetQuery("unix");
   long lMax = query.GetMaxRecords();


   LPDISPATCH rs = query.CreateRecordset("sequential");

At this point I'm stuck again, not knowing how to convert the
IDispatch pointer into a record set object I can use.

Thanks, you help is greatly apprecieated.
Answer  
There is no answer at this time.

Comments  
There are no comments at this time.

Important Disclaimer: Answers and comments provided on Google Answers are general information, and are not intended to substitute for informed professional medical, psychiatric, psychological, tax, legal, investment, accounting, or other professional advice. Google does not endorse, and expressly disclaims liability for any product, manufacturer, distributor, service or service provider mentioned or any opinion expressed in answers or comments. Please read carefully the Google Answers Terms of Service.

If you feel that you have found inappropriate content, please let us know by emailing us at answers-support@google.com with the question ID listed above. Thank you.
Search Google Answers for
Google Answers  


Google Home - Answers FAQ - Terms of Service - Privacy Policy