//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1994 - 2000. // // File: seqquery.cxx // // Contents: Declarations of classes which implement sequential ICursor // and related OLE DB interfaces over file stores. // // Classes: CSeqQuery - container of table/query for a set of seq cursors // // History: 09-Jan-95 DwightKr Created // //---------------------------------------------------------------------------- #include #pragma hdrstop #include #include #include #include "tabledbg.hxx" #include "seqquery.hxx" //+--------------------------------------------------------------------------- // // Class: CSeqQuery // // Purpose: Encapsulates a sequential query execution context, and PID // mapper for use by a row cursor. // // Arguments: [qopt] - Query optimizer // [col] - Initial set of columns to return // [pulCursors] - cursor returned // [pidremap] - prop ID mapping // [pDocStore] - client doc store // // History: 09 Jan 95 DwightKr Created // //---------------------------------------------------------------------------- CSeqQuery::CSeqQuery( XQueryOptimizer & qopt, XColumnSet & col, ULONG *pulCursor, XInterface & pidremap, ICiCDocStore *pDocStore ) : PQuery( ), _ref( 1 ), _pidremap( pidremap.Acquire() ), _QExec( 0 ) { // // Get ci manager and translator interfaces // ICiManager *pCiManager = 0; SCODE sc = pDocStore->GetContentIndex( &pCiManager ); if ( FAILED( sc ) ) { Win4Assert( !"Need to support GetContentIndex interface" ); THROW( CException( sc ) ); } _xCiManager.Set( pCiManager ); ICiCDocNameToWorkidTranslator *pNameToWidTranslator; sc = pDocStore->QueryInterface( IID_ICiCDocNameToWorkidTranslator, (void **) &pNameToWidTranslator ); if ( FAILED( sc ) ) { Win4Assert( !"Need to support translator QI" ); THROW( CException( sc ) ); } _xNameToWidTranslator.Set( pNameToWidTranslator ); _QExec.Set( new CQSeqExecute( qopt ) ); *pulCursor = _CreateRowCursor(); ciDebugOut(( DEB_USER1, "Using a sequential cursor.\n" )); } //+--------------------------------------------------------------------------- // // Member: CSeqQuery::AddRef, public // // Synopsis: Reference the query. // // History: 19-Jan-95 DwightKr Created // //---------------------------------------------------------------------------- ULONG CSeqQuery::AddRef(void) { return InterlockedIncrement( &_ref ); } //+--------------------------------------------------------------------------- // // Member: CSeqQuery::Release, public // // Synopsis: De-Reference the query. // // Effects: If the ref count goes to 0 then the query is deleted. // // History: 19-Jan-95 DwightKr Created // //---------------------------------------------------------------------------- ULONG CSeqQuery::Release(void) { long l = InterlockedDecrement( &_ref ); if ( l <= 0 ) { tbDebugOut(( DEB_ITRACE, "CSeqQuery unreferenced. Deleting.\n" )); delete this; return 0; } return l; } //+------------------------------------------------------------------------- // // Member: CSeqQuery::FetchDeferredValue // // Synopsis: Fetch value from property cache // // Arguments: [wid] -- Workid. // [ps] -- Property to be fetched. // [var] -- Property returned here. // // History: Jun-1-95 KyleP Created // //-------------------------------------------------------------------------- BOOL CSeqQuery::FetchDeferredValue( WORKID wid, CFullPropSpec const & ps, PROPVARIANT & var ) { return _QExec->FetchDeferredValue( wid, ps, var ); } // // Methods supporting IRowset // //+--------------------------------------------------------------------------- // // Member: CSeqQuery::SetBindings, public // // Synopsis: Set column bindings into a cursor // // Arguments: [hCursor] - the handle of the cursor to set bindings on // [cbRowLength] - the width of an output row // [cols] - a description of column bindings to be set // [pids] - a PID mapper which maps fake pids in cols to // column IDs. // // Returns: nothing - failures are thrown. E_FAIL // is thrown if hCursor cannot be looked up, // presumably an internal error. // // History: 19-Jan-95 DwightKr Created // //---------------------------------------------------------------------------- void CSeqQuery::SetBindings( ULONG hCursor, ULONG cbRowLength, CTableColumnSet & cols, CPidMapper & pids ) { _VerifyHandle(hCursor); if (0 == cols.Count() || 0 == cbRowLength || cbRowLength >= USHRT_MAX) THROW( CException( E_INVALIDARG )); XPtr outset(new CTableColumnSet( cols.Count() )); for (unsigned iCol = 0; iCol < cols.Count(); iCol++) { CTableColumn * pCol = cols.Get( iCol ); CFullPropSpec * propspec = pids.Get( pCol->PropId ); // // Convert the DBID to a PROPID // // Win4Assert( iCol+1 == pCol->PropId ); // Therefore pids is useless PROPID prop = _pidremap->NameToReal(propspec); if ( prop == pidInvalid ) THROW( CException( DB_E_BADCOLUMNID )); if (pCol->IsCompressedCol()) THROW( CException( E_INVALIDARG )); XPtr xpOutcol ( new CTableColumn( prop, pCol->GetStoredType() ) ); if (pCol->IsValueStored()) xpOutcol->SetValueField(pCol->GetStoredType(), pCol->GetValueOffset(), pCol->GetValueSize()); Win4Assert( pCol->IsStatusStored() ); xpOutcol->SetStatusField(pCol->GetStatusOffset(), (USHORT)pCol->GetStatusSize()); if (pCol->IsLengthStored()) xpOutcol->SetLengthField(pCol->GetLengthOffset(), (USHORT)pCol->GetLengthSize()); outset->Add(xpOutcol, iCol); } SCODE sc = _cursor.SetBindings( cbRowLength, outset ); if ( FAILED( sc ) ) THROW( CException( sc ) ); } //SetBindings //+------------------------------------------------------------------------- // // Member: CSeqQuery::RatioFinished, public // // Synopsis: Return the completion status as a fraction // // Arguments: [hCursor] - the handle of the cursor to check completion for // [rulDenominator] - on return, denominator of fraction // [rulNumerator] - on return, numerator of fraction // [rcRows] - on return, number of rows in cursor // [rfNewRows] - on return, TRUE if new rows available // // Returns: nothing // // Notes: A value of 0 for hCursor is allowed so that completion // can be checked before a handle exists. // //-------------------------------------------------------------------------- void CSeqQuery::RatioFinished( ULONG hCursor, DBCOUNTITEM & rulDenominator, DBCOUNTITEM & rulNumerator, DBCOUNTITEM & rcRows, BOOL & rfNewRows ) { if ( 0 != hCursor ) _VerifyHandle(hCursor); rulDenominator = 1; rulNumerator = 1; rcRows = 0; // we don't know how many there are... rfNewRows = FALSE; } //+--------------------------------------------------------------------------- // // Member: CSeqQuery::GetRows, public // // Synopsis: Retrieve row data for a table cursor // // Arguments: [hCursor] - the handle of the cursor to fetch data for // [rSeekDesc] - row seek operation to be done before fetch // [rFetchParams] - row fetch parameters and buffer pointers // // Returns: SCODE - the status of the operation. E_FAIL // is thrown if hCursor cannot be looked up, // presumably an internal error. // // History: 19-Jan-95 DwightKr Created // //---------------------------------------------------------------------------- SCODE CSeqQuery::GetRows( ULONG hCursor, const CRowSeekDescription& rSeekDesc, CGetRowsParams& rFetchParams, XPtr& pSeekDescOut ) { _VerifyHandle( hCursor ); if ( ! rSeekDesc.IsCurrentRowSeek() ) THROW( CException( E_FAIL ) ); CRowSeekNext* pRowSeek = (CRowSeekNext*) &rSeekDesc; unsigned cRowsToSkip = pRowSeek->GetSkip(); _cursor.ValidateBindings(); SCODE scRet = _QExec->GetRows( _cursor.GetBindings(), cRowsToSkip, rFetchParams ); if (FAILED(scRet)) { tbDebugOut(( DEB_WARN, "CSeqQuery::GetRows got sc=%x\n", scRet )); } if (DB_S_BLOCKLIMITEDROWS == scRet) pSeekDescOut.Set( new CRowSeekNext(pRowSeek->GetChapter(), 0) ); return scRet; } //GetRows //+------------------------------------------------------------------------- // // Member: CSeqQuery::GetQueryStatus, public // // Synopsis: Return the query status // // Arguments: [hCursor] - the handle of the cursor to check completion for // [rdwStatus] - on return, the query status // // Returns: nothing // //-------------------------------------------------------------------------- void CSeqQuery::GetQueryStatus( ULONG hCursor, DWORD & rdwStatus) { _VerifyHandle( hCursor ); rdwStatus = _QExec->Status(); } //+------------------------------------------------------------------------- // // Member: CSeqQuery::GetQueryStatusEx, public // // Synopsis: Return the query status plus bonus information. It's kind // of an odd assortment of info, but it saves net trips. // // Arguments: [hCursor] - handle of the cursor to check completion for // [rdwStatus] - returns the query status // [rcFilteredDocuments] - returns # of filtered docs // [rcDocumentsToFilter] - returns # of docs to filter // [rdwRatioFinishedDenominator] - ratio finished denom // [rdwRatioFinishedNumerator] - ratio finished num // [bmk] - bmk to find // [riRowBmk] - index of bmk row // [rcRowsTotal] - # of rows in table // // History: Nov-9-96 dlee Created // //-------------------------------------------------------------------------- void CSeqQuery::GetQueryStatusEx( ULONG hCursor, DWORD & rdwStatus, DWORD & rcFilteredDocuments, DWORD & rcDocumentsToFilter, DBCOUNTITEM & rdwRatioFinishedDenominator, DBCOUNTITEM & rdwRatioFinishedNumerator, CI_TBL_BMK bmk, DBCOUNTITEM & riRowBmk, DBCOUNTITEM & rcRowsTotal ) { GetQueryStatus( hCursor, rdwStatus ); CIF_STATE state; state.cbStruct = sizeof state; SCODE sc = _xCiManager->GetStatus( &state ); if ( SUCCEEDED( sc ) ) { rcFilteredDocuments = state.cFilteredDocuments; rcDocumentsToFilter = state.cDocuments; } else { ciDebugOut(( DEB_ERROR, "CSeqQuery::GetQueryStatusEx, get status failed, 0x%x\n", sc )); rcFilteredDocuments = 0; rcDocumentsToFilter = 0; } // sequential query -- it's done rdwRatioFinishedDenominator = 1; rdwRatioFinishedNumerator = 1; // sequential query -- this info isn't available riRowBmk = 0; rcRowsTotal = 0; } //GetQueryStatusEx //+------------------------------------------------------------------------- // // Member: CAsyncQuery::WorkIdToPath // // Synopsis: Converts a wid to a path // // Arguments: [wid] -- of the file to be translated // [funnyPath] -- resulting path // // History: Oct-5-96 dlee Created // //-------------------------------------------------------------------------- void CSeqQuery::WorkIdToPath( WORKID wid, CFunnyPath & funnyPath ) { ICiCDocName *pDocName; SCODE sc = _xNameToWidTranslator->QueryDocName( &pDocName ); if ( SUCCEEDED( sc ) ) { XInterface xDocName( pDocName ); sc = _xNameToWidTranslator->WorkIdToDocName( wid, xDocName.GetPointer() ); if ( SUCCEEDED( sc ) && sc != CI_S_WORKID_DELETED ) { // PERFFIX: Here we are using two buffers XGrowable and // CFunnyPath. This can be avoided if xDocName->Get can take // in CFunnyPath instead of WCHAR* XGrowable xBuf(MAX_PATH); ULONG cb = xBuf.SizeOf(); sc = xDocName->Get( (BYTE *) xBuf.Get(), &cb ); if ( CI_E_BUFFERTOOSMALL == sc ) { xBuf.SetSizeInBytes( cb ); sc = xDocName->Get( (BYTE *) xBuf.Get(), &cb ); } if ( SUCCEEDED( sc ) ) funnyPath.SetPath( xBuf.Get() ); } } } //WorkIdToPath