867 lines
30 KiB
C++
867 lines
30 KiB
C++
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Microsoft WMI OLE DB Provider
|
|
//
|
|
// (C) Copyright 1999 Microsoft Corporation. All Rights Reserved.
|
|
//
|
|
// Module : CMDTEXT.CPP - ICommandText interface implementation
|
|
// Also has implementation of CUtlParam class
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
#include "headers.h"
|
|
#include "command.h"
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP_(ULONG) CImpICommandText::AddRef(void)
|
|
{
|
|
DEBUGCODE(InterlockedIncrement( (long*) &m_cRef));
|
|
|
|
return m_pcmd->GetOuterUnknown()->AddRef();
|
|
}
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP_(ULONG) CImpICommandText::Release(void)
|
|
{
|
|
DEBUGCODE(long lRef = InterlockedDecrement((long*)&m_cRef));
|
|
DEBUGCODE(if( lRef < 0 ){
|
|
ASSERT("Reference count on Object went below 0!")
|
|
})
|
|
|
|
return m_pcmd->GetOuterUnknown()->Release();
|
|
}
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP CImpICommandText::QueryInterface( REFIID riid, LPVOID * ppv )
|
|
{
|
|
return m_pcmd->GetOuterUnknown()->QueryInterface(riid, ppv);
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Echos the current command as text, including all post-processing operations added.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP CImpICommandText::GetCommandText( GUID* pguidDialect, LPOLESTR* ppwszCommand )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
CSetStructuredExceptionHandler seh;
|
|
|
|
TRY_BLOCK;
|
|
|
|
//===============================================================================
|
|
// At the creation of the CAutoBlock object a critical section
|
|
// is entered. This is because the method manipulates shared structures
|
|
// access to which must be serialized . The critical
|
|
// section is left when this method terminate and the destructor
|
|
// for CAutoBlock is called.
|
|
//===============================================================================
|
|
CAutoBlock cab( m_pcmd->GetCriticalSection() );
|
|
|
|
//===============================================================================
|
|
// Clear previous Error Object for this thread
|
|
//===============================================================================
|
|
g_pCError->ClearErrorInfo();
|
|
|
|
//===============================================================================
|
|
// Check Function Arguments
|
|
//===============================================================================
|
|
if ( ppwszCommand == NULL ){
|
|
|
|
hr = E_INVALIDARG;
|
|
}
|
|
else
|
|
//===============================================================================
|
|
// If the command has not been set, make sure the buffer
|
|
// contains an empty stringt to return to the consumer
|
|
//===============================================================================
|
|
if(!(m_pcmd->m_pQuery->GetStatus() & CMD_TEXT_SET)){
|
|
hr = DB_E_NOCOMMAND;
|
|
}
|
|
else
|
|
{
|
|
//===============================================================================
|
|
// Copy our saved text into the newly allocated string
|
|
//===============================================================================
|
|
m_pcmd->m_pQuery->GetQuery(*ppwszCommand);
|
|
|
|
//===============================================================================
|
|
// If the text we're giving back is a different dialect than was
|
|
// requested, let the caller know what dialect the text is in
|
|
//===============================================================================
|
|
if (pguidDialect && *pguidDialect != DBGUID_DEFAULT && *pguidDialect!= DBGUID_WQL &&
|
|
*pguidDialect != DBGUID_LDAP && *pguidDialect != GUID_NULL && *pguidDialect != DBGUID_WMI_METHOD
|
|
&& *pguidDialect != DBGUID_LDAPSQL){
|
|
hr = DB_S_DIALECTIGNORED;
|
|
}
|
|
}
|
|
|
|
if ( FAILED(hr) ){
|
|
if ( pguidDialect )
|
|
{
|
|
memset(pguidDialect, 0, sizeof(GUID));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(pguidDialect)
|
|
{
|
|
GUID guidTemp = m_pcmd->m_pQuery->GetDialectGuid();
|
|
memcpy(pguidDialect, &guidTemp,sizeof(GUID));
|
|
}
|
|
}
|
|
|
|
hr = hr != S_OK ? g_pCError->PostHResult(hr, &IID_ICommandText): hr;
|
|
|
|
CATCH_BLOCK_HRESULT(hr,L"ICommandText::GetCommandText");
|
|
return hr;
|
|
}
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Sets the current command text
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP CImpICommandText::SetCommandText( REFGUID rguidDialect, LPCOLESTR pwszCommand )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
VARIANT varQryLang;
|
|
|
|
VariantInit(&varQryLang);
|
|
|
|
CSetStructuredExceptionHandler seh;
|
|
|
|
TRY_BLOCK;
|
|
|
|
//=========================================================================
|
|
// At the creation of the CAutoBlock object a critical section
|
|
// is entered. This is because the method manipulates shared structures
|
|
// access to which must be serialized . The critical
|
|
// section is left when this method terminate and the destructor
|
|
// for CAutoBlock is called.
|
|
//=========================================================================
|
|
CAutoBlock cab( m_pcmd->GetCriticalSection() );
|
|
|
|
//=========================================================================
|
|
// Clear previous Error Object for this thread
|
|
//=========================================================================
|
|
g_pCError->ClearErrorInfo();
|
|
|
|
|
|
//=========================================================================
|
|
// Don't allow text to be set if we've got a rowset open
|
|
//=========================================================================
|
|
if ( m_pcmd->IsRowsetOpen() ){
|
|
return g_pCError->PostHResult((DB_E_OBJECTOPEN), &IID_ICommandText);
|
|
}
|
|
|
|
//=========================================================================
|
|
// Check Dialect
|
|
//=========================================================================
|
|
if (rguidDialect != DBGUID_WQL && rguidDialect != DBGUID_DEFAULT &&
|
|
rguidDialect != DBGUID_LDAP && rguidDialect != DBGUID_WMI_METHOD &&
|
|
rguidDialect != DBGUID_LDAPSQL){
|
|
|
|
return g_pCError->PostHResult((DB_E_DIALECTNOTSUPPORTED), &IID_ICommandText);
|
|
}
|
|
|
|
if(rguidDialect == DBGUID_WMI_METHOD)
|
|
{
|
|
m_pcmd->m_pQuery->SetType(METHOD_ROWSET);
|
|
}
|
|
//=========================================================================
|
|
// Unprepare if we've already got something prepared
|
|
//=========================================================================
|
|
m_pcmd->UnprepareHelper(UNPREPARE_NEW_CMD);
|
|
|
|
// NTRaid 134165
|
|
if(SUCCEEDED(hr = m_pcmd->GetQueryLanguage(varQryLang)))
|
|
{
|
|
//=========================================================================
|
|
// Delete the old text
|
|
//=========================================================================
|
|
if(SUCCEEDED(hr = m_pcmd->m_pQuery->InitQuery(varQryLang.bstrVal)))
|
|
{
|
|
//=========================================================================
|
|
// Save the new text
|
|
//=========================================================================
|
|
if (pwszCommand && *pwszCommand){
|
|
hr = m_pcmd->m_pQuery->SetQuery(pwszCommand,rguidDialect);
|
|
}
|
|
else{
|
|
//=========================================================================
|
|
// There is no text
|
|
//=========================================================================
|
|
hr = m_pcmd->m_pQuery->SetDefaultQuery();
|
|
}
|
|
}
|
|
}
|
|
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
// If everything is fine then set the datasource persist info to dirty
|
|
m_pcmd->m_pCDBSession->m_pCDataSource->SetPersistDirty();
|
|
|
|
// Clear the column information
|
|
SAFE_DELETE_PTR(m_pcmd->m_pColumns);
|
|
m_pcmd->m_cTotalCols = 0;
|
|
m_pcmd->m_cCols = 0;
|
|
m_pcmd->m_cNestedCols = 0;
|
|
}
|
|
|
|
VariantClear(&varQryLang);
|
|
hr = hr != S_OK ? g_pCError->PostHResult(hr, &IID_ICommandText): hr;
|
|
|
|
CATCH_BLOCK_HRESULT(hr,L"ICommandText::SetCommandText");
|
|
return hr;
|
|
}
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Return an interface from the session object that created this command object
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP CImpICommandText::GetDBSession( REFIID riid, IUnknown** ppSession)
|
|
{
|
|
HRESULT hr;
|
|
|
|
CSetStructuredExceptionHandler seh;
|
|
|
|
TRY_BLOCK;
|
|
|
|
//=========================================================================
|
|
// At the creation of the CAutoBlock object a critical section
|
|
// is entered. This is because the method manipulates shared structures
|
|
// access to which must be serialized . The critical
|
|
// section is left when this method terminate and the destructor
|
|
// for CAutoBlock is called.
|
|
//=========================================================================
|
|
CAutoBlock cab( m_pcmd->GetCriticalSection() );
|
|
|
|
//=========================================================================
|
|
// Clear previous Error Object for this thread
|
|
//=========================================================================
|
|
g_pCError->ClearErrorInfo();
|
|
|
|
//=========================================================================
|
|
// Check Arguments
|
|
//=========================================================================
|
|
if (ppSession == NULL){
|
|
|
|
return g_pCError->PostHResult((E_INVALIDARG), &IID_ICommandText);
|
|
}
|
|
|
|
//=========================================================================
|
|
// Initialize output param
|
|
//=========================================================================
|
|
*ppSession = NULL;
|
|
|
|
//=========================================================================
|
|
// Query for the interface on the session object. If failure,
|
|
// return the error from QueryInterface.
|
|
//=========================================================================
|
|
hr = (m_pcmd->m_pCDBSession->GetOuterUnknown())->QueryInterface(riid, (VOID**)ppSession);
|
|
|
|
hr = hr != S_OK ? g_pCError->PostHResult(hr, &IID_ICommandText): hr;
|
|
|
|
CATCH_BLOCK_HRESULT(hr,L"ICommandText::GetSession");
|
|
return hr;
|
|
}
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// The consumer can allocate a secondary thread in which to cancel
|
|
// the currently executing thread. This cancel will only succeed if
|
|
// the result set is still being generated. If the rowset object is being
|
|
// created, then it will be to late to cancel.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP CImpICommandText::Cancel(void)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
CSetStructuredExceptionHandler seh;
|
|
|
|
TRY_BLOCK;
|
|
|
|
//=========================================================================
|
|
// Clear previous Error Object for this thread
|
|
//=========================================================================
|
|
g_pCError->ClearErrorInfo();
|
|
|
|
m_pcmd->m_pQuery->m_pcsQuery->Enter();
|
|
if (m_pcmd->m_pQuery){
|
|
|
|
HRESULT retcode = m_pcmd->m_pQuery->CancelQuery();
|
|
if( S_OK == retcode){
|
|
m_pcmd->m_pQuery->InitQuery(); // ?
|
|
}
|
|
else{
|
|
hr = DB_E_CANTCANCEL;
|
|
}
|
|
m_pcmd->m_pQuery->SetCancelStatus(CMD_EXEC_CANCELED);
|
|
}
|
|
else{
|
|
m_pcmd->m_pQuery->SetCancelStatus(CMD_EXEC_CANCELED | CMD_EXEC_CANCELED_BEFORE_CQUERY_SET);
|
|
}
|
|
m_pcmd->m_pQuery->m_pcsQuery->Leave();
|
|
|
|
hr = hr != S_OK ? g_pCError->PostHResult(hr, &IID_ICommandText): hr;
|
|
|
|
CATCH_BLOCK_HRESULT(hr,L"ICommandText::Cancel");
|
|
return hr;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Execute the command.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP CImpICommandText::Execute( IUnknown* pUnkOuter,
|
|
REFIID riid, //@parm IN | Interface ID of the interface being queried for.
|
|
DBPARAMS* pParams, //@parm INOUT | Parameter Array
|
|
DBROWCOUNT* pcRowsAffected, //@parm OUT | count of rows affected by command
|
|
IUnknown** ppRowsets //@parm OUT | Pointer to interface that was instantiated
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CSetStructuredExceptionHandler seh;
|
|
VARIANT varQryLang;
|
|
|
|
VariantInit(&varQryLang);
|
|
|
|
TRY_BLOCK;
|
|
|
|
//=========================================================================
|
|
// At the creation of the CAutoBlock object a critical section is entered.
|
|
// This is because the method manipulates shared structures access to which
|
|
// must be serialized . The critical section is left when this method
|
|
// terminate and the destructor for CAutoBlock is called.
|
|
//=========================================================================
|
|
CAutoBlock cab( m_pcmd->GetCriticalSection() );
|
|
|
|
m_pcmd->m_pQuery->m_pcsQuery->Enter();
|
|
if (m_pcmd->m_pQuery->GetCancelStatus() & CMD_EXEC_CANCELED_BEFORE_CQUERY_SET){
|
|
|
|
m_pcmd->m_pQuery->ClearCancelStatus(CMD_EXEC_CANCELED | CMD_EXEC_CANCELED_BEFORE_CQUERY_SET);
|
|
}
|
|
if (m_pcmd->m_pQuery->GetStatus() & CMD_EXECUTED_ONCE){
|
|
|
|
m_pcmd->m_pQuery->ClearStatus(CMD_EXECUTED_ONCE);
|
|
}
|
|
// get the QueryLanguage Property and set it on the
|
|
// query object
|
|
// NTRaid 134165
|
|
if(SUCCEEDED(hr = m_pcmd->GetQueryLanguage(varQryLang)))
|
|
{
|
|
hr = m_pcmd->m_pQuery->SetQueryLanguage(varQryLang.bstrVal);
|
|
}
|
|
m_pcmd->m_pQuery->m_pcsQuery->Leave();
|
|
|
|
//=========================================================================
|
|
// Clear previous Error Object for this thread
|
|
//=========================================================================
|
|
g_pCError->ClearErrorInfo();
|
|
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
//=========================================================================
|
|
// Execute the command
|
|
//=========================================================================
|
|
hr = m_pcmd->Execute(pUnkOuter, riid, pParams, pcRowsAffected, ppRowsets);
|
|
}
|
|
|
|
VariantClear(&varQryLang);
|
|
CATCH_BLOCK_HRESULT(hr,L"ICommandText::Execute");
|
|
return hr;
|
|
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//*********************************************************************************************************
|
|
//
|
|
// CUtlParam class
|
|
//
|
|
//*********************************************************************************************************
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// This routine builds the binding information needed to execute a command with parameters
|
|
//
|
|
// HRESULT indicating status
|
|
// S_OK | No problem processing parameter or statement
|
|
// E_FAIL | Provider specific error
|
|
// E_OUTOFMEMORY | Not enough resources
|
|
// E_UNEXPECTED | Zombie State
|
|
// DB_E_BADACCESSORHANDLE | Accessor handle invalid
|
|
// DB_E_BADACCESSORTYPE | Non-Parameter Accessor used
|
|
// DB_E_BADPARAMETER | Parameter information not correct
|
|
// DB_E_BADPARAMETERCOUNT | Bad Parameter Count
|
|
// DB_E_DUPLICATEPARAM | Same parameter used twice
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP CUtlParam::BuildBindInfo( CCommand *pcmd, DBPARAMS *pParams, const IID* piid)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
// NTRaid::111812
|
|
// 06/07/00
|
|
PACCESSOR pAccessor = NULL;
|
|
DBORDINAL iBind;
|
|
DBCOUNTITEM iParamSet;
|
|
DBBINDING *pBind;
|
|
// DBTYPE wType;
|
|
ULONG cErrors = 0;
|
|
DBORDINAL iParam;
|
|
BYTE *pbData;
|
|
ULONG cBindInfo;
|
|
ULONG iDupBind;
|
|
WMIBINDINFO *pBindInfo;
|
|
BOOL fDeriveParamsFromSql = FALSE;
|
|
|
|
//==========================================================
|
|
// Copy DBPARAMS struct (C++ bitwise copy)
|
|
//==========================================================
|
|
m_dbparams = *pParams;
|
|
|
|
//==========================================================
|
|
// Add an extra reference count to the user's accessor,
|
|
// since we're now holding a pointer to it in m_dbparams
|
|
//==========================================================
|
|
m_pIAccessor = pcmd->GetIAccessorPtr();
|
|
m_pIAccessor->AddRefAccessor(m_dbparams.hAccessor, NULL);
|
|
|
|
//==========================================================
|
|
// Obtain pointer to the accessor that the user passed to us
|
|
//==========================================================
|
|
m_pIAccessor->GetAccessorPtr()->GetItemOfExtBuffer(pParams->hAccessor, &pAccessor);
|
|
m_cbRowSize = 999;
|
|
|
|
//==========================================================
|
|
// Make sure at least one binding for each parameter
|
|
//==========================================================
|
|
m_cParams = pcmd->GetParamCount();
|
|
if (pAccessor->cBindings < m_cParams){
|
|
hr = DB_E_PARAMNOTOPTIONAL;
|
|
}
|
|
else
|
|
{
|
|
//==========================================================
|
|
// Allocate mem ory for binding information
|
|
//==========================================================
|
|
iDupBind = m_cParams;
|
|
cBindInfo = max(m_cParams, pAccessor->cBindings);
|
|
m_prgBindInfo = new WMIBINDINFO[cBindInfo];
|
|
|
|
if (NULL == m_prgBindInfo){
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
else
|
|
{
|
|
memset(m_prgBindInfo, 0, sizeof(WMIBINDINFO)*cBindInfo);
|
|
|
|
//==========================================================
|
|
// Process each binding of the given accessor
|
|
//==========================================================
|
|
for (iBind = 0; iBind < pAccessor->cBindings; iBind++){
|
|
|
|
//======================================================
|
|
// Get the pointer to the binding of interest
|
|
//======================================================
|
|
pBind = pAccessor->rgBindings + iBind;
|
|
|
|
//======================================================
|
|
// Make sure this binding's ordinal is valid
|
|
//======================================================
|
|
if (!pBind->iOrdinal || pBind->iOrdinal > m_cParams){
|
|
|
|
//==================================================
|
|
// This is a bad accessor; set status if bound
|
|
//==================================================
|
|
SetStatus(pBind, DBSTATUS_E_BADACCESSOR);
|
|
|
|
//==================================================
|
|
// Count this error and look for more
|
|
//==================================================
|
|
cErrors++;
|
|
continue;
|
|
}
|
|
iParam = pBind->iOrdinal - 1;
|
|
|
|
//======================================================
|
|
// Save the binding
|
|
//======================================================
|
|
if (NULL == m_prgBindInfo[iParam].pBinding){
|
|
|
|
m_prgBindInfo[iParam].pBinding = pBind;
|
|
if (pBind->eParamIO & DBPARAMIO_OUTPUT)
|
|
m_prgBindInfo[iParam].wFlags |= DBPARAMIO_OUTPUT;
|
|
if (pBind->eParamIO & DBPARAMIO_INPUT)
|
|
m_prgBindInfo[iParam].wFlags |= DBPARAMIO_INPUT;
|
|
}
|
|
else {
|
|
|
|
//==================================================
|
|
// Multiple bindings for this parameter
|
|
//==================================================
|
|
pBindInfo = m_prgBindInfo + iDupBind++;
|
|
pBindInfo->pBinding = pBind;
|
|
pBindInfo->pNextBindInfo =
|
|
m_prgBindInfo[iParam].pNextBindInfo;
|
|
m_prgBindInfo[iParam].pNextBindInfo = pBindInfo;
|
|
if (pBind->eParamIO & DBPARAMIO_OUTPUT)
|
|
m_prgBindInfo[iParam].wFlags |= DBPARAMIO_OUTPUT;
|
|
if (pBind->eParamIO & DBPARAMIO_INPUT){
|
|
|
|
if (m_prgBindInfo[iParam].wFlags & DBPARAMIO_INPUT){
|
|
|
|
//==========================================
|
|
// A bad accessor; set status if bound
|
|
//==========================================
|
|
SetStatus(pBind, DBSTATUS_E_BADACCESSOR);
|
|
//==========================================
|
|
// Count this error and look for more
|
|
//==========================================
|
|
cErrors++;
|
|
continue;
|
|
}
|
|
m_prgBindInfo[iParam].wFlags |= DBPARAMIO_INPUT;
|
|
}
|
|
}
|
|
|
|
//======================================================
|
|
// Get the parameter type from the accessor
|
|
//======================================================
|
|
switch (pBind->eParamIO){
|
|
|
|
case DBPARAMIO_INPUT:
|
|
case DBPARAMIO_OUTPUT:
|
|
case DBPARAMIO_INPUT|DBPARAMIO_OUTPUT:
|
|
break;
|
|
|
|
case DBPARAMIO_NOTPARAM:
|
|
default:
|
|
// This is a bad accessor; set status if bound
|
|
SetStatus(pBind, DBSTATUS_E_BADACCESSOR);
|
|
|
|
// Count this error and look for more
|
|
cErrors++;
|
|
continue;
|
|
}
|
|
|
|
for (pbData = (BYTE*)m_dbparams.pData, iParamSet = 0;iParamSet < m_dbparams.cParamSets;pbData += m_cbRowSize, iParamSet++ ){
|
|
|
|
//=========================================================================
|
|
// If this is not an output param and we aren't given a value
|
|
// or a DBSTATUS_S_ISNULL, that's an error
|
|
//=========================================================================
|
|
BOOL fOutput = m_prgBindInfo[iParam].wFlags & DBPARAMIO_OUTPUT;
|
|
if ((!fOutput ) && !(pBind->dwPart & DBPART_VALUE) && (!(pBind->dwPart & DBPART_STATUS)
|
|
|| *(DBSTATUS *)((BYTE *)pbData + pBind->obStatus) != DBSTATUS_S_ISNULL) ) {
|
|
|
|
// This is a bad accessor; set status if bound
|
|
if (pBind->dwPart & DBPART_STATUS){
|
|
|
|
*(DBSTATUS *)(pbData + pBind->obStatus) =DBSTATUS_E_BADACCESSOR;
|
|
}
|
|
|
|
// Count this error and look for more
|
|
cErrors++;
|
|
break;
|
|
}
|
|
if ((pBind->dwPart & DBPART_STATUS) && DBSTATUS_S_DEFAULT == *(DBSTATUS*)((BYTE*)pbData + pBind->obStatus)) {
|
|
m_dwStatus |= CUTLPARAM_DEFAULT_PARAMS;
|
|
}
|
|
|
|
}
|
|
} // end of outer for loop
|
|
|
|
|
|
// Any errors in processing bindings?
|
|
if (cErrors){
|
|
hr = DB_E_ERRORSOCCURRED;
|
|
}
|
|
else
|
|
if (SUCCEEDED(hr = BuildParamInfo(pcmd, piid)))
|
|
{
|
|
|
|
for (iParam = 0; iParam < m_cParams; iParam++){
|
|
if ((m_prgBindInfo[iParam].wFlags & DBPARAMIO_INPUT) && !((m_prgBindInfo[iParam].pParamInfo->dwFlags & DBPARAMFLAGS_ISINPUT))
|
|
|| ((m_prgBindInfo[iParam].wFlags & DBPARAMIO_OUTPUT) && !(m_prgBindInfo[iParam].pParamInfo->dwFlags & DBPARAMFLAGS_ISOUTPUT))){
|
|
|
|
// This is a bad accessor; set status if bound
|
|
SetStatus(pBind, DBSTATUS_E_BADACCESSOR);
|
|
for (pBindInfo = m_prgBindInfo[iParam].pNextBindInfo; pBindInfo; pBindInfo = pBindInfo->pNextBindInfo)
|
|
SetStatus(pBindInfo->pBinding, DBSTATUS_E_BADACCESSOR);
|
|
|
|
// Count this error and look for more
|
|
cErrors++;
|
|
}
|
|
}
|
|
if (cErrors)
|
|
{
|
|
hr = DB_E_ERRORSOCCURRED;
|
|
}
|
|
}
|
|
} // if memory is allocated properly
|
|
|
|
} // else for checking for DB_E_PARAMNOTOPTIONAL error
|
|
|
|
|
|
hr = hr != S_OK ? g_pCError->PostHResult(hr, piid): hr;
|
|
return hr;
|
|
}
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// This routine builds the parameter information for the command from the binding information.
|
|
//
|
|
// HRESULT indicating status
|
|
// S_OK | No problem processing parameter or statement
|
|
// E_FAIL | Provider specific error
|
|
// E_OUTOFMEMORY | Not enough resources
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP CUtlParam::BuildParamInfo( CCommand *pcmd, const IID* piid )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
ULONG iParam(0);
|
|
PPARAMINFO pParamInfo;
|
|
DBBINDING *pBind;
|
|
BYTE* pbData = NULL;
|
|
DWORD* pdwLength;
|
|
DWORD dwLength(0);
|
|
DBSTATUS* pdwStatus;
|
|
DBSTATUS dwStatus(0);
|
|
DBLENGTH cbMaxLen(0);
|
|
VARIANT varValue;
|
|
|
|
VariantInit(&varValue);
|
|
|
|
m_rgpParamInfo = new PPARAMINFO[m_cParams];
|
|
if (NULL == m_rgpParamInfo)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
else
|
|
{
|
|
memset(m_rgpParamInfo, 0, sizeof(PPARAMINFO)*m_cParams);
|
|
|
|
for (iParam = 0; iParam < m_cParams; iParam++){
|
|
|
|
VariantClear(&varValue);
|
|
pParamInfo = pcmd->GetParamInfo(iParam);
|
|
if (pParamInfo){
|
|
|
|
m_rgpParamInfo[m_cParamInfo++] = pParamInfo;
|
|
|
|
pParamInfo->dwFlags = DBPARAMFLAGS_ISNULLABLE;
|
|
if (m_prgBindInfo[iParam].wFlags & DBPARAMIO_INPUT)
|
|
pParamInfo->dwFlags |= DBPARAMFLAGS_ISINPUT;
|
|
if (m_prgBindInfo[iParam].wFlags & DBPARAMIO_OUTPUT)
|
|
pParamInfo->dwFlags |= DBPARAMFLAGS_ISOUTPUT;
|
|
|
|
//=========================================================
|
|
// Bind the parameter
|
|
//=========================================================
|
|
pBind = GetBinding(m_prgBindInfo+iParam);
|
|
if( pBind ){
|
|
BindParamData(1, iParam+1, pBind, &pParamInfo->pbData, &pdwLength, (ULONG*)&pParamInfo->cbColLength, &pdwStatus, &dwStatus, &(pParamInfo->wOLEDBType));
|
|
|
|
//=========================================================
|
|
// Get the data type for variant params
|
|
//=========================================================
|
|
if (pParamInfo->wOLEDBType == DBTYPE_VARIANT && pParamInfo->pbData != NULL)
|
|
pParamInfo->wOLEDBType = V_VT((VARIANT *)pParamInfo->pbData);
|
|
|
|
// For variable length params, find the max len
|
|
cbMaxLen = 0;
|
|
if (DBTYPE_STR == pParamInfo->wOLEDBType || DBTYPE_WSTR == pParamInfo->wOLEDBType
|
|
|| DBTYPE_BSTR == pParamInfo->wOLEDBType || DBTYPE_BYTES == pParamInfo->wOLEDBType)
|
|
{
|
|
|
|
ULONG iParamSet;
|
|
DBTYPE wDstType = (DBTYPE_BSTR == pParamInfo->wOLEDBType) ? DBTYPE_WSTR : pParamInfo->wOLEDBType;
|
|
|
|
cbMaxLen = pBind->cbMaxLen;
|
|
|
|
for (iParamSet = 2; iParamSet <= m_dbparams.cParamSets; iParamSet++)
|
|
{
|
|
|
|
DBTYPE wSrcType;
|
|
|
|
//==========================================
|
|
// Bind the parameter
|
|
//==========================================
|
|
pBind = m_prgBindInfo[iParam].pBinding;
|
|
BindParamData(iParamSet, iParam+1, pBind, &pbData, &pdwLength, &dwLength, &pdwStatus, &dwStatus, &wSrcType);
|
|
|
|
cbMaxLen = pBind->cbMaxLen;
|
|
}
|
|
|
|
|
|
// Initialize the parameter info
|
|
BOOL bArray = FALSE;
|
|
CDataMap Map;
|
|
if(hr == S_OK)
|
|
{
|
|
hr = Map.MapOLEDBTypeToCIMType(pParamInfo->wOLEDBType, pParamInfo->CIMType ) ;
|
|
|
|
if( S_OK == hr ){
|
|
|
|
WORD wTmp = 0;
|
|
DBLENGTH uSize = 0;
|
|
DWORD dwFlags = 0;
|
|
|
|
// if the length as obtained from BindParamData is 0 and if the parameter
|
|
// is input then get the size of parameter for the type
|
|
if(pParamInfo->cbColLength == 0 && (pParamInfo->dwFlags & DBPARAMIO_INPUT))
|
|
{
|
|
hr = Map.MapCIMTypeToOLEDBType(pParamInfo->CIMType, wTmp, uSize, dwFlags );
|
|
if( hr == S_OK ){
|
|
|
|
pParamInfo->cbColLength = pParamInfo->cbValueMax = pParamInfo->ulParamSize = uSize;
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
m_prgBindInfo[iParam].pParamInfo = pParamInfo;
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//Exit:
|
|
hr = hr != S_OK ? g_pCError->PostHResult(E_OUTOFMEMORY, piid): hr;
|
|
return hr;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Sets the bind status for all parameters, except the one that caused the command to fail,
|
|
// to DBSTATUS_E_UNAVAILABLE.
|
|
//
|
|
// Nothing
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void CUtlParam::SetParamsUnavailable( ULONG iParamSetFailed, ULONG iParamFailed, BOOL fBackOut )
|
|
{
|
|
assert(iParamSetFailed);
|
|
|
|
ULONG iParam;
|
|
ULONG iParamSet;
|
|
BYTE* pbData;
|
|
PWMIBINDINFO pBindInfo;
|
|
|
|
for ( iParamSet = fBackOut? 1 : iParamSetFailed, pbData= (BYTE*)m_dbparams.pData + (iParamSet-1)*m_cbRowSize;
|
|
iParamSet <= m_dbparams.cParamSets; iParamSet++, pbData += m_cbRowSize){
|
|
|
|
for ( iParam = 1, pBindInfo = m_prgBindInfo; iParam <= m_cParams; iParam++, pBindInfo++){
|
|
DBSTATUS* pdbstatus = (DBSTATUS *) (pbData + pBindInfo->pBinding->obStatus);
|
|
|
|
if (pBindInfo->pBinding->dwPart & DBPART_STATUS){
|
|
|
|
if (iParamSet != iParamSetFailed || iParam != iParamFailed
|
|
|| *pdbstatus == DBSTATUS_S_OK
|
|
|| *pdbstatus == DBSTATUS_S_ISNULL
|
|
|| *pdbstatus == DBSTATUS_S_DEFAULT){
|
|
*pdbstatus = DBSTATUS_E_UNAVAILABLE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void CUtlParam::BindParamData( ULONG iParamSet, ULONG iParam, DBBINDING* pBinding,BYTE** ppbValue,
|
|
DWORD** ppdwLength, DWORD* pdwLength,DBSTATUS** ppdwStatus,
|
|
DBSTATUS* pdwStatus, DBTYPE* pdbtype )
|
|
{
|
|
assert(iParamSet && iParamSet <= m_dbparams.cParamSets);
|
|
assert(iParam && iParam <= m_cParams);
|
|
assert(pBinding);
|
|
assert(pBinding->iOrdinal == iParam);
|
|
assert(ppbValue);
|
|
assert(ppdwLength);
|
|
assert(pdwLength);
|
|
assert(ppdwStatus);
|
|
assert(pdwStatus);
|
|
BYTE* pbData = (BYTE*)m_dbparams.pData + (iParamSet-1)*m_cbRowSize;
|
|
|
|
*pdbtype = pBinding->wType & ~DBTYPE_BYREF;
|
|
if (pBinding->dwPart & DBPART_VALUE){
|
|
*ppbValue = pbData + pBinding->obValue;
|
|
|
|
if (pBinding->wType & DBTYPE_BYREF){
|
|
assert(!IsBadReadPtr(*ppbValue,sizeof(BYTE*)));
|
|
*ppbValue = *(BYTE**)*ppbValue;
|
|
}
|
|
}
|
|
else{
|
|
*ppbValue = NULL;
|
|
}
|
|
|
|
if (pBinding->dwPart & DBPART_STATUS){
|
|
assert(!IsBadReadPtr(pbData+pBinding->obStatus,sizeof(DBSTATUS)));
|
|
*ppdwStatus = (DBSTATUS*)(pbData + pBinding->obStatus);
|
|
*pdwStatus = **ppdwStatus;
|
|
}
|
|
else{
|
|
*ppdwStatus = NULL;
|
|
*pdwStatus = DBSTATUS_S_OK;
|
|
}
|
|
|
|
*ppdwLength = (pBinding->dwPart & DBPART_LENGTH) ? (DWORD*)(pbData + pBinding->obLength) : NULL;
|
|
if (*pdwStatus != DBSTATUS_S_OK || *ppbValue == NULL || pBinding->eParamIO == DBPARAMIO_OUTPUT){
|
|
*pdwLength = 0;
|
|
}
|
|
//NTRaid:111761
|
|
// 06/07/00
|
|
else
|
|
if(*ppdwLength)
|
|
{
|
|
*pdwLength = *(*ppdwLength);
|
|
}
|
|
else
|
|
{
|
|
*pdwLength = 0;
|
|
}
|
|
|
|
// check NULL data
|
|
if (*pdwStatus == DBSTATUS_S_OK && *ppbValue && (*pdbtype == DBTYPE_VARIANT || *pdbtype == DBTYPE_PROPVARIANT)
|
|
&& V_VT((VARIANT *)(*ppbValue)) == VT_NULL){
|
|
*pdwStatus = DBSTATUS_S_ISNULL;
|
|
}
|
|
}
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
ULONG CUtlParam::AddRef ( void)
|
|
{
|
|
return InterlockedIncrement( (long*) &m_cRef);
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
ULONG CUtlParam::Release(void)
|
|
{
|
|
assert( m_cRef > 0 );
|
|
ULONG cRef = InterlockedDecrement( (long*) &m_cRef);
|
|
if (!cRef)
|
|
delete this;
|
|
return cRef;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
CUtlParam::CUtlParam()
|
|
{
|
|
m_cRef = 0;
|
|
m_cbRowSize = 0;
|
|
m_cParams = 0;
|
|
m_cParamInfo = 0;
|
|
m_dwStatus = 0;
|
|
|
|
m_pIAccessor = NULL;
|
|
m_prgBindInfo = NULL;
|
|
m_rgpParamInfo = NULL;
|
|
}
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
CUtlParam::~CUtlParam()
|
|
{
|
|
} |