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.

682 lines
23 KiB

  1. ////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2. // Microsoft WMI OLE DB Provider
  3. //
  4. // (C) Copyright 1999 Microsoft Corporation. All Rights Reserved.
  5. //
  6. // Module : CMDPARAM.CPP - ICommandWithParameters interface implementation
  7. //
  8. ////////////////////////////////////////////////////////////////////////////////////////////////////////////
  9. #include "headers.h"
  10. #include "command.h"
  11. ////////////////////////////////////////////////////////////////////////////////////////////////////////////
  12. //
  13. // Increments a reference count for the object.
  14. //
  15. ////////////////////////////////////////////////////////////////////////////////////////////////////////////
  16. STDMETHODIMP_(ULONG) CImpICommandWithParameters::AddRef(void)
  17. {
  18. DEBUGCODE(InterlockedIncrement((long*)&m_cRef));
  19. return m_pcmd->AddRef();
  20. }
  21. ////////////////////////////////////////////////////////////////////////////////////////////////////////////
  22. //
  23. // Decrement the object's reference count and deletes the object when the new reference count is zero.
  24. //
  25. ////////////////////////////////////////////////////////////////////////////////////////////////////////////
  26. STDMETHODIMP_(ULONG) CImpICommandWithParameters::Release(void)
  27. {
  28. DEBUGCODE(long lRef = InterlockedDecrement((long*)&m_cRef));
  29. DEBUGCODE(if( lRef < 0 ){
  30. ASSERT("Reference count on Object went below 0!")
  31. });
  32. return m_pcmd->GetOuterUnknown()->Release();
  33. }
  34. ////////////////////////////////////////////////////////////////////////////////////////////////////////////
  35. //
  36. // Returns a pointer to a specified interface. Callers use QueryInterface to determine which interfaces the
  37. // called object supports.
  38. //
  39. ////////////////////////////////////////////////////////////////////////////////////////////////////////////
  40. STDMETHODIMP CImpICommandWithParameters::QueryInterface( REFIID riid, LPVOID * ppv )
  41. {
  42. return m_pcmd->QueryInterface(riid, ppv);
  43. }
  44. ////////////////////////////////////////////////////////////////////////////////////////////////////////////
  45. //
  46. // Get a list of the command's parameters, their names, and their required types.
  47. //
  48. ////////////////////////////////////////////////////////////////////////////////////////////////////////////
  49. STDMETHODIMP CImpICommandWithParameters::GetParameterInfo( DB_UPARAMS* pcParams, DBPARAMINFO** prgParamInfo, OLECHAR** ppNamesBuffer )
  50. {
  51. HRESULT hr = S_OK;
  52. CSetStructuredExceptionHandler seh;
  53. TRY_BLOCK;
  54. //=========================================================
  55. // Serialize access
  56. //=========================================================
  57. CAutoBlock cab(m_pcmd->GetCriticalSection());
  58. //=========================================================
  59. // Clear previous Error Object for this thread
  60. //=========================================================
  61. g_pCError->ClearErrorInfo();
  62. //=========================================================
  63. // Initialize buffers
  64. //=========================================================
  65. if ( pcParams )
  66. {
  67. *pcParams = 0;
  68. }
  69. if ( prgParamInfo )
  70. {
  71. *prgParamInfo = NULL;
  72. }
  73. if ( ppNamesBuffer )
  74. {
  75. *ppNamesBuffer = NULL;
  76. }
  77. //=========================================================
  78. // Validate Agruments
  79. //=========================================================
  80. if ( (pcParams == NULL) || (prgParamInfo == NULL) )
  81. {
  82. hr = E_INVALIDARG;
  83. }
  84. else
  85. //=========================================================
  86. // If the consumer has not supplied parameter information.
  87. //=========================================================
  88. if ( m_pcmd->m_pQuery->GetParamCount() == 0 )
  89. {
  90. //=====================================================
  91. // Command Object must be in prepared state
  92. //=====================================================
  93. if ( !(m_pcmd->m_pQuery->GetStatus() & CMD_READY) )
  94. {
  95. hr = DB_E_NOTPREPARED;
  96. }
  97. }
  98. if(SUCCEEDED(hr))
  99. {
  100. hr = m_pcmd->GetParameterInfo(pcParams, prgParamInfo, ppNamesBuffer, &IID_ICommandWithParameters);
  101. }
  102. hr = hr == S_OK ? hr : g_pCError->PostHResult(hr,&IID_ICommandWithParameters);
  103. CATCH_BLOCK_HRESULT(hr,L"ICommandWithParameters::GetParameterInfo");
  104. return hr;
  105. }
  106. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  107. //
  108. // Map parameter names to parameter ordinals
  109. //
  110. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  111. STDMETHODIMP CImpICommandWithParameters::MapParameterNames( DB_UPARAMS cParamNames, const OLECHAR* rgParamNames[], DB_LPARAMS rgParamOrdinals[] )
  112. {
  113. HRESULT hr = S_OK;
  114. CSetStructuredExceptionHandler seh;
  115. TRY_BLOCK;
  116. //=========================================================
  117. // Serialize access
  118. //=========================================================
  119. CAutoBlock cab(m_pcmd->GetCriticalSection());
  120. //==============================================================
  121. // Clear previous Error Object for this thread
  122. //==============================================================
  123. g_pCError->ClearErrorInfo();
  124. if(cParamNames != 0)
  125. {
  126. if (rgParamNames == NULL || rgParamOrdinals == NULL){
  127. hr = E_INVALIDARG;
  128. }
  129. else
  130. //==============================================================
  131. // If the consumer has not supplied parameter information.
  132. //==============================================================
  133. if ( m_pcmd->m_pQuery->GetParamCount() == 0 ){
  134. //==========================================================
  135. // Command Text must be set
  136. //==========================================================
  137. if (!(m_pcmd->m_pQuery->GetStatus() & CMD_TEXT_SET)){
  138. hr = DB_E_NOCOMMAND;
  139. }
  140. else
  141. //==========================================================
  142. // Command Object must be in prepared state
  143. //==========================================================
  144. if ( !(m_pcmd->m_pQuery->GetStatus() & CMD_READY) ){
  145. hr = DB_E_NOTPREPARED;
  146. }
  147. }
  148. if(SUCCEEDED(hr))
  149. {
  150. hr = m_pcmd->MapParameterNames(cParamNames, rgParamNames, rgParamOrdinals, &IID_ICommandWithParameters);
  151. }
  152. }
  153. hr = hr == S_OK ? hr : g_pCError->PostHResult(hr,&IID_ICommandWithParameters);
  154. CATCH_BLOCK_HRESULT(hr,L"ICommandWithParameters::MapParameterNames");
  155. return hr;
  156. }
  157. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  158. //
  159. // Override the provider's parameter information.
  160. //
  161. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  162. STDMETHODIMP CImpICommandWithParameters::SetParameterInfo( DB_UPARAMS cParams, const DB_UPARAMS rgParamOrdinals[], const DBPARAMBINDINFO rgParamBindInfo[] )
  163. {
  164. ULONG i;
  165. BOOL fNamedParams = (cParams > 0) ? TRUE : FALSE;
  166. HRESULT hr = S_OK;
  167. CSetStructuredExceptionHandler seh;
  168. TRY_BLOCK;
  169. //=========================================================
  170. // Serialize access
  171. //=========================================================
  172. CAutoBlock cab(m_pcmd->GetCriticalSection());
  173. //===================================================================
  174. // Clear previous Error Object for this thread
  175. //===================================================================
  176. g_pCError->ClearErrorInfo();
  177. if ( (cParams != 0) && (rgParamOrdinals == NULL) ){
  178. hr = E_INVALIDARG;
  179. }
  180. else
  181. {
  182. //===================================================================
  183. // Scan for invalid arguments in the arrays
  184. //===================================================================
  185. for( i = 0; i < cParams; i++ ){
  186. if ( !rgParamOrdinals[i] || (rgParamBindInfo && !(rgParamBindInfo[i].pwszDataSourceType)) ) {
  187. hr = E_INVALIDARG;
  188. }
  189. else
  190. if (rgParamBindInfo && rgParamBindInfo[i].pwszName == NULL)
  191. {
  192. fNamedParams = FALSE;
  193. }
  194. }
  195. if(SUCCEEDED(hr))
  196. {
  197. //===================================================================
  198. // Don't allow parameters to be set if we've got a rowset open
  199. //===================================================================
  200. if ( m_pcmd->IsRowsetOpen() ){
  201. hr = DB_E_OBJECTOPEN;
  202. }
  203. else
  204. {
  205. //===================================================================
  206. // Need to unprepare the statement when parameter info is changed and
  207. // set named params
  208. //===================================================================
  209. if ((m_pcmd->m_pQuery->GetStatus() & CMD_READY) && m_pcmd->m_pQuery->GetParamCount() > 0 && fNamedParams){
  210. m_pcmd->UnprepareHelper(UNPREPARE_RESET_STMT);
  211. }
  212. hr = m_pcmd->SetParameterInfo(cParams, rgParamOrdinals, rgParamBindInfo);
  213. }
  214. }
  215. }
  216. hr = hr == S_OK ? hr : g_pCError->PostHResult(hr,&IID_ICommandWithParameters);
  217. CATCH_BLOCK_HRESULT(hr,L"ICommandWithParameters::SetParameterInfo");
  218. return hr;
  219. }
  220. ////////////////////////////////////////////////////////////////////////////////////////////////////////////
  221. //
  222. // Get a list of the command's parameters, their names, and their required types.
  223. //
  224. ////////////////////////////////////////////////////////////////////////////////////////////////////////////
  225. HRESULT CCommand::GetParameterInfo( DB_UPARAMS* pcParams, DBPARAMINFO** prgDBParamInfo, WCHAR** ppNamesBuffer, const IID* piid )
  226. {
  227. HRESULT hr = S_OK;
  228. SHORT sw = 0;
  229. ULONG cNumParams = 0;
  230. ULONG cbNames = 0;
  231. DBPARAMINFO* pTempInfo;
  232. WCHAR* pwszNameBuffer;
  233. PPARAMINFO pParamInfo;
  234. ULONG iParam;
  235. //=================================================================================
  236. // If the consumer has set info for at least one parameter,
  237. // we only return info on the parameters set by the consumer
  238. //=================================================================================
  239. if (m_pQuery->GetParamCount() > 0){
  240. //=============================================================================
  241. // Count the params set by the consumer
  242. //=============================================================================
  243. cNumParams = 0;
  244. for (iParam = 0; iParam <(unsigned) m_pQuery->GetParamCount(); iParam++){
  245. pParamInfo = (PPARAMINFO)m_pQuery->GetParam(iParam);
  246. if (pParamInfo){
  247. cNumParams++;
  248. if (ppNamesBuffer && pParamInfo->pwszParamName)
  249. cbNames += (wcslen(pParamInfo->pwszParamName)+1)*sizeof(WCHAR);
  250. }
  251. }
  252. }
  253. else{
  254. hr = S_OK;
  255. if (!m_pQuery->m_prgProviderParamInfo && m_pQuery->GetParamCount()){
  256. //=========================================================================
  257. // Get the parameter info
  258. //=========================================================================
  259. hr = GetParamInfo(piid);
  260. }
  261. if( hr == S_OK ){
  262. cNumParams = m_pQuery->GetParamCount();
  263. if (ppNamesBuffer){
  264. for (iParam = 0; iParam < cNumParams; iParam++){
  265. pParamInfo = m_pQuery->m_prgProviderParamInfo + iParam;
  266. if (pParamInfo->pwszParamName)
  267. cbNames += (wcslen(pParamInfo->pwszParamName)+1)*sizeof(WCHAR);
  268. }
  269. }
  270. }
  271. }
  272. //==================================================================================
  273. // Check if we have any parameters
  274. //==================================================================================
  275. if ( cNumParams ){
  276. //==============================================================================
  277. // Allocate memory to return the information
  278. //==============================================================================
  279. *prgDBParamInfo = (DBPARAMINFO*)g_pIMalloc->Alloc(cNumParams*sizeof(DBPARAMINFO));
  280. if ( !*prgDBParamInfo ){
  281. hr = g_pCError->PostHResult(E_OUTOFMEMORY, piid);
  282. }
  283. else{
  284. hr = S_OK;
  285. if (cbNames){
  286. *ppNamesBuffer = (WCHAR*)g_pIMalloc->Alloc(cbNames);
  287. if (!*ppNamesBuffer){
  288. hr = g_pCError->PostHResult(E_OUTOFMEMORY, piid);
  289. }
  290. }
  291. if( S_OK == hr ){
  292. //======================================================================
  293. // Initialize memory
  294. //======================================================================
  295. memset(*prgDBParamInfo, 0, (cNumParams*sizeof(DBPARAMINFO)));
  296. //======================================================================
  297. // Describe the Parameter Markers
  298. //======================================================================
  299. if (m_pQuery->GetParamCount() > 0){
  300. //==================================================================
  301. // Return the parameter information set by the consumer
  302. //==================================================================
  303. pwszNameBuffer = ppNamesBuffer? *ppNamesBuffer : NULL;
  304. pTempInfo = *prgDBParamInfo;
  305. for (iParam = 0; iParam < (unsigned)m_pQuery->GetParamCount(); iParam++) {
  306. pParamInfo = (PPARAMINFO) m_pQuery->GetParam(iParam);
  307. if (!pParamInfo)
  308. continue;
  309. //==============================================================
  310. // Fill 'er up
  311. //==============================================================
  312. pTempInfo->dwFlags = pParamInfo->dwFlags;
  313. pTempInfo->iOrdinal = iParam+1;
  314. if (pwszNameBuffer && pParamInfo->pwszParamName) {
  315. pTempInfo->pwszName = pwszNameBuffer;
  316. wcscpy(pwszNameBuffer, pParamInfo->pwszParamName);
  317. pwszNameBuffer += wcslen(pParamInfo->pwszParamName) + 1;
  318. }
  319. //==============================================================
  320. // pTempInfo->pTypeInfo already NULL
  321. //==============================================================
  322. pTempInfo->ulParamSize = pParamInfo->ulParamSize;
  323. pTempInfo->wType = pParamInfo->wOLEDBType,
  324. pTempInfo++;
  325. }
  326. }
  327. else{
  328. //==================================================================
  329. // Return the parameter information derived from the command.
  330. //==================================================================
  331. pwszNameBuffer = ppNamesBuffer? *ppNamesBuffer : NULL;
  332. pTempInfo = *prgDBParamInfo;
  333. for (iParam = 0; iParam <(ULONG) m_pQuery->GetParamCount(); iParam++){
  334. pParamInfo = m_pQuery->m_prgProviderParamInfo + iParam;
  335. //==============================================================
  336. // Fill 'er up
  337. //==============================================================
  338. pTempInfo->dwFlags = pParamInfo->dwFlags;
  339. pTempInfo->iOrdinal = iParam+1;
  340. if (pwszNameBuffer && pParamInfo->pwszParamName){
  341. pTempInfo->pwszName = pwszNameBuffer;
  342. wcscpy(pwszNameBuffer, pParamInfo->pwszParamName);
  343. pwszNameBuffer += wcslen(pParamInfo->pwszParamName) + 1;
  344. }
  345. //==============================================================
  346. // pTempInfo->pTypeInfo already NULL
  347. //==============================================================
  348. pTempInfo->ulParamSize = pParamInfo->ulParamSize;
  349. pTempInfo->wType = pParamInfo->wOLEDBType,
  350. pTempInfo++;
  351. }
  352. }
  353. }
  354. }
  355. }
  356. if ( SUCCEEDED(hr) ){
  357. *pcParams = cNumParams;
  358. }
  359. else{
  360. *pcParams = 0;
  361. if (*prgDBParamInfo){
  362. g_pIMalloc->Free(*prgDBParamInfo);
  363. *prgDBParamInfo = NULL;
  364. }
  365. if (ppNamesBuffer && *ppNamesBuffer){
  366. g_pIMalloc->Free(*ppNamesBuffer);
  367. ppNamesBuffer = NULL;
  368. }
  369. }
  370. return hr;
  371. }
  372. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  373. //
  374. // This method allows client to define the parameters.
  375. //
  376. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  377. HRESULT CCommand::SetParameterInfo( DB_UPARAMS cParams, const DB_UPARAMS rgParamOrdinals[], const DBPARAMBINDINFO rgParamBindInfo[] )
  378. {
  379. HRESULT hr = S_OK;
  380. PPARAMINFO pParamInfo = NULL;
  381. DBORDINAL iMax = 0;
  382. DBORDINAL iParams;
  383. CDataMap DataMap;
  384. DBTYPE wDataType = 0;
  385. BOOL bOveridden = FALSE;
  386. BOOL bRet = FALSE;
  387. //=====================================================================
  388. // If given no params, discard all user param info and return
  389. //=====================================================================
  390. if (!cParams){
  391. m_pQuery->DeleteConsumerParamInfo();
  392. hr = S_OK;
  393. }
  394. else
  395. {
  396. //=====================================================================
  397. // If there's no rgParamBindInfo, we're to discard the param information
  398. //=====================================================================
  399. if ( !rgParamBindInfo ){
  400. ULONG_PTR iElem = 0;
  401. //=================================================================
  402. // Discard the param info
  403. //=================================================================
  404. for (iParams = 0; iParams < cParams; iParams++){
  405. iElem = rgParamOrdinals[iParams];
  406. if (iElem > 0 && iElem <= (unsigned)m_pQuery->GetParamCount()){
  407. m_pQuery->RemoveParam(iElem-1);
  408. delete pParamInfo;
  409. }
  410. }
  411. hr = S_OK;
  412. bRet = TRUE;
  413. }
  414. //=====================================================================
  415. // Find the max param ordinal and check for valid param names
  416. //=====================================================================
  417. iMax = rgParamOrdinals[0];
  418. for (iParams = 0; iParams < cParams; iParams++){
  419. if (iMax < rgParamOrdinals[iParams])
  420. {
  421. iMax = rgParamOrdinals[iParams];
  422. }
  423. if(rgParamBindInfo[iParams].pwszName != NULL)
  424. /* {
  425. hr = DB_E_BADPARAMETERNAME;
  426. }
  427. else
  428. */ if (wcslen(rgParamBindInfo[iParams].pwszName )== 0){
  429. hr = DB_E_BADPARAMETERNAME;
  430. }
  431. }
  432. if(SUCCEEDED(hr))
  433. {
  434. DBORDINAL iOrdinal;
  435. //=====================================================================
  436. // Loop over bind info and set or override the param info
  437. //=====================================================================
  438. for (iParams = 0; iParams < cParams; iParams++){
  439. iOrdinal = rgParamOrdinals[iParams];
  440. //=================================================================
  441. // Add the consumer-provided information to our cache
  442. //=================================================================
  443. try
  444. {
  445. pParamInfo = new PARAMINFO;
  446. }
  447. catch(...)
  448. {
  449. SAFE_DELETE_PTR(pParamInfo);
  450. throw;
  451. }
  452. if (NULL == pParamInfo){
  453. hr = (E_OUTOFMEMORY);
  454. }
  455. else
  456. {
  457. pParamInfo->dwFlags = rgParamBindInfo[iParams].dwFlags;
  458. pParamInfo->ulParamSize = rgParamBindInfo[iParams].ulParamSize;
  459. pParamInfo->iOrdinal = iOrdinal;
  460. DataMap.TranslateParameterStringToOLEDBType( wDataType, rgParamBindInfo[iParams].pwszDataSourceType);
  461. pParamInfo->wOLEDBType = wDataType;
  462. if (rgParamBindInfo[iParams].pwszName){
  463. ULONG cwchName = wcslen(rgParamBindInfo[iParams].pwszName);
  464. try
  465. {
  466. pParamInfo->pwszParamName = new WCHAR[cwchName+1];
  467. }
  468. catch(...)
  469. {
  470. SAFE_DELETE_ARRAY(pParamInfo->pwszParamName);
  471. throw;
  472. }
  473. if (NULL == pParamInfo->pwszParamName){
  474. SAFE_DELETE_PTR(pParamInfo);
  475. hr = (E_OUTOFMEMORY);
  476. }
  477. else
  478. {
  479. wcscpy(pParamInfo->pwszParamName,rgParamBindInfo[iParams].pwszName);
  480. }
  481. }
  482. if(SUCCEEDED(hr))
  483. {
  484. // Remove the parameter if a parameter alread exist at the ordinal
  485. if (iOrdinal > 0 && iOrdinal <= (unsigned)m_pQuery->GetParamCount()){
  486. m_pQuery->RemoveParam(iOrdinal-1);
  487. SAFE_DELETE_ARRAY(pParamInfo->pwszParamName);
  488. SAFE_DELETE_PTR(pParamInfo);
  489. bOveridden = TRUE;
  490. }
  491. // If there is already a parameter at this ordinal , remove
  492. // that and insert this new one
  493. hr = m_pQuery->AddConsumerParamInfo(iOrdinal-1,pParamInfo);
  494. if( FAILED(hr)){
  495. break;
  496. }
  497. if( hr == S_OK && bOveridden == TRUE)
  498. {
  499. hr = DB_S_TYPEINFOOVERRIDDEN;
  500. }
  501. }
  502. }
  503. } // for loop
  504. } // If succeeded(hr)
  505. }
  506. hr = hr == S_OK ? hr : g_pCError->PostHResult(hr, &IID_ICommandWithParameters);
  507. return hr;
  508. }
  509. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  510. //
  511. // Gets the parameter information for each param marker present in the command.
  512. //
  513. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  514. HRESULT CCommand::GetParamInfo( const IID *piid )
  515. {
  516. PPARAMINFO prgParamInfo = NULL;
  517. if (m_CError.Size())
  518. {
  519. m_CError.FreeErrors();
  520. }
  521. m_pQuery->SetProviderParamInfo(prgParamInfo);
  522. return S_OK;
  523. }
  524. //////////////////////////////////////////////////////////////////////////////////////////////////////////
  525. STDMETHODIMP CCommand::MapParameterNames( DB_UPARAMS cParamNames, const OLECHAR* rgParamNames[], DB_LPARAMS rgParamOrdinals[],
  526. const IID* piid )
  527. {
  528. HRESULT hr = S_OK;
  529. ULONG iName = 0;
  530. ULONG iParam = 0;
  531. ULONG cParam = 0;
  532. ULONG cErrors = 0;
  533. //=======================================================
  534. // Check if we have any parameters
  535. //=======================================================
  536. if ( cParamNames )
  537. {
  538. cParam = m_pQuery->GetParamCount();
  539. if (cParam > 0){
  540. for (iName = 0; iName < cParamNames; iName++){
  541. for (iParam = 0; iParam < cParam; iParam++){
  542. PPARAMINFO pParamInfo;
  543. pParamInfo = (PPARAMINFO) m_pQuery->GetParam(iParam);
  544. if (pParamInfo && pParamInfo->pwszParamName && !_wcsicmp(rgParamNames[iName],pParamInfo->pwszParamName)){
  545. rgParamOrdinals[iName] = LONG(iParam + 1);
  546. break;
  547. }
  548. }
  549. if (iParam == cParam){
  550. rgParamOrdinals[iName] = 0;
  551. cErrors++;
  552. }
  553. }
  554. }
  555. else{
  556. if (!m_pQuery->m_prgProviderParamInfo && m_pQuery->GetParamCount() && !(m_pQuery->GetStatus())){
  557. //=======================================================
  558. // Get the parameter info
  559. //=======================================================
  560. if (SUCCEEDED(hr = GetParamInfo(piid))){
  561. cParam = m_pQuery->GetParamCount();
  562. for (iName = 0; iName < cParamNames; iName++) {
  563. for (iParam = rgParamNames[iName]? 0 : cParam; iParam < cParam; iParam++){
  564. PPARAMINFO pParamInfo = m_pQuery->m_prgProviderParamInfo + iParam;
  565. if (pParamInfo->pwszParamName && !_wcsicmp(rgParamNames[iName],pParamInfo->pwszParamName)){
  566. rgParamOrdinals[iName] = LONG(iParam + 1);
  567. break;
  568. }
  569. }
  570. }
  571. if (iParam == cParam) {
  572. rgParamOrdinals[iName] = 0;
  573. cErrors++;
  574. }
  575. }
  576. }
  577. }
  578. if (!cErrors)
  579. {
  580. hr = S_OK;
  581. }
  582. else if (cErrors < cParamNames)
  583. {
  584. hr = DB_S_ERRORSOCCURRED;
  585. }
  586. else
  587. {
  588. hr = DB_E_ERRORSOCCURRED;
  589. }
  590. }
  591. hr = hr == S_OK ? hr : g_pCError->PostHResult(hr, &IID_ICommandWithParameters);
  592. return hr;
  593. }