Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1141 lines
37 KiB

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 2000.
//
// File: datasrc.cxx
//
// Contents: Class factory description
//
// History: 3-30-97 MohamedN Created
//
//----------------------------------------------------------------------------
#include <pch.cxx>
#pragma hdrstop
#include <datasrc.hxx>
#include <session.hxx>
#include <cidbprop.hxx> // CDbProperties
#include <dbprpini.hxx> // 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<DBPROPSET> 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<cPropertySets; iSet++ )
{
// Remove any DBPROPSET_DBINIT values and mark them all
// as not settable
if( rgPropertySets[iSet].guidPropertySet == DBPROPSET_DBINIT )
{
fFoundDBINIT = true;
for(iProp=0; iProp<rgPropertySets[iSet].cProperties; iProp++)
{
rgPropertySets[iSet].rgProperties[iProp].dwStatus = DBPROPSTATUS_NOTSETTABLE;
}
}
else
{
// If not DBPROPSET_DBINIT then copy the DBPROPSET values
RtlCopyMemory( &(xaDbPropSet[iNewSet++]), &rgPropertySets[iSet], sizeof(DBPROPSET) );
}
}
// If we have no propertyset to pass on to the property handler,
// we can exit
if( 0 == iNewSet )
{
sc = DB_E_ERRORSOCCURRED;
}
else
{
sc = _UtlProps.SetProperties( iNewSet, xaDbPropSet.GetPointer() );
// If we have determined that one of the property sets was DBINIT, we may
// need to fixup the returned hr value.
if( fFoundDBINIT && (sc == S_OK) )
sc = DB_S_ERRORSOCCURRED;
}
}
else
{
// Note that CUtlProps knows about initialization, so we don't
// have to here. This sets members _bstrCatalog and _bstrMachine
// in CMDSProps
sc = _UtlProps.SetProperties( cPropertySets, rgPropertySets );
}
if ( FAILED(sc) )
THROW( CException(sc) );
}
CATCH( CException, e )
{
sc = _ErrorInfo.PostHResult( e, IID_IDBProperties );
}
END_CATCH;
UNTRANSLATE_EXCEPTIONS;
return sc;
} // CDatasrc::SetProperties
//+---------------------------------------------------------------------------
//
// Function: CDataSrc::GetPropertyInfo
//
// Synopsis: sets IDBProperties
//
// Arguments: [cPropertyIDSets] - number of property sets
// [rgPropertyIDSets] - array of property sets
// [pcPropertyInfoSets] - count of properties returned
// [prgPropertyInfoSets] - property information returned
// [ppDescBuffer] - buffer for returned descriptions
//
// Returns:
//
// History: 10-28-97 danleg created from Monarch
//
//----------------------------------------------------------------------------
STDMETHODIMP CDataSrc::GetPropertyInfo
(
ULONG cPropertyIDSets,
const DBPROPIDSET rgPropertyIDSets[],
ULONG * pcPropertyInfoSets,
DBPROPINFOSET ** prgPropertyInfoSets,
OLECHAR ** ppDescBuffer
)
{
ULONG ul;
ULONG cSpecialPropertySets = 0;
// Clear previous Error Object for this thread
_ErrorInfo.ClearErrorInfo();
// Initialize
if( pcPropertyInfoSets )
*pcPropertyInfoSets = 0;
if( prgPropertyInfoSets )
*prgPropertyInfoSets = 0;
if( ppDescBuffer )
*ppDescBuffer = 0;
// Check Arguments, on failure post HRESULT to error queue
if( ((cPropertyIDSets > 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<cPropertyIDSets; ul++)
{
if( rgPropertyIDSets[ul].cPropertyIDs &&
!(rgPropertyIDSets[ul].rgPropertyIDs) )
return _ErrorInfo.PostHResult( E_INVALIDARG, IID_IDBProperties );
}
//check the count of special propertySets
for(ul=0; ul<cPropertyIDSets; ul++)
{
if( (rgPropertyIDSets[ul].guidPropertySet ==DBPROPSET_DATASOURCEALL) ||
(rgPropertyIDSets[ul].guidPropertySet ==DBPROPSET_DATASOURCEINFOALL) ||
(rgPropertyIDSets[ul].guidPropertySet ==DBPROPSET_DBINITALL) ||
(rgPropertyIDSets[ul].guidPropertySet ==DBPROPSET_ROWSETALL) ||
(rgPropertyIDSets[ul].guidPropertySet ==DBPROPSET_SESSIONALL) )
cSpecialPropertySets++;
}
// if used SpecialPropertySets with non-special Propertysets
if ((cSpecialPropertySets > 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<IParserTreeProperties> 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<IColumnMapperCreator> xColMapCreator;
XInterface<IParserSession> 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<IUnknown> 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<WCHAR> 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<DBLITERALINFO> xaLiteralInfo( cLiterals );
XArrayOLE<WCHAR> 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; ulDex<cLiterals; ulDex++)
{
pdbLitInfo = &(xaLiteralInfo[ulNew]);
pdbLitInfo->lt = 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;
}