//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1996 - 2000. // // File: wqitem.cxx // // Contents: WEB Query item class // // History: 96/Jan/3 DwightKr Created // //---------------------------------------------------------------------------- #include #pragma hdrstop #include 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 & wcsColumns, XPtr & dbColumns, CDynArray & 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 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 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 xpCat; XPtrST 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 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 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 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 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 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 xVariables( cCols ); for ( ULONG i=0; iAtEnd(); 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; iGetFirstRecordNumber() == 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"Sequential cursor
\n" ); } else { string.StrCat( L"Non-Sequential cursor
\n" ); } if ( 0 != pVariableSet ) pVariableSet->Dump( string, *pOutputFormat ); WCHAR wcsBuffer[80]; LONG cwcBuffer = swprintf( wcsBuffer, L"Refcount=%d
\n", _refCount ); string.StrCat( wcsBuffer, cwcBuffer ); cwcBuffer = swprintf( wcsBuffer, L"NextRecordNumber=%d
\n", _lNextRecordNumber ); string.StrCat( wcsBuffer, cwcBuffer ); cwcBuffer = swprintf( wcsBuffer, L"SequenceNumber=%d
\n", _ulSequenceNumber ); string.StrCat( wcsBuffer, cwcBuffer ); cwcBuffer = swprintf( wcsBuffer, L"IDQ File name=" ); string.StrCat( wcsBuffer, cwcBuffer ); string.StrCat( _idqFile.GetIDQFileName() ); string.StrCat( L"
\n" ); cwcBuffer = swprintf( wcsBuffer, L"# documents filtered when query created=%d
\n", _cFilteredDocuments ); string.StrCat( wcsBuffer, cwcBuffer ); string.StrCat( L"

\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 & queryItem, XPtr & outputFormat, XPtr & 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"Completed query, " ); } else { string.StrCat( L"Executing query, " ); } _pQueryItem->LokDump( string, _pVariableSet, _pOutputFormat ); } #endif // DBG