windows-nt/Source/XPSP1/NT/inetsrv/query/bigtable/seqquery.cxx
2020-09-26 16:20:57 +08:00

446 lines
14 KiB
C++

//+---------------------------------------------------------------------------
//
// 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 <pch.cxx>
#pragma hdrstop
#include <tblalloc.hxx>
#include <rowseek.hxx>
#include <tblvarnt.hxx>
#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<CPidRemapper> & 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<CTableColumnSet> 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<CTableColumn> 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<CRowSeekDescription>& 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<ICiCDocName> 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<WCHAR> 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