//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 2000. // // File: datasrc.cxx // // Contents: Class factory description // // History: 3-30-97 MohamedN Created // //---------------------------------------------------------------------------- #include #pragma hdrstop #include #include #include // CDbProperties #include // CGetDbInitProps // Datasource object interfaces that support ISupportErrorInfo static const GUID* apDataSrcErrInt[] = { &IID_IDBCreateSession, &IID_IDBInitialize, &IID_IDBProperties, &IID_IPersist, &IID_IDBInfo, }; static const ULONG cDataSrcErrInt = NUMELEM( apDataSrcErrInt ); //+--------------------------------------------------------------------------- // // Method: CDataSrc::CDataSrc // // Synopsis: ctor // // Arguments: pUnkOuter - outer unknown // // History: 3-30-97 mohamedn Created // 10-05-97 danleg _ErrorInfo // 10-30-97 danleg Prop info for Initialize/Uninitialize // Notes: // //---------------------------------------------------------------------------- CDataSrc::CDataSrc( IUnknown * pUnkOuter, IUnknown ** ppUnkInner ) : _cSessionCount(0), _fDSOInitialized(FALSE), _fGlobalViewsCreated(FALSE), _xIPVerify(new CImpIParserVerify()), _UtlProps(_xIPVerify.GetPointer()), #pragma warning(disable : 4355) _impIUnknown(this), _ErrorInfo( * ((IUnknown *) (IDBInitialize *) this), _mtxDSO ) #pragma warning(default : 4355) { _pUnkOuter = pUnkOuter ? pUnkOuter : (IUnknown *) &_impIUnknown; _ErrorInfo.SetInterfaceArray( cDataSrcErrInt, apDataSrcErrInt ); // SQL Text Parser // @devnote: The following is allocated since its existence is controlled // by AddRef and Release. SCODE sc = MakeIParser(((IParser**)_xIParser.GetQIPointer())); if( FAILED(sc) ) THROW( CException(sc) ); _UtlPropInfo.ExposeMinimalSets(); _UtlProps.ExposeMinimalSets(); *ppUnkInner = (IUnknown *) &_impIUnknown; (*ppUnkInner)->AddRef(); } //+--------------------------------------------------------------------------- // // Method: CDataSrc::~CDataSrc // // Synopsis: d-ctor // // Arguments: // // History: 3-30-97 mohamedn Created // 10-30-97 danleg Prop info for Initialize/Uninitialize //---------------------------------------------------------------------------- CDataSrc::~CDataSrc() { _UtlPropInfo.ExposeMaximalSets(); _UtlProps.ExposeMaximalSets(); } //+--------------------------------------------------------------------------- // // Member: CDataSrc::RealQueryInterface // // Synopsis: Supports IID_IUnknown, // IID_IDBInitialize, // IID_IDBProperties, // IID_IDBIPersist, // IID_IDBCreateSession // IID_IDBInfo // // History: 03-30-97 mohamedn created // 09-05-97 danleg added IDBInfo & ISupportErrorInfo // 01-29-98 danleg non delegating QI when not aggregated // //---------------------------------------------------------------------------- STDMETHODIMP CDataSrc::RealQueryInterface(REFIID riid, void **ppvObj ) { SCODE sc = S_OK; if ( !ppvObj ) return E_INVALIDARG; if ( riid == IID_IUnknown ) { *ppvObj = (void *) ( (IUnknown *) (IDBInitialize *) this ); } else if ( riid == IID_IDBInitialize ) { *ppvObj = (void *) (IDBInitialize *) this; } else if ( riid == IID_IDBProperties ) { *ppvObj = (void *) (IDBProperties *) this; } else if ( riid == IID_IPersist ) { *ppvObj = (void *) (IPersist *) this; } else if ( riid == IID_IDBCreateSession ) { // // The following interfaces are supported only if DSO is initialized // // Make sure we don't get uninitialized if ( _fDSOInitialized ) { *ppvObj = (void *) (IDBCreateSession *) this; } else { *ppvObj = 0; sc = E_UNEXPECTED; // per OLE DB spec. } } else if ( riid == IID_IDBInfo ) { *ppvObj = (void *) (IDBInfo *) this; } else if ( riid == IID_ISupportErrorInfo ) { *ppvObj = (void *) ((IUnknown *) (ISupportErrorInfo *) &_ErrorInfo); } else { *ppvObj = 0; sc = E_NOINTERFACE; } return sc; } // QueryInterface //+--------------------------------------------------------------------------- // // Method: CDataSrc::Initialize // // Synopsis: changes the DSO state to Initialized. // // Arguments: // // History: 3-30-97 mohamedn Created // //---------------------------------------------------------------------------- STDMETHODIMP CDataSrc::Initialize() { SCODE sc = S_OK; // Clear previous Error Object for this thread _ErrorInfo.ClearErrorInfo(); TRANSLATE_EXCEPTIONS; TRY { CLock lck( _mtxDSO ); if ( !_fDSOInitialized ) { // Expose non-init propsets sc = _UtlProps.ExposeMaximalSets(); if ( SUCCEEDED(sc) ) { // Expose propinfo for non-init propsets _UtlPropInfo.ExposeMaximalSets(); // OK, now we're initialized. _fDSOInitialized = TRUE; } else { THROW( CException(sc) ); } } else { THROW( CException(DB_E_ALREADYINITIALIZED) ); } } CATCH( CException, e ) { sc = _ErrorInfo.PostHResult( e, IID_IDBInitialize ); } END_CATCH; UNTRANSLATE_EXCEPTIONS; return sc; } //+--------------------------------------------------------------------------- // // Method: CDataSrc::Uninitialize // // Synopsis: changes the DSO state to Uninitialized. // // Arguments: // // History: 3-30-97 mohamedn Created // //---------------------------------------------------------------------------- STDMETHODIMP CDataSrc::Uninitialize() { SCODE sc = S_OK; // Clear previous Error Object for this thread _ErrorInfo.ClearErrorInfo(); TRANSLATE_EXCEPTIONS; TRY { CLock lck( _mtxDSO ); if ( 0 == _cSessionCount ) { // Hide non-init propsets _UtlProps.ExposeMinimalSets(); _UtlPropInfo.ExposeMinimalSets(); // Mark DSO as uninitialized _fDSOInitialized = FALSE; } else { THROW( CException(DB_E_OBJECTOPEN) ); } } CATCH( CException, e ) { sc = _ErrorInfo.PostHResult( e, IID_IDBInitialize ); } END_CATCH; UNTRANSLATE_EXCEPTIONS; return sc; } //+------------------------------------------------------------------------- // // Function: CDataSrc::GetProperties // // Synopsis: gets IDBProperties // // Arguments: [cPropertyIDSets] - number of desired property set IDs or 0 // [pPropIDSets] - array of desired property set IDs or NULL // [pcPropertySets] - number of property sets returned // [prgPropertySets] - array of returned property sets // // Returns: SCODE - result code indicating error return status. One of // S_OK, DB_S_ERRORSOCCURRED, E_INVALIDARG. // // History: 3-30-97 mohamedn Created // 10-30-97 danleg Chaned to use the Monarch prop code // //-------------------------------------------------------------------------- STDMETHODIMP CDataSrc::GetProperties ( ULONG cPropertySets, const DBPROPIDSET rgPropertySets[], ULONG * pcProperties, DBPROPSET ** prgProperties ) { SCODE sc = S_OK; // Clear previous Error Object for this thread _ErrorInfo.ClearErrorInfo(); TRANSLATE_EXCEPTIONS; TRY { CLock lck( _mtxDSO ); // Check Arguments _UtlProps.GetPropertiesArgChk( cPropertySets, rgPropertySets, pcProperties, prgProperties ); // Note that CUtlProps knows about initialization, // so we don't have to here. sc = _UtlProps.GetProperties( cPropertySets, rgPropertySets, pcProperties, prgProperties ); if ( FAILED(sc) ) THROW( CException(sc) ); } CATCH( CException, e ) { sc = _ErrorInfo.PostHResult( e, IID_IDBProperties ); } END_CATCH; UNTRANSLATE_EXCEPTIONS; return sc; } //+--------------------------------------------------------------------------- // // Function: CDataSrc::SetProperties // // Synopsis: sets IDBProperties // // Arguments: [cPropertySets] - number of property sets // [rgPropertySets] - array of property sets // // Returns: SCODE - result code indicating error return status. One of // S_OK, DB_S_ERRORSOCCURRED, E_INVALIDARG. // // History: 03-30-97 mohamedn created // 10-30-97 danleg Changed to use Monarch's prop code // //---------------------------------------------------------------------------- STDMETHODIMP CDataSrc::SetProperties ( ULONG cPropertySets, DBPROPSET rgPropertySets[] ) { // Clear previous Error Object for this thread _ErrorInfo.ClearErrorInfo(); // Quick return if the Count of Properties is 0 if( cPropertySets == 0 ) return S_OK; SCODE sc = S_OK; TRANSLATE_EXCEPTIONS; TRY { XArray xaDbPropSet; ULONG iNewSet, iSet, iProp; CLock lck( _mtxDSO ); _UtlProps.SetPropertiesArgChk( cPropertySets, rgPropertySets ); // We need to handle the DBINIT properties specially after being initialized. // - they should be treated as NOTSETTABLE at this point. if( _fDSOInitialized ) { Win4Assert( cPropertySets ); bool fFoundDBINIT = false; // Allocate a DBPROPSET structure of equal size xaDbPropSet.Init( cPropertySets ); for( iNewSet=0,iSet=0; iSet 0) && !rgPropertyIDSets ) || !pcPropertyInfoSets || !prgPropertyInfoSets ) return _ErrorInfo.PostHResult( E_INVALIDARG, IID_IDBProperties ); // New argument check for > 1 cPropertyIDs and NULL pointer for // array of property ids. for(ul=0; ul 0) && (cSpecialPropertySets < cPropertyIDSets)) { return _ErrorInfo.PostHResult( E_INVALIDARG, IID_IDBProperties ); } SCODE sc = S_OK; TRANSLATE_EXCEPTIONS; TRY { CLock lck( _mtxDSO ); sc = _UtlPropInfo.GetPropertyInfo( cPropertyIDSets, rgPropertyIDSets, pcPropertyInfoSets, prgPropertyInfoSets, ppDescBuffer ); if ( FAILED(sc) ) THROW( CException(sc) ); } CATCH( CException, e ) { sc = _ErrorInfo.PostHResult( e, IID_IDBProperties ); } END_CATCH; UNTRANSLATE_EXCEPTIONS; return sc; } //+--------------------------------------------------------------------------- // // Method: CDataSrc::CreateGlobalViews // // Synopsis: Creates global views (FILEINFO, WEBINFO etc.). These views // are removed when the IParser object goes away. // // Arguments: // // History: 01-09-98 danleg Created // //---------------------------------------------------------------------------- void CDataSrc::CreateGlobalViews( IParserSession * pIPSession ) { SCODE sc = S_OK; extern const LPWSTR s_pwszPredefinedViews; DBCOMMANDTREE * pDBCOMMANDTREE = 0; XInterface xIPTProperties; LCID lcid = GetDSPropsPtr()->GetValLong( CMDSProps::eid_DBPROPSET_DBINIT, CMDSProps::eid_INIT_LCID ); sc = pIPSession->ToTree( lcid, s_pwszPredefinedViews, &pDBCOMMANDTREE, xIPTProperties.GetPPointer() ); if ( FAILED(sc) ) THROW( CException(sc) ); _fGlobalViewsCreated = TRUE; } //+--------------------------------------------------------------------------- // // Method: CDataSrc::DupImpersonationToken, public // // Synopsis: Clients calling CreateSession can be impersonated. One such // client, SQL Server's Distributed Query Processor, stays // impersonated only for the duration of the call to CreateSession. // // This routine is called from CreateSession and caches the // impersonation token. This token is used to get back the security // context of the client during CreateCommand/OpenRowset. // // Arguments: // // History: 09-01-98 danleg Created // // Notes: Revisit if OLE DB defines "Integrated Security" differently in // the future, or defines a better security scheme. // //---------------------------------------------------------------------------- void CDataSrc::DupImpersonationToken ( HANDLE & hToken ) { DWORD dwLength = 0; NTSTATUS status = STATUS_SUCCESS; TOKEN_STATISTICS TokenInformation; HANDLE hTempToken; status = NtOpenThreadToken( GetCurrentThread(), TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE, TRUE, &hTempToken ); if ( !NT_SUCCESS(status) ) { if ( STATUS_NO_TOKEN == status ) { status = NtOpenProcessToken( GetCurrentProcess(), TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE, &hTempToken ); } if ( !NT_SUCCESS(status) ) { vqDebugOut(( DEB_ERROR, "DupImpersonationToken failed to get token, %x\n", status )); THROW( CException(status) ); } } SHandle xHandle( hTempToken ); HANDLE hNewToken = INVALID_HANDLE_VALUE; OBJECT_ATTRIBUTES ObjAttr; SECURITY_QUALITY_OF_SERVICE qos; qos.Length = sizeof( SECURITY_QUALITY_OF_SERVICE ); qos.ImpersonationLevel = SecurityImpersonation; qos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING; qos.EffectiveOnly = FALSE; InitializeObjectAttributes( &ObjAttr, NULL, 0, NULL, NULL ); ObjAttr.SecurityQualityOfService = &qos; status = NtDuplicateToken( hTempToken, TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_DUPLICATE, &ObjAttr, FALSE, TokenImpersonation, &hNewToken ); if ( !NT_SUCCESS(status) ) { vqDebugOut(( DEB_ERROR, "DupImpersonationToken failed to duplicate token, %x\n", status )); THROW( CException(HRESULT_FROM_WIN32(status)) ); } hToken = hNewToken; } //+--------------------------------------------------------------------------- // // Method: CDataSrc::CreateSession // // Synopsis: Associates a session with the DSO. // // Arguments: [pUnkOuter] - controlling unknown // [riid] - interface requested // [ppDBSession] - contains returned interface pointer // // History: 3-30-97 mohamedn Created // 1-10-98 danleg Added global views // //---------------------------------------------------------------------------- STDMETHODIMP CDataSrc::CreateSession( IUnknown * pUnkOuter, REFIID riid, IUnknown ** ppDBSession ) { _ErrorInfo.ClearErrorInfo(); if ( !ppDBSession ) return _ErrorInfo.PostHResult( E_INVALIDARG, IID_IDBCreateSession ); else *ppDBSession = 0; if ( !_fDSOInitialized ) return _ErrorInfo.PostHResult( E_UNEXPECTED, IID_IDBCreateSession ); if (0 != pUnkOuter && riid != IID_IUnknown) return _ErrorInfo.PostHResult( DB_E_NOAGGREGATION, IID_IDBCreateSession ); SCODE sc = S_OK; HANDLE hToken = INVALID_HANDLE_VALUE; TRANSLATE_EXCEPTIONS; TRY { XInterface xColMapCreator; XInterface xIPSession; CLock lck( _mtxDSO ); DupImpersonationToken( hToken ); // // Service Components set DBPROP_RESETDATASOURCE to indicate that the DSO has been // pooled. We need to reset the IParser object because it maintains state valid // across sessions (eg. views) // LONG lResetVal = _UtlProps.GetValLong( CMDSProps::eid_DBPROPSET_DATASOURCE, CMDSProps::eid_DBPROPVAL_RESETDATASOURCE); if ( DBPROPVAL_RD_RESETALL == lResetVal ) { // make sure there aren't any outstanding sessions when doing this. if ( 0 != _cSessionCount ) THROW( CException( E_INVALIDARG ) ); _xIParser.Free(); sc = MakeIParser( _xIParser.GetPPointer() ); if ( FAILED(sc) ) THROW( CException(sc) ); _UtlProps.SetValLong( CMDSProps::eid_DBPROPSET_DATASOURCE, CMDSProps::eid_DBPROPVAL_RESETDATASOURCE, 0L ); } // // Create an IParserSession object to pass to the session // _xIPVerify->GetColMapCreator( xColMapCreator.GetPPointer() ); sc = _xIParser->CreateSession( &DBGUID_MSSQLTEXT, GetDSPropsPtr()->GetValString( CMDSProps::eid_DBPROPSET_DBINIT, CMDSProps::eid_DBPROPVAL_INIT_LOCATION), _xIPVerify.GetPointer(), xColMapCreator.GetPointer(), xIPSession.GetPPointer() ); if ( FAILED(sc) ) THROW( CException(sc) ); LPCWSTR pwszCatalog = 0; pwszCatalog = GetDSPropsPtr()->GetValString( CMDSProps::eid_DBPROPSET_DATASOURCE, CMDSProps::eid_DBPROPVAL_CURRENTCATALOG); sc = xIPSession->SetCatalog( pwszCatalog ); if( FAILED(sc) ) THROW( CException(sc) ); // // Predefined views -- only once per DSO // if ( !_fGlobalViewsCreated ) CreateGlobalViews( xIPSession.GetPointer() ); // // Create the session object // XInterface xUnkInner; CDBSession *pDBSession = new CDBSession( *this, pUnkOuter, xUnkInner.GetPPointer(), xIPSession.GetPointer(), hToken ); // NOTE: pDBSession is the same object as xUnkInner. sc = xUnkInner->QueryInterface( riid, (void **) ppDBSession ); if ( FAILED(sc) ) THROW( CException(sc) ); } CATCH(CException, e) { sc = _ErrorInfo.PostHResult( e, IID_IDBCreateSession ); } END_CATCH; UNTRANSLATE_EXCEPTIONS; return sc; } //+--------------------------------------------------------------------------- // // Method: CDataSrc::GetClassID // // Synopsis: Return the CLSID for this server object // // Arguments: [pClassID] // // History: 3-30-97 mohamedn Created // 10-28-97 danleg added _ErrorInfo // //---------------------------------------------------------------------------- STDMETHODIMP CDataSrc::GetClassID ( CLSID *pClassID ) { _ErrorInfo.ClearErrorInfo(); if (pClassID) { RtlCopyMemory( pClassID, &CLSID_CiFwDSO, sizeof(CLSID) ); return S_OK; } else return _ErrorInfo.PostHResult( E_FAIL, IID_IPersist ); } //============================================================================ // LITERAL INFO Constants //============================================================================ // The following are constants that define literals that don't change.. When the buffer // to return literal information is allocated, it is initialized with this string and // then when a particular literal is asked for; a pointer in these values is used. static const LPWSTR LIT_BUFFER = L"\"\0.\0%\0_\0[]\0[]\0"; static const ULONG LIT_QUOTE_VALID_OFFSET = 0; static const ULONG LIT_CATALOG_SEP_VALID_OFFSET = LIT_QUOTE_VALID_OFFSET + NUMELEM(L"\""); static const ULONG LIT_PERCENT_VALID_OFFSET = LIT_CATALOG_SEP_VALID_OFFSET + NUMELEM(L"."); static const ULONG LIT_UNDERSCORE_VALID_OFFSET = LIT_PERCENT_VALID_OFFSET + NUMELEM(L"%"); static const ULONG LIT_ESCAPE_PERCENT_OFFSET = LIT_UNDERSCORE_VALID_OFFSET + NUMELEM(L"_"); static const ULONG LIT_ESCAPE_UNDERSCORE_OFFSET = LIT_ESCAPE_PERCENT_OFFSET + NUMELEM(L"[]"); static const ULONG LIT_CCH_INITIAL_BUFFER = LIT_ESCAPE_UNDERSCORE_OFFSET + NUMELEM(L"[]"); static const ULONG LIT_CB_INITIAL_BUFFER = LIT_CCH_INITIAL_BUFFER * sizeof(WCHAR); // List of unique Keywords that OLE DB does not define. static const WCHAR s_pwszKeyWords[] = {L"ARRAY,COERCE,CONTAINS,DEEP,DERIVATIONAL," L"EXCLUDE,FORMSOF,FREETEXT,INFLECTIONAL," L"ISABOUT,MATCHES,NEAR,PARAGRAPH,PASSTHROUGH," L"PROPERTYNAME,PROPID,RANKMETHOD,SENTENCE," L"SCOPE,SEARCH,SHALLOW,SOUNDEX,THESAURUS," L"TRAVERSAL,TYPE,WEIGHT,WORD"}; //+--------------------------------------------------------------------------- // // Function: CDataSrc::GetKeywords // // Synopsis: returns a list of provider specific keywords // // Arguments: [ppwszKeywords] - string containing returned list of comma // separated keywords // // Returns: HRESULT indicating the status of the method // S_OK | Keyword list retrieved // E_FAIL | Provider specific error (ODBC call failed) // E_OUTOFMEMORY | Buffer could not be allocated for the keywords. // E_INVALIDARG | Arguments did not match specification // // History: 09-05-97 danleg created from Monarch project // //---------------------------------------------------------------------------- STDMETHODIMP CDataSrc::GetKeywords(LPOLESTR* ppwszKeywords) { SCODE sc = S_OK; // Clear previous Error Object for this thread _ErrorInfo.ClearErrorInfo(); TRANSLATE_EXCEPTIONS; TRY { CLock lck( _mtxDSO ); // Check arguments if( ppwszKeywords ) { *ppwszKeywords = 0; // Check that object is initialized if( _fDSOInitialized ) { XArrayOLE xpwszKeyWords( NUMELEM(s_pwszKeyWords) ); RtlCopyMemory( xpwszKeyWords.GetPointer(), s_pwszKeyWords, sizeof(s_pwszKeyWords) ); *ppwszKeywords = xpwszKeyWords.Acquire(); } else { vqDebugOut(( DEB_TRACE, "Initialization must occur before IDBInfo can be called\n" )); sc = E_UNEXPECTED; } } else { sc = E_INVALIDARG; } if ( FAILED(sc) ) THROW( CException(sc) ); } CATCH( CException, e ) { sc = _ErrorInfo.PostHResult( e, IID_IDBInfo ); } END_CATCH; UNTRANSLATE_EXCEPTIONS; return sc; } //+--------------------------------------------------------------------------- // // Function: CDataSrc::GetLiteralInfo // // Synopsis: Retreives information about literals. Their length, and special // characters and whether they are actually supported. // // Arguments: [cLiterals] - Number of literals being asked about // [rgLiterals] - Array of literals being asked about // [pcLiteralInfo] - Contains returned number of literals // [prgLiteralInfo] - Contains returned literal information // [ppCharBuffer] - Buffer for returned string values // // Returns: HRESULT indicating the status of the method // S_OK | Keyword list retrieved // E_FAIL | Provider specific error (ODBC call failed) // E_OUTOFMEMORY | Buffer could not be allocated for the keywords. // E_INVALIDARG | Arguments did not match specification // // History: 09-05-97 danleg created from Monarch project // //---------------------------------------------------------------------------- STDMETHODIMP CDataSrc::GetLiteralInfo ( ULONG cLiterals, const DBLITERAL rgLiterals[], ULONG* pcLiteralInfo, DBLITERALINFO** prgLiteralInfo, OLECHAR** ppCharBuffer ) { SCODE sc = S_OK; const DWORD LITERAL_NORESTRICTIONS = 0x00000001; const DWORD LITERAL_FAILURE = 0x00000002; const DWORD LITERAL_SUCCESS = 0x00000004; const static DBLITERAL s_rgSupportedLiterals[] = { DBLITERAL_BINARY_LITERAL, DBLITERAL_CATALOG_NAME, DBLITERAL_CATALOG_SEPARATOR, DBLITERAL_CHAR_LITERAL, DBLITERAL_COLUMN_NAME, DBLITERAL_CORRELATION_NAME, DBLITERAL_ESCAPE_PERCENT, DBLITERAL_ESCAPE_UNDERSCORE, DBLITERAL_LIKE_PERCENT, DBLITERAL_LIKE_UNDERSCORE, DBLITERAL_TABLE_NAME, DBLITERAL_TEXT_COMMAND, DBLITERAL_VIEW_NAME, DBLITERAL_QUOTE_PREFIX, DBLITERAL_QUOTE_SUFFIX }; // Clear previous Error Object for this thread _ErrorInfo.ClearErrorInfo(); // Initialize if( pcLiteralInfo ) *pcLiteralInfo = 0; if( prgLiteralInfo ) *prgLiteralInfo = 0; if( ppCharBuffer ) *ppCharBuffer = 0; // Check Arguments if( ((cLiterals > 0) && !rgLiterals) || !pcLiteralInfo || !ppCharBuffer || !prgLiteralInfo ) { return _ErrorInfo.PostHResult( E_INVALIDARG, IID_IDBInfo ); } TRANSLATE_EXCEPTIONS; TRY { ULONG ulDex, ulNew; DWORD dwStatus = 0; DBLITERALINFO* pdbLitInfo; CLock lck( _mtxDSO ); // We must be initialized if( !_fDSOInitialized ) { vqDebugOut(( DEB_TRACE, "Initialization must occur before IDBInfo can be called\n" )); return _ErrorInfo.PostHResult( E_UNEXPECTED, IID_IDBInfo ); } // Allocate Memory for literal information if( cLiterals == 0 ) { dwStatus |= LITERAL_NORESTRICTIONS; cLiterals = NUMELEM( s_rgSupportedLiterals ); rgLiterals = s_rgSupportedLiterals; } XArrayOLE xaLiteralInfo( cLiterals ); XArrayOLE xaCharBuffer( LIT_CCH_INITIAL_BUFFER ); // Initialize the first part of the buffer with our // static set of literal information RtlCopyMemory( xaCharBuffer.GetPointer(), LIT_BUFFER, LIT_CB_INITIAL_BUFFER ); // Process each of the DBLITERAL values that are in the // restriction array or that we potentially could support for(ulDex=0, ulNew=0; ulDexlt = rgLiterals[ulDex]; pdbLitInfo->fSupported = TRUE; pdbLitInfo->pwszLiteralValue = 0; pdbLitInfo->pwszInvalidChars = 0; pdbLitInfo->pwszInvalidStartingChars = 0; switch( rgLiterals[ulDex] ) { case DBLITERAL_TEXT_COMMAND: case DBLITERAL_CHAR_LITERAL: case DBLITERAL_BINARY_LITERAL: case DBLITERAL_TABLE_NAME: pdbLitInfo->cchMaxLen = ~0; break; case DBLITERAL_CATALOG_NAME: case DBLITERAL_COLUMN_NAME: case DBLITERAL_CORRELATION_NAME: case DBLITERAL_VIEW_NAME: pdbLitInfo->cchMaxLen = 128; break; case DBLITERAL_CATALOG_SEPARATOR: pdbLitInfo->cchMaxLen = 1; // L'.'; pdbLitInfo->pwszLiteralValue = xaCharBuffer.GetPointer() + LIT_CATALOG_SEP_VALID_OFFSET; break; case DBLITERAL_ESCAPE_PERCENT: pdbLitInfo->cchMaxLen = 2; // L"[]"; pdbLitInfo->pwszLiteralValue = xaCharBuffer.GetPointer() + LIT_ESCAPE_PERCENT_OFFSET; break; case DBLITERAL_ESCAPE_UNDERSCORE: pdbLitInfo->cchMaxLen = 2; // L"[]"; pdbLitInfo->pwszLiteralValue = xaCharBuffer.GetPointer() + LIT_ESCAPE_UNDERSCORE_OFFSET; break; case DBLITERAL_LIKE_PERCENT: pdbLitInfo->cchMaxLen = 1; // L'%'; pdbLitInfo->pwszLiteralValue = xaCharBuffer.GetPointer() + LIT_PERCENT_VALID_OFFSET; break; case DBLITERAL_LIKE_UNDERSCORE: pdbLitInfo->cchMaxLen = 1; // L'_'; pdbLitInfo->pwszLiteralValue = xaCharBuffer.GetPointer() + LIT_UNDERSCORE_VALID_OFFSET; break; case DBLITERAL_QUOTE_PREFIX: case DBLITERAL_QUOTE_SUFFIX: pdbLitInfo->cchMaxLen = 1; // L'"'; pdbLitInfo->pwszLiteralValue = xaCharBuffer.GetPointer() + LIT_QUOTE_VALID_OFFSET; break; default: pdbLitInfo->cchMaxLen = 0; // If we are given a dbLiteral that we do not // support, just set the fSupport flag false // and continue on. pdbLitInfo->fSupported = FALSE; break; } // If we are returning all the supported literals, then // we need to drop any that are fSupported = FALSE; if( dwStatus & LITERAL_NORESTRICTIONS ) { if( pdbLitInfo->fSupported == FALSE ) continue; } else { if( pdbLitInfo->fSupported == FALSE ) dwStatus |= LITERAL_FAILURE; else dwStatus |= LITERAL_SUCCESS; } ulNew++; } sc = (dwStatus & LITERAL_FAILURE) ? ((dwStatus & LITERAL_SUCCESS) ? DB_S_ERRORSOCCURRED : DB_E_ERRORSOCCURRED) : S_OK; *pcLiteralInfo = ulNew; // We only want to return the string buffer if it // is a success if ( SUCCEEDED(sc) ) *ppCharBuffer = xaCharBuffer.Acquire(); // We want to return the LiteralInfo on success and on // a DB_E_ERRORSOCCURRED failure if ( SUCCEEDED(sc) || (sc == DB_E_ERRORSOCCURRED) ) *prgLiteralInfo = xaLiteralInfo.Acquire(); if ( FAILED(sc) ) THROW( CException(sc) ); } CATCH( CException, e ) { sc = _ErrorInfo.PostHResult( e, IID_IDBInfo ); } END_CATCH; UNTRANSLATE_EXCEPTIONS; return sc; }