1217 lines
39 KiB
C++
1217 lines
39 KiB
C++
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1996 - 2000.
|
|
//
|
|
// File: wqitem.cxx
|
|
//
|
|
// Contents: WEB Query item class
|
|
//
|
|
// History: 96/Jan/3 DwightKr Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include <pch.cxx>
|
|
#pragma hdrstop
|
|
|
|
#include <params.hxx>
|
|
|
|
static const DBID dbcolNull = { {0,0,0,{0,0,0,0,0,0,0,0}},DBKIND_GUID_PROPID,0};
|
|
|
|
static const GUID guidQueryExt = DBPROPSET_QUERYEXT;
|
|
static const GUID guidRowsetProps = DBPROPSET_ROWSET;
|
|
|
|
static const DBID dbidVirtualPath = { QueryGuid, DBKIND_GUID_PROPID, (LPWSTR) 9 };
|
|
|
|
DBBINDING g_aDbBinding[ MAX_QUERY_COLUMNS ];
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CWQueryItem::CWQueryItem - public constructor
|
|
//
|
|
// Arguments: [idqFile] - IDQ file corresponding to this query
|
|
// [htxFile] - HTX file corresponding to this query
|
|
// [wcsColumns] - string representation of output columns
|
|
// [dbColumns] - OLE-DB column representation of output
|
|
// [avarColumns] - Variables from [dbColumns]. Same order.
|
|
// [ulSequenceNumber] - sequence # to assign this query
|
|
// [lNextRecordNumber] - # of next available record from query
|
|
// results; important for reconstructing
|
|
// stale sequential queries
|
|
// [securityIdentity] - security context of this query
|
|
//
|
|
// Synopsis: Builds a new query object, parses the IDQ file, and parses
|
|
// the HTX file.
|
|
//
|
|
// History: 96-Jan-18 DwightKr Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CWQueryItem::CWQueryItem(CIDQFile & idqFile,
|
|
CHTXFile & htxFile,
|
|
XPtrST<WCHAR> & wcsColumns,
|
|
XPtr<CDbColumns> & dbColumns,
|
|
CDynArray<WCHAR> & awcsColumns,
|
|
ULONG ulSequenceNumber,
|
|
LONG lNextRecordNumber,
|
|
CSecurityIdentity securityIdentity ) :
|
|
_signature(CWQueryItemSignature),
|
|
_idqFile(idqFile),
|
|
_htxFile(htxFile),
|
|
_ulSequenceNumber(ulSequenceNumber),
|
|
_refCount(0),
|
|
_fIsZombie(FALSE),
|
|
_fInCache(FALSE),
|
|
_fCanCache(TRUE),
|
|
_locale(InvalidLCID),
|
|
_wcsRestriction(0),
|
|
_wcsDialect(0),
|
|
_ulDialect(0),
|
|
_wcsSort(0),
|
|
_wcsScope(0),
|
|
_wcsCatalog(0),
|
|
_wcsCiFlags(0),
|
|
_wcsForceUseCI(0),
|
|
_wcsDeferTrimming(0),
|
|
_wcsColumns(wcsColumns.Acquire()),
|
|
_wcsQueryTimeZone(0),
|
|
_pDbColumns(dbColumns.Acquire()),
|
|
_awcsColumns( awcsColumns ),
|
|
_pIRowset(0),
|
|
_pIAccessor(0),
|
|
_pIRowsetStatus(0),
|
|
_pICommand(0),
|
|
_lNextRecordNumber(lNextRecordNumber),
|
|
_cFilteredDocuments(0),
|
|
_securityIdentity(securityIdentity)
|
|
{
|
|
time ( &_lastAccessTime );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CWQueryItem::~CWQueryItem - public destructor
|
|
//
|
|
// Synopsis: Releases storage and interfaces.
|
|
//
|
|
// History: 96-Jan-18 DwightKr Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CWQueryItem::~CWQueryItem()
|
|
{
|
|
Win4Assert( _refCount == 0 );
|
|
|
|
delete _wcsRestriction;
|
|
delete _wcsDialect;
|
|
delete _wcsSort;
|
|
delete _wcsScope;
|
|
delete _wcsCatalog;
|
|
delete _wcsColumns;
|
|
delete _wcsCiFlags;
|
|
delete _wcsForceUseCI;
|
|
delete _wcsDeferTrimming;
|
|
delete _wcsQueryTimeZone;
|
|
delete _pDbColumns;
|
|
|
|
if ( 0 != _pIAccessor )
|
|
{
|
|
_pIAccessor->ReleaseAccessor( _hAccessor, 0 );
|
|
_pIAccessor->Release();
|
|
}
|
|
|
|
if ( 0 != _pIRowset )
|
|
{
|
|
_pIRowset->Release();
|
|
}
|
|
|
|
if ( 0 != _pIRowsetStatus )
|
|
{
|
|
_pIRowsetStatus->Release();
|
|
}
|
|
|
|
if ( 0 != _pICommand )
|
|
{
|
|
TheICommandCache.Release( _pICommand );
|
|
}
|
|
|
|
_idqFile.Release();
|
|
_htxFile.Release();
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CWQueryItem::ExecuteQuery - public
|
|
//
|
|
// Synopsis: Executes the query and builds an IRowset or IRowsetScroll
|
|
// as necessary.
|
|
//
|
|
// Arguments: [variableSet] - list of replaceable parameters
|
|
// [outputFormat] - format of numbers & dates
|
|
//
|
|
// History: 96-Jan-18 DwightKr Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
void CWQueryItem::ExecuteQuery( CVariableSet & variableSet,
|
|
COutputFormat & outputFormat )
|
|
{
|
|
Win4Assert( 0 == _pIRowset ); // Should not have executed query
|
|
Win4Assert( 0 == _pIAccessor );
|
|
|
|
_locale = outputFormat.GetLCID();
|
|
|
|
//
|
|
// Setup the variables needed to execute this query; including:
|
|
//
|
|
// CiRestriction
|
|
// CiMaxRecordsInResultSet
|
|
// CiSort
|
|
// CiScope
|
|
//
|
|
|
|
//
|
|
// Build the final restriction from the existing restriction string
|
|
// and the additional parameters passed in from the browser.
|
|
//
|
|
ULONG cwcOut;
|
|
_wcsRestriction = ReplaceParameters( _idqFile.GetRestriction(),
|
|
variableSet,
|
|
outputFormat,
|
|
cwcOut );
|
|
|
|
variableSet.CopyStringValue( ISAPI_CI_RESTRICTION, _wcsRestriction, 0, cwcOut );
|
|
ciGibDebugOut(( DEB_ITRACE, "Restriction = '%ws'\n", _wcsRestriction ));
|
|
if ( 0 == *_wcsRestriction )
|
|
{
|
|
THROW( CIDQException(MSG_CI_IDQ_MISSING_RESTRICTION , 0) );
|
|
}
|
|
|
|
//
|
|
// Setup CiMaxRecordsInResultSet
|
|
//
|
|
_lMaxRecordsInResultSet =
|
|
ReplaceNumericParameter( _idqFile.GetMaxRecordsInResultSet(),
|
|
variableSet,
|
|
outputFormat,
|
|
TheIDQRegParams.GetMaxISRowsInResultSet(),
|
|
IS_MAX_ROWS_IN_RESULT_MIN,
|
|
IS_MAX_ROWS_IN_RESULT_MAX );
|
|
|
|
PROPVARIANT propVariant;
|
|
propVariant.vt = VT_I4;
|
|
propVariant.lVal = _lMaxRecordsInResultSet;
|
|
variableSet.SetVariable( ISAPI_CI_MAX_RECORDS_IN_RESULTSET, &propVariant, 0 );
|
|
ciGibDebugOut(( DEB_ITRACE, "CiMaxRecordsInResultSet = %d\n", _lMaxRecordsInResultSet ));
|
|
|
|
// Setup CiFirstRowsInResultSet
|
|
//
|
|
_lFirstRowsInResultSet =
|
|
ReplaceNumericParameter( _idqFile.GetFirstRowsInResultSet(),
|
|
variableSet,
|
|
outputFormat,
|
|
TheIDQRegParams.GetISFirstRowsInResultSet(),
|
|
IS_FIRST_ROWS_IN_RESULT_MIN,
|
|
IS_FIRST_ROWS_IN_RESULT_MAX );
|
|
|
|
PROPVARIANT propVar;
|
|
propVar.vt = VT_I4;
|
|
propVar.lVal = _lFirstRowsInResultSet;
|
|
variableSet.SetVariable( ISAPI_CI_FIRST_ROWS_IN_RESULTSET, &propVar, 0 );
|
|
ciGibDebugOut(( DEB_ITRACE, "CiFirstRowsInResultSet = %d\n", _lFirstRowsInResultSet ));
|
|
|
|
|
|
_ulDialect =
|
|
ReplaceNumericParameter( _idqFile.GetDialect(),
|
|
variableSet,
|
|
outputFormat,
|
|
ISQLANG_V2, // default
|
|
ISQLANG_V1, // min
|
|
ISQLANG_V2 ); // max
|
|
Win4Assert( 0 != _ulDialect );
|
|
|
|
propVariant.vt = VT_UI4;
|
|
propVariant.ulVal = _ulDialect;
|
|
variableSet.SetVariable( ISAPI_CI_DIALECT, &propVariant, 0 );
|
|
ciGibDebugOut(( DEB_ITRACE, "CiDialect = %d\n", _ulDialect ));
|
|
|
|
//
|
|
// Build the final sort set from the existing sortset string
|
|
// and the additional parameters passed in from the browser.
|
|
//
|
|
|
|
XPtr<CDbSortNode> xDbSortNode;
|
|
|
|
if ( 0 != _idqFile.GetSort() )
|
|
{
|
|
_wcsSort = ReplaceParameters( _idqFile.GetSort(),
|
|
variableSet,
|
|
outputFormat,
|
|
cwcOut );
|
|
|
|
variableSet.CopyStringValue( ISAPI_CI_SORT, _wcsSort, 0, cwcOut );
|
|
|
|
ciGibDebugOut(( DEB_ITRACE, "Sort = '%ws'\n", _wcsSort ));
|
|
Win4Assert( 0 != _wcsSort );
|
|
}
|
|
|
|
//
|
|
// Build the projection list from the column list.
|
|
//
|
|
|
|
CTextToTree textToTree( _wcsRestriction,
|
|
_ulDialect,
|
|
_pDbColumns,
|
|
_idqFile.GetColumnMapper(),
|
|
_locale,
|
|
_wcsSort,
|
|
0,
|
|
0,
|
|
_lMaxRecordsInResultSet,
|
|
_lFirstRowsInResultSet );
|
|
|
|
CDbCmdTreeNode * pDbCmdTree = (CDbCmdTreeNode *) (void *) textToTree.FormFullTree();
|
|
XPtr<CDbCmdTreeNode> xDbCmdTree( pDbCmdTree );
|
|
|
|
//
|
|
// Remap the scope from a replaceable parameter
|
|
//
|
|
_wcsScope = ReplaceParameters( _idqFile.GetScope(),
|
|
variableSet,
|
|
outputFormat,
|
|
cwcOut );
|
|
|
|
variableSet.CopyStringValue( ISAPI_CI_SCOPE, _wcsScope, 0, cwcOut );
|
|
|
|
ciGibDebugOut(( DEB_ITRACE, "Scope = '%ws'\n", _wcsScope ));
|
|
Win4Assert( 0 != _wcsScope );
|
|
if ( 0 == *_wcsScope )
|
|
{
|
|
THROW( CIDQException(MSG_CI_IDQ_MISSING_SCOPE , 0) );
|
|
}
|
|
|
|
//
|
|
// Build the location of the catalog
|
|
//
|
|
ULONG cwcCatalog;
|
|
Win4Assert( 0 != _idqFile.GetCatalog() );
|
|
_wcsCatalog = ReplaceParameters( _idqFile.GetCatalog(),
|
|
variableSet,
|
|
outputFormat,
|
|
cwcCatalog );
|
|
|
|
variableSet.CopyStringValue( ISAPI_CI_CATALOG, _wcsCatalog, 0, cwcCatalog );
|
|
|
|
ciGibDebugOut(( DEB_ITRACE, "Catalog = '%ws'\n", _wcsCatalog ));
|
|
Win4Assert( 0 != _wcsCatalog );
|
|
|
|
if ( !IsAValidCatalog( _wcsCatalog, cwcCatalog ) )
|
|
{
|
|
THROW( CIDQException(MSG_CI_IDQ_NO_SUCH_CATALOG, 0) );
|
|
}
|
|
|
|
XPtrST<WCHAR> xpCat;
|
|
XPtrST<WCHAR> xpMach;
|
|
|
|
if ( ( ! SUCCEEDED( ParseCatalogURL( _wcsCatalog, xpCat, xpMach ) ) ) ||
|
|
( xpCat.IsNull() ) )
|
|
{
|
|
THROW( CIDQException(MSG_CI_IDQ_NO_SUCH_CATALOG, 0) );
|
|
}
|
|
|
|
//
|
|
// Get the query flags.
|
|
//
|
|
ULONG cwcCiFlags;
|
|
_wcsCiFlags = ReplaceParameters( _idqFile.GetCiFlags(),
|
|
variableSet,
|
|
outputFormat,
|
|
cwcCiFlags );
|
|
|
|
if ( 0 != _wcsCiFlags )
|
|
{
|
|
variableSet.CopyStringValue( ISAPI_CI_FLAGS, _wcsCiFlags, 0, cwcCiFlags );
|
|
}
|
|
ULONG ulFlags = _idqFile.ParseFlags( _wcsCiFlags );
|
|
ciGibDebugOut(( DEB_ITRACE, "CiFlags = '%ws' (%x)\n", _wcsCiFlags, ulFlags ));
|
|
|
|
//
|
|
// We've setup all the parameters to run the query. Run the query
|
|
// now.
|
|
//
|
|
_pICommand = 0;
|
|
|
|
//
|
|
// Paths start out as one of:
|
|
// ?:\...
|
|
// \\....\....\
|
|
// /...
|
|
//
|
|
|
|
SCODE scIC = S_OK;
|
|
|
|
if ( _wcsicmp( _wcsScope, L"VIRTUAL_ROOTS" ) == 0 )
|
|
{
|
|
_fCanCache = FALSE;
|
|
CheckAdminSecurity( xpMach.GetPointer() );
|
|
IUnknown * pIUnknown;
|
|
scIC = MakeMetadataICommand( &pIUnknown,
|
|
CiVirtualRoots,
|
|
xpCat.GetPointer(),
|
|
xpMach.GetPointer() );
|
|
if (SUCCEEDED (scIC))
|
|
{
|
|
XInterface<IUnknown> xUnk( pIUnknown );
|
|
scIC = pIUnknown->QueryInterface(IID_ICommand, (void **)&_pICommand);
|
|
}
|
|
}
|
|
else if ( _wcsicmp( _wcsScope, L"PROPERTIES" ) == 0 )
|
|
{
|
|
_fCanCache = FALSE;
|
|
CheckAdminSecurity( xpMach.GetPointer() );
|
|
IUnknown * pIUnknown;
|
|
scIC = MakeMetadataICommand( &pIUnknown,
|
|
CiProperties,
|
|
xpCat.GetPointer(),
|
|
xpMach.GetPointer() );
|
|
if (SUCCEEDED (scIC))
|
|
{
|
|
XInterface<IUnknown> xUnk( pIUnknown );
|
|
scIC = pIUnknown->QueryInterface(IID_ICommand, (void **)&_pICommand);
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Verify that the caller has admin security for DontTimeout queries.
|
|
//
|
|
if ( _idqFile.IsDontTimeout() )
|
|
CheckAdminSecurity( xpMach.GetPointer() );
|
|
|
|
scIC = TheICommandCache.Make( &_pICommand,
|
|
ulFlags,
|
|
xpMach.GetPointer(),
|
|
xpCat.GetPointer(),
|
|
_wcsScope );
|
|
|
|
}
|
|
|
|
#if CIDBG == 1
|
|
if ( FAILED( scIC ) )
|
|
Win4Assert( 0 == _pICommand );
|
|
else
|
|
Win4Assert( 0 != _pICommand );
|
|
#endif // CIDBG == 1
|
|
|
|
if ( 0 == _pICommand )
|
|
{
|
|
ciGibDebugOut(( DEB_ITRACE, "Make*ICommand failed with error 0x%x\n", scIC ));
|
|
|
|
// Make*ICommand returns SCODEs, not Win32 error codes
|
|
|
|
Win4Assert( ERROR_FILE_NOT_FOUND != scIC );
|
|
Win4Assert( ERROR_SEM_TIMEOUT != scIC );
|
|
|
|
// These errors are no longer returned -- the work isn't
|
|
// done until Execute(), and the errors are mapped to
|
|
// the popular E_FAIL. Leave the code in since now the
|
|
// OLE DB spec allows the errors and we may change the provider.
|
|
|
|
if ( ( HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND ) == scIC ) ||
|
|
( HRESULT_FROM_WIN32( ERROR_SEM_TIMEOUT ) == scIC ) )
|
|
{
|
|
THROW( CIDQException( MSG_CI_IDQ_CISVC_NOT_RUNNING, 0 ) );
|
|
}
|
|
else
|
|
{
|
|
THROW( CIDQException( MSG_CI_IDQ_BAD_SCOPE_OR_CATALOG, 0 ) );
|
|
}
|
|
}
|
|
|
|
ICommandTree * pICmdTree = 0;
|
|
SCODE sc = _pICommand->QueryInterface( IID_ICommandTree,
|
|
(void **) &pICmdTree );
|
|
if (FAILED (sc) )
|
|
{
|
|
THROW( CException( QUERY_EXECUTE_FAILED ) );
|
|
}
|
|
|
|
DBCOMMANDTREE * pDbCommandTree = pDbCmdTree->CastToStruct();
|
|
sc = pICmdTree->SetCommandTree(&pDbCommandTree, DBCOMMANDREUSE_NONE, FALSE);
|
|
pICmdTree->Release();
|
|
|
|
if ( FAILED(sc) )
|
|
{
|
|
THROW( CException(sc) );
|
|
}
|
|
|
|
xDbCmdTree.Acquire();
|
|
|
|
//
|
|
// Save the time this query started execution
|
|
//
|
|
GetLocalTime( &_queryTime );
|
|
|
|
//
|
|
// If we should NOT be using a enumerated query, notify pCommand
|
|
//
|
|
const unsigned MAX_PROPS = 5;
|
|
DBPROPSET aPropSet[MAX_PROPS];
|
|
DBPROP aProp[MAX_PROPS];
|
|
ULONG cProp = 0;
|
|
|
|
// Set the property that says we accept PROPVARIANTs
|
|
aProp[cProp].dwPropertyID = DBPROP_USEEXTENDEDDBTYPES;
|
|
aProp[cProp].dwOptions = DBPROPOPTIONS_OPTIONAL;
|
|
aProp[cProp].dwStatus = 0; // Ignored
|
|
aProp[cProp].colid = dbcolNull;
|
|
aProp[cProp].vValue.vt = VT_BOOL;
|
|
aProp[cProp].vValue.boolVal = VARIANT_TRUE;
|
|
|
|
aPropSet[cProp].rgProperties = &aProp[cProp];
|
|
aPropSet[cProp].cProperties = 1;
|
|
aPropSet[cProp].guidPropertySet = guidQueryExt;
|
|
|
|
cProp++;
|
|
|
|
ULONG cwc;
|
|
_wcsForceUseCI = ReplaceParameters( _idqFile.GetForceUseCI(),
|
|
variableSet,
|
|
outputFormat,
|
|
cwc );
|
|
|
|
if ( 0 != _wcsForceUseCI )
|
|
{
|
|
variableSet.CopyStringValue( ISAPI_CI_FORCE_USE_CI, _wcsForceUseCI, 0, cwc );
|
|
}
|
|
|
|
BOOL fForceUseCI = _idqFile.ParseForceUseCI( _wcsForceUseCI );
|
|
ciGibDebugOut(( DEB_ITRACE, "CiForceUseCi = '%ws'\n", _wcsForceUseCI ));
|
|
|
|
{
|
|
// Set the property that says we don't want to enumerate
|
|
aProp[cProp].dwPropertyID = DBPROP_USECONTENTINDEX;
|
|
aProp[cProp].dwOptions = DBPROPOPTIONS_OPTIONAL;
|
|
aProp[cProp].dwStatus = 0; // Ignored
|
|
aProp[cProp].colid = dbcolNull;
|
|
aProp[cProp].vValue.vt = VT_BOOL;
|
|
aProp[cProp].vValue.boolVal = fForceUseCI ? VARIANT_TRUE : VARIANT_FALSE;
|
|
|
|
aPropSet[cProp].rgProperties = &aProp[cProp];
|
|
aPropSet[cProp].cProperties = 1;
|
|
aPropSet[cProp].guidPropertySet = guidQueryExt;
|
|
|
|
cProp++;
|
|
}
|
|
|
|
PROPVARIANT Variant;
|
|
Variant.vt = VT_BOOL;
|
|
Variant.boolVal = fForceUseCI ? VARIANT_TRUE : VARIANT_FALSE;
|
|
variableSet.SetVariable( ISAPI_CI_FORCE_USE_CI, &Variant, 0 );
|
|
|
|
_wcsDeferTrimming = ReplaceParameters( _idqFile.GetDeferTrimming(),
|
|
variableSet,
|
|
outputFormat,
|
|
cwc );
|
|
|
|
if ( 0 != _wcsDeferTrimming )
|
|
{
|
|
variableSet.CopyStringValue( ISAPI_CI_DEFER_NONINDEXED_TRIMMING, _wcsDeferTrimming, 0, cwc );
|
|
}
|
|
|
|
BOOL fDeferTrimming = _idqFile.ParseDeferTrimming( _wcsDeferTrimming );
|
|
ciGibDebugOut(( DEB_ITRACE, "CiDeferNonIndexedTrimming = '%ws'\n", _wcsDeferTrimming ));
|
|
|
|
{
|
|
// Set the property that says we don't want to enumerate
|
|
aProp[cProp].dwPropertyID = DBPROP_DEFERNONINDEXEDTRIMMING;
|
|
aProp[cProp].dwOptions = DBPROPOPTIONS_OPTIONAL;
|
|
aProp[cProp].dwStatus = 0; // Ignored
|
|
aProp[cProp].colid = dbcolNull;
|
|
aProp[cProp].vValue.vt = VT_BOOL;
|
|
aProp[cProp].vValue.boolVal = fDeferTrimming ? VARIANT_TRUE : VARIANT_FALSE;
|
|
|
|
aPropSet[cProp].rgProperties = &aProp[cProp];
|
|
aPropSet[cProp].cProperties = 1;
|
|
aPropSet[cProp].guidPropertySet = guidQueryExt;
|
|
|
|
cProp++;
|
|
}
|
|
|
|
if ( _idqFile.IsDontTimeout() )
|
|
{
|
|
// Set the property that says we don't want to timeout
|
|
aProp[cProp].dwPropertyID = DBPROP_COMMANDTIMEOUT;
|
|
aProp[cProp].dwOptions = DBPROPOPTIONS_OPTIONAL;
|
|
aProp[cProp].dwStatus = 0; // Ignored
|
|
aProp[cProp].colid = dbcolNull;
|
|
aProp[cProp].vValue.vt = VT_I4;
|
|
aProp[cProp].vValue.lVal = 0;
|
|
|
|
aPropSet[cProp].rgProperties = &aProp[cProp];
|
|
aPropSet[cProp].cProperties = 1;
|
|
aPropSet[cProp].guidPropertySet = guidRowsetProps;
|
|
|
|
cProp++;
|
|
}
|
|
|
|
Win4Assert( Variant.vt == VT_BOOL );
|
|
Variant.boolVal = fDeferTrimming ? VARIANT_TRUE : VARIANT_FALSE;
|
|
variableSet.SetVariable( ISAPI_CI_DEFER_NONINDEXED_TRIMMING, &Variant, 0 );
|
|
|
|
//
|
|
// If this is a non-Sequential query, make it asynchronous
|
|
//
|
|
if (! IsSequential() )
|
|
{
|
|
// Set the property that says we want to use asynch. queries
|
|
aProp[cProp].dwPropertyID = DBPROP_ROWSET_ASYNCH;
|
|
aProp[cProp].dwOptions = DBPROPOPTIONS_OPTIONAL;
|
|
aProp[cProp].dwStatus = 0; // Ignored
|
|
aProp[cProp].colid = dbcolNull;
|
|
aProp[cProp].vValue.vt = VT_I4;
|
|
aProp[cProp].vValue.lVal = DBPROPVAL_ASYNCH_SEQUENTIALPOPULATION |
|
|
DBPROPVAL_ASYNCH_RANDOMPOPULATION;
|
|
|
|
aPropSet[cProp].rgProperties = &aProp[cProp];
|
|
aPropSet[cProp].cProperties = 1;
|
|
aPropSet[cProp].guidPropertySet = guidRowsetProps;
|
|
|
|
cProp++;
|
|
}
|
|
|
|
if ( cProp > 0 )
|
|
{
|
|
Win4Assert( cProp <= MAX_PROPS );
|
|
|
|
ICommandProperties * pCmdProp = 0;
|
|
sc = _pICommand->QueryInterface( IID_ICommandProperties,
|
|
(void **)&pCmdProp );
|
|
|
|
if (FAILED (sc) )
|
|
{
|
|
THROW( CException( QUERY_EXECUTE_FAILED ) );
|
|
}
|
|
|
|
sc = pCmdProp->SetProperties( cProp, aPropSet );
|
|
pCmdProp->Release();
|
|
|
|
if ( FAILED(sc) || DB_S_ERRORSOCCURRED == sc )
|
|
{
|
|
THROW( CException( QUERY_EXECUTE_FAILED ) );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Execute the query
|
|
//
|
|
|
|
sc = _pICommand->Execute( 0, // No aggr
|
|
IsSequential() ? IID_IRowset : IID_IRowsetScroll,
|
|
0, // disp params
|
|
0, // # rowsets returned
|
|
(IUnknown **) &_pIRowset );
|
|
|
|
if ( FAILED(sc) )
|
|
{
|
|
ERRORINFO ErrorInfo;
|
|
XInterface<IErrorInfo> xErrorInfo;
|
|
SCODE sc2 = GetOleDBErrorInfo(_pICommand,
|
|
IID_ICommand,
|
|
GetLocale(),
|
|
eMostDetailedCIError,
|
|
&ErrorInfo,
|
|
(IErrorInfo **)xErrorInfo.GetQIPointer());
|
|
// Post IErrorInfo only if we have a valid ptr to it.
|
|
if (SUCCEEDED(sc2) && 0 != xErrorInfo.GetPointer())
|
|
{
|
|
sc = ErrorInfo.hrError;
|
|
|
|
// Maybe the ICommand is stale because cisvc was stopped and
|
|
// restarted -- purge it from the cache.
|
|
|
|
TheICommandCache.Remove( _pICommand );
|
|
_pICommand = 0;
|
|
|
|
THROW( CPostedOleDBException(sc, eDefaultISAPIError, xErrorInfo.GetPointer()) );
|
|
}
|
|
else
|
|
{
|
|
// Maybe the ICommand is stale because cisvc was stopped and
|
|
// restarted -- purge it from the cache.
|
|
|
|
TheICommandCache.Remove( _pICommand );
|
|
_pICommand = 0;
|
|
|
|
THROW( CException(sc) );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Create an accessor
|
|
//
|
|
|
|
_pIAccessor = 0;
|
|
|
|
sc = _pIRowset->QueryInterface( IID_IAccessor, (void **)&_pIAccessor);
|
|
if ( FAILED( sc ) || _pIAccessor == 0 )
|
|
{
|
|
THROW( CException( DB_E_ERRORSOCCURRED ) );
|
|
}
|
|
|
|
ULONG cCols = _pDbColumns->Count();
|
|
if ( cCols > MAX_QUERY_COLUMNS )
|
|
{
|
|
THROW( CException( DB_E_ERRORSOCCURRED ) );
|
|
}
|
|
|
|
sc = _pIAccessor->CreateAccessor( DBACCESSOR_ROWDATA, // Type of access required
|
|
cCols, // # of bindings
|
|
g_aDbBinding, // Array of bindings
|
|
0, // reserved
|
|
&_hAccessor,
|
|
0 );
|
|
|
|
if ( FAILED( sc ) )
|
|
{
|
|
THROW( CException(sc) );
|
|
}
|
|
|
|
//
|
|
// Create some of the restriction specific variables.
|
|
//
|
|
|
|
//
|
|
// Get _pIRowsetStatus interface
|
|
//
|
|
sc = _pIRowset->QueryInterface( IID_IRowsetQueryStatus,
|
|
(void **) &_pIRowsetStatus );
|
|
|
|
if ( FAILED(sc) )
|
|
{
|
|
THROW( CException(sc) );
|
|
}
|
|
|
|
Win4Assert( 0 != _pIRowsetStatus );
|
|
|
|
//
|
|
// Save the # of filtered documents for this catalog and get the
|
|
// query status.
|
|
//
|
|
|
|
DWORD dwStatus = 0;
|
|
DWORD cToFilter;
|
|
DBCOUNTITEM cDen, cNum;
|
|
DBCOUNTITEM iCur, cTotal;
|
|
sc = _pIRowsetStatus->GetStatusEx( &dwStatus,
|
|
&_cFilteredDocuments,
|
|
&cToFilter,
|
|
&cDen,
|
|
&cNum,
|
|
0,
|
|
0,
|
|
&iCur,
|
|
&cTotal );
|
|
|
|
if ( FAILED( sc ) )
|
|
{
|
|
THROW( CException(sc) );
|
|
}
|
|
|
|
propVariant.vt = VT_BOOL;
|
|
|
|
if ( QUERY_RELIABILITY_STATUS(dwStatus) &
|
|
(STAT_CONTENT_OUT_OF_DATE | STAT_REFRESH_INCOMPLETE) )
|
|
{
|
|
propVariant.boolVal = VARIANT_TRUE;
|
|
ciGibDebugOut(( DEB_ITRACE, "The query is out of date\n" ));
|
|
}
|
|
else
|
|
{
|
|
propVariant.boolVal = VARIANT_FALSE;
|
|
}
|
|
variableSet.SetVariable( ISAPI_CI_OUT_OF_DATE, &propVariant, 0 );
|
|
|
|
if ( QUERY_RELIABILITY_STATUS(dwStatus) & STAT_CONTENT_QUERY_INCOMPLETE )
|
|
{
|
|
propVariant.boolVal = VARIANT_TRUE;
|
|
ciGibDebugOut(( DEB_ITRACE, "The query is incomplete\n" ));
|
|
}
|
|
else
|
|
{
|
|
propVariant.boolVal = VARIANT_FALSE;
|
|
}
|
|
variableSet.SetVariable( ISAPI_CI_QUERY_INCOMPLETE, &propVariant, 0 );
|
|
|
|
if ( QUERY_RELIABILITY_STATUS(dwStatus) & STAT_TIME_LIMIT_EXCEEDED )
|
|
{
|
|
propVariant.boolVal = VARIANT_TRUE;
|
|
ciGibDebugOut(( DEB_ITRACE, "The query timed out\n" ));
|
|
}
|
|
else
|
|
{
|
|
propVariant.boolVal = VARIANT_FALSE;
|
|
}
|
|
variableSet.SetVariable( ISAPI_CI_QUERY_TIMEDOUT, &propVariant, 0 );
|
|
|
|
//
|
|
// Set CiQueryTimeZone
|
|
//
|
|
TIME_ZONE_INFORMATION TimeZoneInformation;
|
|
DWORD dwResult = GetTimeZoneInformation( &TimeZoneInformation );
|
|
LPWSTR pwszTimeZoneName = 0;
|
|
|
|
if ( TIME_ZONE_ID_DAYLIGHT == dwResult )
|
|
{
|
|
pwszTimeZoneName = TimeZoneInformation.DaylightName;
|
|
}
|
|
else if ( 0xFFFFFFFF == dwResult )
|
|
{
|
|
# if CIDBG == 1
|
|
DWORD dwError = GetLastError();
|
|
ciGibDebugOut(( DEB_ERROR, "Error %d from GetTimeZoneInformation.\n", dwError ));
|
|
THROW(CException( HRESULT_FROM_WIN32(dwError) ));
|
|
# else
|
|
THROW( CException() );
|
|
# endif
|
|
}
|
|
else
|
|
{
|
|
pwszTimeZoneName = TimeZoneInformation.StandardName;
|
|
}
|
|
|
|
ULONG cchQueryTimeZone = wcslen( pwszTimeZoneName );
|
|
_wcsQueryTimeZone = new WCHAR[ cchQueryTimeZone + 1 ];
|
|
RtlCopyMemory( _wcsQueryTimeZone,
|
|
pwszTimeZoneName,
|
|
(cchQueryTimeZone+1) * sizeof(WCHAR) );
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CWQueryItem::GetQueryResultsIterator - private
|
|
//
|
|
// Synopsis: Builds a CBaseQueryResultsIter which can subsequently be used
|
|
// to send the query results back to the web browser. All
|
|
// per-browser data relative to the query is kept in the iterator.
|
|
//
|
|
// Returns: [CBaseQueryResultsIter] - a sequential or non-sequential
|
|
// iterator depending on the paramaters requested in the HTX
|
|
// file.
|
|
//
|
|
// History: 96-Jan-18 DwightKr Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
CBaseQueryResultsIter * CWQueryItem::GetQueryResultsIterator( COutputFormat & outputFormat )
|
|
{
|
|
CBaseQueryResultsIter *pIter;
|
|
|
|
//
|
|
// Setup the formatting for the vector types
|
|
//
|
|
|
|
_idqFile.GetVectorFormatting( outputFormat );
|
|
|
|
if ( IsSequential() )
|
|
{
|
|
Win4Assert( _lNextRecordNumber > 0 );
|
|
pIter = new CSeqQueryResultsIter( *this,
|
|
_pIRowset,
|
|
_hAccessor,
|
|
_pDbColumns->Count(),
|
|
_lNextRecordNumber-1 );
|
|
|
|
ciGibDebugOut(( DEB_ITRACE, "Using a sequential iterator\n" ));
|
|
}
|
|
else
|
|
{
|
|
IRowsetScroll *pIRowsetScroll = 0;
|
|
HRESULT sc = _pIRowset->QueryInterface(IID_IRowsetScroll, (void **) &pIRowsetScroll);
|
|
|
|
if ( FAILED( sc ) )
|
|
{
|
|
THROW( CException(sc) );
|
|
}
|
|
|
|
XInterface<IRowsetScroll> xIRowsetScroll(pIRowsetScroll);
|
|
pIter = new CQueryResultsIter( *this,
|
|
pIRowsetScroll,
|
|
_hAccessor,
|
|
_pDbColumns->Count() );
|
|
|
|
xIRowsetScroll.Acquire();
|
|
|
|
ciGibDebugOut(( DEB_ITRACE, "Using a NON-sequential iterator\n" ));
|
|
}
|
|
|
|
return pIter;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CWQueryItem::OutputQueryResults - public
|
|
//
|
|
// Arguments: [variableSet] - list of browser-supplied replaceable parameters
|
|
// [outputFormat] - format of numbers & dates
|
|
// [vString] - destination buffer for output results
|
|
//
|
|
// Synopsis: Using the parameters passed, build an iterator to walk the
|
|
// query results and buffer output into the vString.
|
|
//
|
|
// History: 18-Jan-96 DwightKr Created
|
|
// 11-Jun-97 KyleP Use web server from output format
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CWQueryItem::OutputQueryResults( CVariableSet & variableSet,
|
|
COutputFormat & outputFormat,
|
|
CVirtualString & vString )
|
|
{
|
|
//
|
|
// Build the query results iterator based on the parameters passed in.
|
|
//
|
|
|
|
CBaseQueryResultsIter *pIter = GetQueryResultsIterator( outputFormat );
|
|
XPtr<CBaseQueryResultsIter> iter(pIter);
|
|
|
|
iter->Init( variableSet, outputFormat );
|
|
|
|
UpdateQueryStatus( variableSet );
|
|
|
|
//
|
|
// Build the HTML pages in three sections: first the header
|
|
// section (evenything before the <%begindetail%>), next the detail
|
|
// section (everything between the <%begindetail%> and <%enddetail%>),
|
|
// and finally the footer section (everything after the
|
|
// <%enddetail%> section).
|
|
//
|
|
|
|
//
|
|
// Output the header section.
|
|
//
|
|
|
|
_htxFile.GetHeader( vString, variableSet, outputFormat ) ;
|
|
|
|
LONG lCurrentRecordNumber = iter->GetFirstRecordNumber();
|
|
|
|
if ( _htxFile.DoesDetailSectionExist() )
|
|
{
|
|
//
|
|
// Output the detail section
|
|
//
|
|
ULONG cCols = iter->GetColumnCount();
|
|
XArray<CVariable *> xVariables( cCols );
|
|
|
|
for ( ULONG i=0; i<cCols; i++ )
|
|
{
|
|
xVariables[i] = variableSet.SetVariable( _awcsColumns.Get(i), 0, 0 );
|
|
Win4Assert( 0 != xVariables[i] );
|
|
}
|
|
|
|
PROPVARIANT VariantRecordNumber;
|
|
VariantRecordNumber.vt = VT_I4;
|
|
|
|
CVariable * pvarRecordNumber = variableSet.SetVariable( ISAPI_CI_CURRENT_RECORD_NUMBER, 0, 0 );
|
|
Win4Assert( 0 != pvarRecordNumber );
|
|
|
|
//
|
|
// Execute the detail section for each row/record in the query results
|
|
//
|
|
for ( ;
|
|
!iter->AtEnd();
|
|
iter->Next(), lCurrentRecordNumber++ )
|
|
{
|
|
COutputColumn * pColumns = iter->GetRowData();
|
|
|
|
//
|
|
// Update the replaceable parameters for each of the columns
|
|
// in this row.
|
|
//
|
|
|
|
for ( i = 0; i < cCols; i++ )
|
|
xVariables[i]->FastSetValue( pColumns[i].GetVariant() );
|
|
|
|
VariantRecordNumber.lVal = lCurrentRecordNumber;
|
|
pvarRecordNumber->FastSetValue( &VariantRecordNumber );
|
|
|
|
_htxFile.GetDetailSection( vString, variableSet, outputFormat );
|
|
}
|
|
|
|
//
|
|
// The query output columns are no longer defined outside of the
|
|
// DETAIL section. Delete these variables here so that any reference
|
|
// to them will return a NULL string.
|
|
//
|
|
for ( i=0; i<cCols; i++ )
|
|
{
|
|
variableSet.Delete( xVariables[i] );
|
|
}
|
|
}
|
|
|
|
//
|
|
// If we couldn't get the first record #, then the current page #
|
|
// should be set to 0.
|
|
//
|
|
|
|
if ( iter->GetFirstRecordNumber() == lCurrentRecordNumber )
|
|
{
|
|
PROPVARIANT Variant;
|
|
Variant.vt = VT_I4;
|
|
Variant.lVal = 0;
|
|
variableSet.SetVariable( ISAPI_CI_CURRENT_PAGE_NUMBER, &Variant, 0 );
|
|
}
|
|
|
|
//
|
|
// Output the footer section.
|
|
//
|
|
|
|
_htxFile.GetFooter( vString, variableSet, outputFormat );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CWQueryItem::UpdateQueryStatus - public
|
|
//
|
|
// Synopsis: Updates variables relating to query status.
|
|
//
|
|
// Arguments: [variableSet] - VariableSet to be updated
|
|
//
|
|
// Returns: Nothing
|
|
//
|
|
// Notes: These are post-execution checks that can change an up-to-date
|
|
// query to an out-of-date query, but not the reverse. The
|
|
// following variables are set:
|
|
// CiOutOfDate
|
|
// CiQueryIncomplete
|
|
// CiQueryTimedOut
|
|
//
|
|
// History: 96 Apr 16 AlanW Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CWQueryItem::UpdateQueryStatus( CVariableSet & variableSet )
|
|
{
|
|
Win4Assert( 0 != _pIRowsetStatus );
|
|
|
|
DWORD dwStatus = 0;
|
|
DWORD cDocsFiltered, cToFilter;
|
|
DBCOUNTITEM cDen, cNum;
|
|
DBCOUNTITEM iCur, cTotal;
|
|
SCODE sc = _pIRowsetStatus->GetStatusEx( &dwStatus,
|
|
&cDocsFiltered,
|
|
&cToFilter,
|
|
&cDen,
|
|
&cNum,
|
|
0,
|
|
0,
|
|
&iCur,
|
|
&cTotal );
|
|
|
|
if ( FAILED( sc ) )
|
|
THROW( CException(sc) );
|
|
|
|
PROPVARIANT propVariant;
|
|
propVariant.vt = VT_BOOL;
|
|
|
|
BOOL fUpToDate = ( ( cDocsFiltered == _cFilteredDocuments ) &&
|
|
( 0 == cToFilter ) );
|
|
|
|
if (( QUERY_RELIABILITY_STATUS(dwStatus) &
|
|
(STAT_CONTENT_OUT_OF_DATE | STAT_REFRESH_INCOMPLETE) ) ||
|
|
! fUpToDate )
|
|
{
|
|
propVariant.boolVal = VARIANT_TRUE;
|
|
ciGibDebugOut(( DEB_ITRACE, "The query is out of date\n" ));
|
|
variableSet.SetVariable( ISAPI_CI_OUT_OF_DATE, &propVariant, 0 );
|
|
}
|
|
|
|
if ( QUERY_RELIABILITY_STATUS(dwStatus) & STAT_CONTENT_QUERY_INCOMPLETE )
|
|
{
|
|
propVariant.boolVal = VARIANT_TRUE;
|
|
ciGibDebugOut(( DEB_ITRACE, "The query is incomplete\n" ));
|
|
variableSet.SetVariable( ISAPI_CI_QUERY_INCOMPLETE, &propVariant, 0 );
|
|
}
|
|
|
|
if ( QUERY_RELIABILITY_STATUS(dwStatus) & STAT_TIME_LIMIT_EXCEEDED )
|
|
{
|
|
propVariant.boolVal = VARIANT_TRUE;
|
|
ciGibDebugOut(( DEB_ITRACE, "The query timed out\n" ));
|
|
variableSet.SetVariable( ISAPI_CI_QUERY_TIMEDOUT, &propVariant, 0 );
|
|
}
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CWQueryItem::IsQueryDone - public
|
|
//
|
|
// History: 96-Mar-01 DwightKr Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL CWQueryItem::IsQueryDone()
|
|
{
|
|
Win4Assert( 0 != _pIRowsetStatus );
|
|
|
|
DWORD dwStatus = 0;
|
|
SCODE sc = _pIRowsetStatus->GetStatus( &dwStatus );
|
|
if ( FAILED( sc ) )
|
|
{
|
|
THROW( CException(sc) );
|
|
}
|
|
|
|
BOOL fQueryDone = FALSE;
|
|
|
|
if ( QUERY_FILL_STATUS(dwStatus) == STAT_DONE ||
|
|
QUERY_FILL_STATUS(dwStatus) == STAT_ERROR)
|
|
{
|
|
fQueryDone = TRUE;
|
|
}
|
|
|
|
return fQueryDone;
|
|
}
|
|
|
|
|
|
|
|
#if (DBG == 1)
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CWQueryItem::LokDump - public
|
|
//
|
|
// Arguments: [string] - buffer to send results to
|
|
//
|
|
// Synopsis: Dumps the state of the query
|
|
//
|
|
// History: 96-Jan-18 DwightKr Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
void CWQueryItem::LokDump( CVirtualString & string,
|
|
CVariableSet * pVariableSet,
|
|
COutputFormat * pOutputFormat )
|
|
{
|
|
if ( IsSequential() )
|
|
{
|
|
string.StrCat( L"<I>Sequential cursor</I><BR>\n" );
|
|
}
|
|
else
|
|
{
|
|
string.StrCat( L"<I>Non-Sequential cursor</I><BR>\n" );
|
|
}
|
|
|
|
if ( 0 != pVariableSet )
|
|
pVariableSet->Dump( string, *pOutputFormat );
|
|
|
|
WCHAR wcsBuffer[80];
|
|
LONG cwcBuffer = swprintf( wcsBuffer, L"Refcount=%d<BR>\n", _refCount );
|
|
string.StrCat( wcsBuffer, cwcBuffer );
|
|
|
|
cwcBuffer = swprintf( wcsBuffer, L"NextRecordNumber=%d<BR>\n", _lNextRecordNumber );
|
|
string.StrCat( wcsBuffer, cwcBuffer );
|
|
|
|
cwcBuffer = swprintf( wcsBuffer, L"SequenceNumber=%d<BR>\n", _ulSequenceNumber );
|
|
string.StrCat( wcsBuffer, cwcBuffer );
|
|
|
|
cwcBuffer = swprintf( wcsBuffer, L"IDQ File name=" );
|
|
string.StrCat( wcsBuffer, cwcBuffer );
|
|
string.StrCat( _idqFile.GetIDQFileName() );
|
|
string.StrCat( L"<BR>\n" );
|
|
|
|
cwcBuffer = swprintf( wcsBuffer, L"# documents filtered when query created=%d<BR>\n", _cFilteredDocuments );
|
|
string.StrCat( wcsBuffer, cwcBuffer );
|
|
|
|
string.StrCat( L"<P>\n" );
|
|
}
|
|
#endif // DBG
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CWPendingQueryItem::CWPendingQueryItem - public constructor
|
|
//
|
|
// Synposis: Builds a item for use to track an asynchronous query.
|
|
//
|
|
// Arguments: [queryItem] - query item that is pending
|
|
// [outputFormat] - output format supplied by the browser
|
|
// [variableSet] - browser supplied variables
|
|
//
|
|
// History: 96-Mar-01 DwightKr Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CWPendingQueryItem::CWPendingQueryItem( XPtr<CWQueryItem> & queryItem,
|
|
XPtr<COutputFormat> & outputFormat,
|
|
XPtr<CVariableSet> & variableSet ) :
|
|
|
|
_pQueryItem(queryItem.GetPointer()),
|
|
_pOutputFormat(outputFormat.GetPointer()),
|
|
_pVariableSet(variableSet.GetPointer())
|
|
{
|
|
queryItem.Acquire();
|
|
outputFormat.Acquire();
|
|
variableSet.Acquire();
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CWPendingQueryItem::~CWPendingQueryItem - public destructor
|
|
//
|
|
// Synposis: Destrolys a query item
|
|
//
|
|
// History: 96-Mar-01 DwightKr Created
|
|
// 96-Nov-25 dlee added header, moved out of .hxx
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CWPendingQueryItem::~CWPendingQueryItem()
|
|
{
|
|
Win4Assert( 0 != _pOutputFormat );
|
|
|
|
if ( _pOutputFormat->IsValid() )
|
|
{
|
|
TheWebQueryCache.DecrementActiveRequests();
|
|
ciGibDebugOut(( DEB_ITRACE, "~cwpendingqueryitem releasing session hse %d http %d\n",
|
|
HSE_STATUS_SUCCESS, HTTP_STATUS_OK ));
|
|
|
|
//
|
|
// Processing the query may not have been successful, but if so
|
|
// we wrote an error message, so from an isapi standpoint this was
|
|
// a success.
|
|
//
|
|
|
|
_pOutputFormat->SetHttpStatus( HTTP_STATUS_OK );
|
|
_pOutputFormat->ReleaseSession( HSE_STATUS_SUCCESS );
|
|
}
|
|
|
|
delete _pQueryItem;
|
|
delete _pOutputFormat;
|
|
delete _pVariableSet;
|
|
}
|
|
|
|
|
|
#if (DBG == 1)
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CWPendingQueryItem::LokDump - public
|
|
//
|
|
// Arguments: [string] - buffer to send results to
|
|
//
|
|
// Synopsis: Dumps the state of a pending query
|
|
//
|
|
// History: 96 Mar 20 Alanw Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
void CWPendingQueryItem::LokDump( CVirtualString & string )
|
|
{
|
|
if ( IsQueryDone() )
|
|
{
|
|
string.StrCat( L"<I>Completed query, </I>" );
|
|
}
|
|
else
|
|
{
|
|
string.StrCat( L"<I>Executing query, </I>" );
|
|
}
|
|
_pQueryItem->LokDump( string, _pVariableSet, _pOutputFormat );
|
|
}
|
|
#endif // DBG
|