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.

1052 lines
26 KiB

  1. /********************************************************************
  2. Copyright (c) 1999-2000 Microsoft Corporation
  3. Module Name:
  4. pfdb.cpp
  5. Abstract:
  6. encapsulates all database activity
  7. Revision History:
  8. DerekM created 05/01/99
  9. DerekM modified 02/26/00
  10. DerekM modified 03/24/00
  11. ********************************************************************/
  12. #include "stdafx.h"
  13. #include <adoid.h>
  14. #include "pfdb.h"
  15. /////////////////////////////////////////////////////////////////////////////
  16. // tracing stuff
  17. #ifdef THIS_FILE
  18. #undef THIS_FILE
  19. #endif
  20. static char __szTraceSourceFile[] = __FILE__;
  21. #define THIS_FILE __szTraceSourceFile
  22. /////////////////////////////////////////////////////////////////////////////
  23. // CPFDB- init & termination
  24. // **************************************************************************
  25. CPFDB::CPFDB()
  26. {
  27. m_rgpParams = NULL;
  28. m_pParams = NULL;
  29. m_pCmd = NULL;
  30. m_pConn = NULL;
  31. m_pRS = NULL;
  32. m_pFields = NULL;
  33. m_fNeedReset = FALSE;
  34. m_cSlots = 0;
  35. m_iLastSlot = (DWORD)-1;
  36. m_cte = adCmdUnspecified;
  37. }
  38. // **************************************************************************
  39. CPFDB::~CPFDB()
  40. {
  41. this->Cleanup();
  42. }
  43. /////////////////////////////////////////////////////////////////////////////
  44. // CPFDB- IUnknown
  45. // **************************************************************************
  46. STDMETHODIMP_(ULONG) CPFDB::AddRef(void)
  47. {
  48. USE_TRACING("CPFDB::AddRef");
  49. m_cRef++;
  50. return m_cRef;
  51. }
  52. // **************************************************************************
  53. STDMETHODIMP_(ULONG) CPFDB::Release(void)
  54. {
  55. USE_TRACING("CPFDB::Release");
  56. m_cRef--;
  57. if (m_cRef == 0)
  58. {
  59. delete this;
  60. return 0;
  61. }
  62. return m_cRef;
  63. }
  64. /////////////////////////////////////////////////////////////////////////////
  65. // CPFDB- internal methods
  66. // **************************************************************************
  67. void CPFDB::Cleanup(void)
  68. {
  69. USE_TRACING("CPFDB::Cleanup");
  70. if (m_rgpParams != NULL)
  71. {
  72. DWORD i;
  73. for (i = 0; i < m_cSlots; i++)
  74. {
  75. if (m_rgpParams[i] != NULL)
  76. m_rgpParams[i]->Release();
  77. }
  78. MyFree(m_rgpParams);
  79. }
  80. m_bstrConn.Empty();
  81. m_bstrCmd.Empty();
  82. if (m_pParams != NULL)
  83. m_pParams->Release();
  84. if (m_pCmd != NULL)
  85. m_pCmd->Release();
  86. if (m_pConn != NULL)
  87. m_pConn->Release();
  88. if (m_pFields != NULL)
  89. m_pFields->Release();
  90. if (m_pRS != NULL)
  91. {
  92. m_pRS->Close();
  93. m_pRS->Release();
  94. }
  95. m_rgpParams = NULL;
  96. m_pParams = NULL;
  97. m_pCmd = NULL;
  98. m_pConn = NULL;
  99. m_pRS = NULL;
  100. m_pFields = NULL;
  101. m_fNeedReset = FALSE;
  102. m_cSlots = 0;
  103. m_iLastSlot = (DWORD)-1;
  104. m_cte = adCmdUnspecified;
  105. }
  106. // **************************************************************************
  107. HRESULT CPFDB::AddParameterObj(DWORD iPos)
  108. {
  109. USE_TRACING("CPFDB::CreateParameter");
  110. VARIANT varEmpty;
  111. HRESULT hr = NOERROR;
  112. if (iPos >= m_cSlots)
  113. {
  114. LPVOID pv;
  115. DWORD cSlots;
  116. cSlots = MyMax(m_cSlots * 2, c_cInitialProps);
  117. cSlots = MyMax(cSlots , iPos + 1);
  118. pv = MyAlloc(cSlots * sizeof(ADOParameter *));
  119. VALIDATEEXPR(hr, (pv == NULL), E_OUTOFMEMORY);
  120. if (FAILED(hr))
  121. goto done;
  122. CopyMemory(pv, m_rgpParams, m_cSlots * sizeof(ADOParameter *));
  123. MyFree(m_rgpParams);
  124. m_rgpParams = (ADOParameter **)pv;
  125. m_cSlots = cSlots;
  126. }
  127. // create the parameter and set up the direction
  128. VariantInit(&varEmpty);
  129. TESTHR(hr, m_pCmd->CreateParameter(NULL, adEmpty, adParamInput, 0,
  130. varEmpty, &m_rgpParams[iPos]));
  131. if (FAILED(hr))
  132. goto done;
  133. done:
  134. return hr;
  135. }
  136. // **************************************************************************
  137. HRESULT CPFDB::TestConnAndRefresh(void)
  138. {
  139. USE_TRACING("CPFDB::AttemptReset");
  140. ADORecordset *pRS = NULL;
  141. CComBSTR bstr;
  142. HRESULT hr = NOERROR;
  143. // if these are missing, we are totally screwed. So tell the caller
  144. // about and share the annoyance
  145. VALIDATEEXPR(hr, (m_pCmd == NULL ||
  146. (m_pConn == NULL && m_bstrConn.m_str == NULL)), E_FAIL);
  147. if (FAILED(hr))
  148. goto done;
  149. // ok, first try to do a bogus send to see if the connection is there or
  150. // not...
  151. TESTHR(hr, bstr.Append(L"SELECT 1"));
  152. if (FAILED(hr))
  153. goto done;
  154. TESTHR(hr, m_pCmd->put_CommandText(bstr.m_str));
  155. if (FAILED(hr))
  156. goto done;
  157. // if this succeeds, there's nothing wrong with the connection (yeah, we
  158. // actually WANT this to fail...)
  159. TESTHR(hr, m_pCmd->Execute(NULL, NULL, adCmdText | adExecuteNoRecords,
  160. &pRS));
  161. if (SUCCEEDED(hr))
  162. {
  163. hr = S_FALSE;
  164. goto done;
  165. }
  166. // ok, so the connection is somehow screwed up so try to fix it...
  167. VALIDATEEXPR(hr, (m_bstrConn.m_str == NULL), E_FAIL);
  168. if (FAILED(hr))
  169. goto done;
  170. m_pConn->Close();
  171. TESTHR(hr, m_pConn->Open(m_bstrConn.m_str, NULL, NULL,
  172. adConnectUnspecified));
  173. if (FAILED(hr))
  174. goto done;
  175. // might have to reset all of the parameter objects at this point &
  176. // re-add them to the command object.
  177. done:
  178. if (pRS != NULL)
  179. {
  180. pRS->Close();
  181. pRS->Release();
  182. }
  183. return hr;
  184. }
  185. /////////////////////////////////////////////////////////////////////////////
  186. // CPFDB- exposed methods
  187. // **************************************************************************
  188. HRESULT CPFDB::Init(LPCWSTR wszConn, DWORD dwTimeout)
  189. {
  190. USE_TRACING("CPFDB::Init");
  191. ADOConnection *pConn = NULL;
  192. CComBSTR bstrConn;
  193. HRESULT hr = NOERROR;
  194. VALIDATEPARM(hr, (wszConn == NULL || dwTimeout == 0));
  195. if (FAILED(hr))
  196. goto done;
  197. TESTHR(hr, CoCreateInstance(CLSID_CADOConnection, NULL,
  198. CLSCTX_INPROC_SERVER, IID_IADOConnection,
  199. (LPVOID *)&pConn));
  200. if (FAILED(hr))
  201. goto done;
  202. TESTHR(hr, pConn->put_CommandTimeout(dwTimeout));
  203. if (FAILED(hr))
  204. hr = NOERROR;
  205. TESTHR(hr, bstrConn.Append(wszConn));
  206. if (FAILED(hr))
  207. goto done;
  208. TESTHR(hr, pConn->Open(bstrConn.m_str, NULL, NULL, adConnectUnspecified));
  209. if (FAILED(hr))
  210. goto done;
  211. TESTHR(hr, this->Init(pConn, dwTimeout, bstrConn.m_str));
  212. if (FAILED(hr))
  213. goto done;
  214. // if the Init method succeeded, then it took control of the bstr, so we
  215. // don't want to free when we exit.
  216. bstrConn.Detach();
  217. done:
  218. if (pConn != NULL)
  219. pConn->Release();
  220. return hr;
  221. }
  222. // **************************************************************************
  223. HRESULT CPFDB::Init(ADOConnection *pConn, DWORD dwTimeout, BSTR bstrConn)
  224. {
  225. USE_TRACING("CPFDB::Init");
  226. ADOParameters *pParams = NULL;
  227. ADOCommand *pCmd = NULL;
  228. CComBSTR bstrConnNew;
  229. HRESULT hr = NOERROR;
  230. // can't have both the connection string and connection object NULL...
  231. VALIDATEPARM(hr, (pConn == NULL));
  232. if (FAILED(hr))
  233. goto done;
  234. // get the connection string for the object
  235. if (bstrConn == NULL)
  236. {
  237. TESTHR(hr, pConn->get_ConnectionString(&bstrConnNew));
  238. if (FAILED(hr))
  239. goto done;
  240. }
  241. else
  242. {
  243. bstrConnNew.Attach(bstrConn);
  244. }
  245. // set up the command object
  246. TESTHR(hr, CoCreateInstance(CLSID_CADOCommand, NULL, CLSCTX_INPROC_SERVER,
  247. IID_IADOCommand25, (LPVOID *)&pCmd));
  248. if (FAILED(hr))
  249. goto done;
  250. TESTHR(hr, pCmd->put_CommandTimeout(dwTimeout));
  251. if (FAILED(hr))
  252. hr = NOERROR;
  253. TESTHR(hr, pCmd->putref_ActiveConnection(pConn));
  254. if (FAILED(hr))
  255. goto done;
  256. TESTHR(hr, pCmd->get_Parameters(&pParams));
  257. if (FAILED(hr))
  258. goto done;
  259. // free up anything that already exists
  260. this->Cleanup();
  261. // save off what we just allocated...
  262. pConn->AddRef();
  263. m_pConn = pConn;
  264. m_pCmd = pCmd;
  265. m_pParams = pParams;
  266. pParams = NULL;
  267. pCmd = NULL;
  268. if (bstrConnNew.m_str != NULL)
  269. m_bstrConn.Attach(bstrConnNew.Detach());
  270. done:
  271. if (pParams != NULL)
  272. pParams->Release();
  273. if (pCmd != NULL)
  274. pCmd->Release();
  275. return hr;
  276. }
  277. // **************************************************************************
  278. HRESULT CPFDB::Begin(LPCWSTR wszCmd, CommandTypeEnum cte)
  279. {
  280. USE_TRACING("CPFDB::Begin");
  281. HRESULT hr = NOERROR;
  282. // validate params
  283. VALIDATEPARM(hr, (wszCmd == NULL));
  284. if (FAILED(hr))
  285. goto done;
  286. // make sure we've been initialized
  287. VALIDATEEXPR(hr, (m_pCmd == NULL), E_FAIL);
  288. if (FAILED(hr))
  289. goto done;
  290. if (m_fNeedReset)
  291. {
  292. TESTHR(hr, this->Reset());
  293. if (FAILED(hr))
  294. goto done;
  295. }
  296. // set the command text
  297. TESTHR(hr, m_bstrCmd.Append(wszCmd));
  298. if (FAILED(hr))
  299. goto done;
  300. TESTHR(hr, m_pCmd->put_CommandText(m_bstrCmd.m_str));
  301. if (FAILED(hr))
  302. goto done;
  303. TESTHR(hr, m_pCmd->put_CommandType(cte));
  304. if (FAILED(hr))
  305. goto done;
  306. m_cte = cte;
  307. done:
  308. return hr;
  309. }
  310. // **************************************************************************
  311. HRESULT CPFDB::Reset(void)
  312. {
  313. USE_TRACING("CPFDB::Reset");
  314. HRESULT hr = NOERROR;
  315. // check if we need to reset internal stuff
  316. if (m_fNeedReset && m_pParams != NULL)
  317. {
  318. VARIANT var;
  319. long cParams, i;
  320. // got to delete everything in the parameters object cuz ADO is
  321. // stupid and won't let us reuse parameter objects.
  322. TESTHR(hr, m_pParams->get_Count(&cParams));
  323. if (FAILED(hr))
  324. goto done;
  325. VariantInit(&var);
  326. V_VT(&var) = VT_I4;
  327. V_I4(&var) = 0;
  328. for (i = 0; i < cParams; i++)
  329. {
  330. TESTHR(hr, m_pParams->Delete(var));
  331. if (FAILED(hr))
  332. goto done;
  333. if (m_rgpParams != NULL && m_rgpParams[i] != NULL)
  334. {
  335. m_rgpParams[i]->Release();
  336. m_rgpParams[i] = NULL;
  337. }
  338. }
  339. }
  340. m_bstrCmd.Empty();
  341. if (m_pFields != NULL)
  342. m_pFields->Release();
  343. if (m_pRS != NULL)
  344. {
  345. m_pRS->Close();
  346. m_pRS->Release();
  347. }
  348. m_pFields = NULL;
  349. m_pRS = NULL;
  350. m_fNeedReset = FALSE;
  351. m_iLastSlot = (DWORD)-1;
  352. m_cte = adCmdUnspecified;
  353. done:
  354. return hr;
  355. }
  356. // **************************************************************************
  357. HRESULT CPFDB::AddInParam(VARIANT &varData, DataTypeEnum dtADO, DWORD iPos)
  358. {
  359. USE_TRACING("CPFDB::AddInParam");
  360. VARIANT var;
  361. HRESULT hr = NOERROR;
  362. DWORD dwSize;
  363. VALIDATEEXPR(hr, (m_fNeedReset || m_pCmd == NULL), E_FAIL);
  364. if (FAILED(hr))
  365. goto done;
  366. VariantInit(&var);
  367. // if he passed in -1, it means to use 1 more than the last parameter
  368. // added so far.
  369. if (iPos == (DWORD)-1)
  370. iPos = m_iLastSlot + 1;
  371. // check if we need to alloc a new parameter
  372. TESTHR(hr, this->AddParameterObj(iPos));
  373. if (FAILED(hr))
  374. goto done;
  375. // set the fact that it's an input parameter
  376. TESTHR(hr, m_rgpParams[iPos]->put_Direction(adParamInput));
  377. if (FAILED(hr))
  378. goto done;
  379. // if we got passed in a BSTR with a NULL string, convert it
  380. // to an empty parameter.
  381. if (V_VT(&varData) == VT_BSTR && V_BSTR(&varData) == NULL)
  382. V_VT(&varData) = VT_EMPTY;
  383. // ok, so we have some special case handling for adLongVarWChar types.
  384. // If we have data for it (type is set to VT_BSTR) then we gotta get
  385. // the size of that data & pass it to the parameter object.
  386. // If we don't have data for it (type set to VT_EMPTY) then we gotta
  387. // change the data type to adVarWChar cuz adLongVarWChar expects a non-
  388. // zero size when u append it to the Parameters collection. Stupid ADO.
  389. // more ADO stupidity. If the size of a string isn't specified, ADO will
  390. // determine the max size of the column and tack on spaces until the
  391. // string we send up is the size of the column. So we need to specify a
  392. // size or we'll end up using WAY more space that we need to.
  393. switch(dtADO)
  394. {
  395. case adLongVarWChar:
  396. case adLongVarBinary:
  397. case adLongVarChar:
  398. case adVarWChar:
  399. case adVarChar:
  400. case adVarBinary:
  401. if (V_VT(&varData) == VT_BSTR && *(V_BSTR(&varData)) != L'\0')
  402. {
  403. switch(dtADO)
  404. {
  405. case adLongVarWChar:
  406. case adLongVarChar:
  407. case adVarWChar:
  408. case adVarChar:
  409. dwSize = SysStringLen(V_BSTR(&varData));
  410. break;
  411. case adLongVarBinary:
  412. case adVarBinary:
  413. dwSize = SysStringByteLen(V_BSTR(&varData));
  414. break;
  415. }
  416. }
  417. else if (V_VT(&varData) == (VT_ARRAY | VT_UI1) &&
  418. (dtADO == adVarBinary || dtADO == adLongVarBinary))
  419. {
  420. dwSize = V_ARRAY(&varData)->rgsabound[0].cElements -
  421. V_ARRAY(&varData)->rgsabound[0].lLbound;
  422. }
  423. else
  424. {
  425. dwSize = 0;
  426. switch(dtADO)
  427. {
  428. case adLongVarWChar:
  429. case adVarWChar:
  430. case adLongVarChar:
  431. case adVarChar:
  432. dtADO = adBSTR;
  433. break;
  434. }
  435. }
  436. // gotta set the size of these
  437. TESTHR(hr, m_rgpParams[iPos]->put_Size(dwSize));
  438. if (FAILED(hr))
  439. goto done;
  440. break;
  441. }
  442. // set the type
  443. TESTHR(hr, m_rgpParams[iPos]->put_Type(dtADO));
  444. if (FAILED(hr))
  445. goto done;
  446. TESTHR(hr, m_rgpParams[iPos]->put_Value(varData));
  447. if (FAILED(hr))
  448. goto done;
  449. if (iPos > m_iLastSlot || m_iLastSlot == (DWORD)-1)
  450. m_iLastSlot = iPos;
  451. done:
  452. return hr;
  453. }
  454. // **************************************************************************
  455. HRESULT CPFDB::AddOutParam(DataTypeEnum dtADO, DWORD iPos, BOOL fSPRetVal,
  456. DWORD cchSize)
  457. {
  458. USE_TRACING("CPFDB::AddOutParam");
  459. HRESULT hr = NOERROR;
  460. VALIDATEEXPR(hr, (m_fNeedReset || m_pCmd == NULL), E_FAIL);
  461. if (FAILED(hr))
  462. goto done;
  463. // if he passed in -1, it means to use 1 more than the last parameter
  464. // added so far.
  465. if (iPos == (DWORD)-1)
  466. iPos = m_iLastSlot + 1;
  467. // check if we need to alloc a new parameter
  468. TESTHR(hr, this->AddParameterObj(iPos));
  469. if (FAILED(hr))
  470. goto done;
  471. // set the type
  472. TESTHR(hr, m_rgpParams[iPos]->put_Type(dtADO));
  473. if (FAILED(hr))
  474. goto done;
  475. // set the fact that it's an output parameter
  476. if (fSPRetVal)
  477. {
  478. TESTHR(hr, m_rgpParams[iPos]->put_Direction(adParamReturnValue));
  479. }
  480. else
  481. {
  482. TESTHR(hr, m_rgpParams[iPos]->put_Direction(adParamOutput));
  483. }
  484. if (FAILED(hr))
  485. goto done;
  486. // if we have a string output parameter, we gotta set the size
  487. // of the string we want returned to us. Why can't ADO just
  488. // return us the string in a BSTR? Cuz ADO is stupid.
  489. if (dtADO == adVarWChar || dtADO == adBSTR || dtADO == adVarChar)
  490. {
  491. TESTHR(hr, m_rgpParams[iPos]->put_Size(cchSize));
  492. if (FAILED(hr))
  493. goto done;
  494. }
  495. if (iPos > m_iLastSlot || m_iLastSlot == (DWORD)-1)
  496. m_iLastSlot = iPos;
  497. done:
  498. return hr;
  499. }
  500. // **************************************************************************
  501. HRESULT CPFDB::Execute(BOOL fNeedRS)
  502. {
  503. USE_TRACING("CPFDB::Commit");
  504. ADORecordset *pRS = NULL;
  505. IDispatch *pdisp = NULL;
  506. HRESULT hr = NOERROR;
  507. DWORD i;
  508. LONG lVal;
  509. BOOL fConnReset = FALSE;
  510. #if defined(DEBUG) || defined(_DEBUG)
  511. ParameterDirectionEnum pdDbgADO[32];
  512. DataTypeEnum dtDbgADO[32];
  513. VARIANT varDbgVal[32];
  514. DWORD iDbg;
  515. ZeroMemory(pdDbgADO, sizeof(pdDbgADO));
  516. ZeroMemory(dtDbgADO, sizeof(dtDbgADO));
  517. ZeroMemory(varDbgVal, sizeof(varDbgVal));
  518. #endif
  519. // don't want to try this if we failed once or the command object
  520. // doesn't exist
  521. VALIDATEEXPR(hr, (m_fNeedReset || m_pCmd == NULL), E_FAIL);
  522. if (FAILED(hr))
  523. goto done;
  524. m_fNeedReset = TRUE;
  525. // put all of the parameters into the query...
  526. for (i = 0; i < m_iLastSlot + 1; i++)
  527. {
  528. // we cannot have an empty parameter cuz ADO will choke if we do.
  529. // And we can't fill it with a default empty parameter (ie of some
  530. // random type) cuz ADO will complain that it doesn't know how to
  531. // (essentially) convert NULL into NULL or some such stuff.
  532. VALIDATEEXPR(hr, (m_rgpParams[i] == NULL), E_FAIL);
  533. if (FAILED(hr))
  534. goto done;
  535. #if defined(DEBUG) || defined(_DEBUG)
  536. if (i < 32)
  537. {
  538. VariantInit(&varDbgVal[i]);
  539. m_rgpParams[i]->get_Direction(&pdDbgADO[i]);
  540. m_rgpParams[i]->get_Type(&dtDbgADO[i]);
  541. m_rgpParams[i]->get_Value(&varDbgVal[i]);
  542. }
  543. #endif
  544. TESTHR(hr, m_rgpParams[i]->QueryInterface(IID_IDispatch,
  545. (LPVOID *)&pdisp));
  546. _ASSERT(SUCCEEDED(hr));
  547. TESTHR(hr, m_pParams->Append(pdisp));
  548. if (FAILED(hr))
  549. goto done;
  550. pdisp->Release();
  551. pdisp = NULL;
  552. }
  553. // execute the sucker
  554. lVal = (fNeedRS) ? m_cte : m_cte | adExecuteNoRecords;
  555. TESTHR(hr, m_pCmd->Execute(NULL, NULL, lVal, &pRS));
  556. if (FAILED(hr))
  557. goto done;
  558. // ok, if we have the recordset. If the caller wanted one, check & see if
  559. // it has any data & fetch the first set of fields out of it...
  560. if (fNeedRS)
  561. {
  562. VARIANT_BOOL vbf;
  563. if (pRS == NULL)
  564. {
  565. hr = S_FALSE;
  566. goto done;
  567. }
  568. TESTHR(hr, pRS->get_EOF(&vbf));
  569. if (FAILED(hr))
  570. goto done;
  571. if (vbf == VARIANT_TRUE)
  572. {
  573. hr = S_FALSE;
  574. goto done;
  575. }
  576. TESTHR(hr, pRS->get_Fields(&m_pFields));
  577. if (FAILED(hr))
  578. goto done;
  579. m_pRS = pRS;
  580. pRS = NULL;
  581. }
  582. done:
  583. #if defined(DEBUG) || defined(_DEBUG)
  584. for (iDbg = 0; iDbg < m_iLastSlot + 1; iDbg++)
  585. VariantClear(&(varDbgVal[iDbg]));
  586. #endif
  587. if (pRS != NULL)
  588. {
  589. pRS->Close();
  590. pRS->Release();
  591. }
  592. if (pdisp != NULL)
  593. pdisp->Release();
  594. return hr;
  595. }
  596. // **************************************************************************
  597. HRESULT CPFDB::GetOutParam(VARIANT &varParam, VARIANT *pvar, VARTYPE vt)
  598. {
  599. USE_TRACING("CPFDB::GetOutParam");
  600. ADOParameter *pParam = NULL;
  601. VARIANT varParamID;
  602. HRESULT hr = NOERROR;
  603. _ASSERT(pvar != NULL && m_pParams != NULL && m_fNeedReset);
  604. VariantClear(pvar);
  605. TESTHR(hr, m_pParams->get_Item(varParam, &pParam));
  606. if (FAILED(hr))
  607. goto done;
  608. TESTHR(hr, pParam->get_Value(pvar));
  609. if (FAILED(hr))
  610. goto done;
  611. if (vt != VT_ILLEGAL && V_VT(pvar) != vt)
  612. {
  613. TESTHR(hr, VariantChangeType(pvar, pvar, 0, vt));
  614. if (FAILED(hr))
  615. {
  616. VariantClear(pvar);
  617. goto done;
  618. }
  619. }
  620. done:
  621. if (pParam != NULL)
  622. pParam->Release();
  623. return hr;
  624. }
  625. // **************************************************************************
  626. HRESULT CPFDB::GetOutParam(BSTR bstrParam, VARIANT *pvar, VARTYPE vt)
  627. {
  628. USE_TRACING("CPFDB::GetOutParam");
  629. VARIANT varParam;
  630. HRESULT hr = NOERROR;
  631. VALIDATEPARM(hr, (bstrParam == NULL || pvar == NULL));
  632. if (FAILED(hr))
  633. goto done;
  634. // make sure we've been initialized & that we've executed an SP...
  635. VALIDATEEXPR(hr, (m_pParams == NULL || m_fNeedReset == FALSE), E_FAIL);
  636. if (FAILED(hr))
  637. goto done;
  638. // do not free this VARIANT cuz we don't own the BSTR
  639. VariantInit(&varParam);
  640. V_VT(&varParam) = VT_BSTR;
  641. V_BSTR(&varParam) = bstrParam;
  642. TESTHR(hr, this->GetOutParam(varParam, pvar, vt));
  643. if (FAILED(hr))
  644. goto done;
  645. done:
  646. return hr;
  647. }
  648. // **************************************************************************
  649. HRESULT CPFDB::GetOutParam(DWORD iParam, VARIANT *pvar, VARTYPE vt)
  650. {
  651. USE_TRACING("CPFDB::GetOutParam");
  652. VARIANT varParam;
  653. HRESULT hr = NOERROR;
  654. VALIDATEPARM(hr, (pvar == NULL));
  655. if (FAILED(hr))
  656. goto done;
  657. // make sure we've been initialized & that we've executed an SP...
  658. VALIDATEEXPR(hr, (m_pParams == NULL || m_fNeedReset == FALSE), E_FAIL);
  659. if (FAILED(hr))
  660. goto done;
  661. if (iParam == (DWORD)-1)
  662. iParam = m_iLastSlot;
  663. // we can't get the parameter via the array we've stored so we have to
  664. // ask the parameter object for it
  665. if (iParam >= m_cSlots)
  666. {
  667. VariantInit(&varParam);
  668. V_VT(&varParam) = VT_I4;
  669. V_I4(&varParam) = iParam;
  670. TESTHR(hr, this->GetOutParam(varParam, pvar, vt));
  671. if (FAILED(hr))
  672. goto done;
  673. }
  674. // WOOHOO!! Life is good when u can just accessed cached stuff...
  675. else
  676. {
  677. VariantClear(pvar);
  678. TESTHR(hr, m_rgpParams[iParam]->get_Value(pvar));
  679. if (FAILED(hr))
  680. goto done;
  681. if (V_VT(pvar) != vt && vt != VT_ILLEGAL && V_VT(pvar) != VT_NULL &&
  682. V_VT(pvar) != VT_EMPTY)
  683. {
  684. TESTHR(hr, VariantChangeType(pvar, pvar, 0, vt));
  685. if (FAILED(hr))
  686. {
  687. VariantClear(pvar);
  688. goto done;
  689. }
  690. }
  691. }
  692. done:
  693. return hr;
  694. }
  695. // **************************************************************************
  696. HRESULT CPFDB::GetNextRow(void)
  697. {
  698. USE_TRACING("CPFDB::GetNextRow");
  699. VARIANT_BOOL vbf;
  700. HRESULT hr = NOERROR;
  701. VALIDATEEXPR(hr, (m_pRS == NULL || m_fNeedReset == FALSE), E_FAIL);
  702. if (FAILED(hr))
  703. goto done;
  704. if (m_pFields != NULL)
  705. {
  706. m_pFields->Release();
  707. m_pFields = NULL;
  708. }
  709. TESTHR(hr, m_pRS->MoveNext());
  710. if (FAILED(hr))
  711. goto done;
  712. // see if we're at the end of th line & if so, free everything up...
  713. TESTHR(hr, m_pRS->get_EOF(&vbf));
  714. if (FAILED(hr))
  715. goto done;
  716. if (vbf == VARIANT_TRUE)
  717. {
  718. m_pRS->Close();
  719. m_pRS->Release();
  720. m_pRS = NULL;
  721. hr = S_FALSE;
  722. goto done;
  723. }
  724. TESTHR(hr, m_pRS->get_Fields(&m_pFields));
  725. if (FAILED(hr))
  726. goto done;
  727. done:
  728. return hr;
  729. }
  730. // **************************************************************************
  731. HRESULT CPFDB::GetData(VARIANT &varField, VARIANT *pvarData)
  732. {
  733. USE_TRACING("CPFDB::GetData");
  734. ADOField *pField = NULL;
  735. HRESULT hr = NOERROR;
  736. LONG lVal;
  737. ADO_LONGPTR llSize;
  738. _ASSERT(pvarData != NULL && m_pFields != NULL && m_fNeedReset);
  739. TESTHR(hr, m_pFields->get_Item(varField, &pField));
  740. if (FAILED(hr))
  741. goto done;
  742. TESTHR(hr, pField->get_Attributes(&lVal));
  743. if (FAILED(hr))
  744. goto done;
  745. // get the actual data out of the field- if it has adFldLong set, then
  746. // retrieve it using the GetChunk method cuz ADO likes it this way.
  747. if ((lVal & adFldLong) != 0)
  748. {
  749. TESTHR(hr, pField->get_ActualSize(&llSize));
  750. if (FAILED(hr))
  751. goto done;
  752. // NTRAID#NTBUG9-374453-2001/4/21-reinerf
  753. // we only ever read 4gig of data since GetChunk still only takes a LONG
  754. lVal = min(MAXLONG, llSize);
  755. TESTHR(hr, pField->GetChunk(lVal, pvarData));
  756. if (FAILED(hr))
  757. goto done;
  758. }
  759. else
  760. {
  761. TESTHR(hr, pField->get_Value(pvarData));
  762. if (FAILED(hr))
  763. goto done;
  764. }
  765. done:
  766. if (pField != NULL)
  767. pField->Release();
  768. return hr;
  769. }
  770. // **************************************************************************
  771. HRESULT CPFDB::GetData(BSTR bstrField, VARIANT *pvarData)
  772. {
  773. USE_TRACING("CPFDB::GetData");
  774. VARIANT varField;
  775. HRESULT hr = NOERROR;
  776. LONG cFields;
  777. VALIDATEPARM(hr, (bstrField == NULL || pvarData == NULL));
  778. if (FAILED(hr))
  779. goto done;
  780. VALIDATEEXPR(hr, (m_pFields == NULL || m_fNeedReset == FALSE), E_FAIL);
  781. if (FAILED(hr))
  782. goto done;
  783. // don't free this VARIANT since we don't own the BSTR
  784. VariantInit(&varField);
  785. V_VT(&varField) = VT_BSTR;
  786. V_BSTR(&varField) = bstrField;
  787. TESTHR(hr, this->GetData(varField, pvarData));
  788. if (FAILED(hr))
  789. goto done;
  790. done:
  791. return hr;
  792. }
  793. // **************************************************************************
  794. HRESULT CPFDB::GetData(DWORD iField, VARIANT *pvarData)
  795. {
  796. USE_TRACING("CPFDB::GetData");
  797. ADOField *pField = NULL;
  798. VARIANT varField;
  799. HRESULT hr = NOERROR;
  800. LONG cFields;
  801. VALIDATEPARM(hr, (pvarData == NULL));
  802. if (FAILED(hr))
  803. goto done;
  804. VALIDATEEXPR(hr, (m_pFields == NULL || m_fNeedReset == FALSE), E_FAIL);
  805. if (FAILED(hr))
  806. goto done;
  807. TESTHR(hr, m_pFields->get_Count(&cFields));
  808. if (FAILED(hr))
  809. goto done;
  810. VALIDATEEXPR(hr, (iField >= (DWORD)cFields),
  811. Err2HR(RPC_S_INVALID_BOUND));
  812. if (FAILED(hr))
  813. goto done;
  814. VariantInit(&varField);
  815. V_VT(&varField) = VT_I4;
  816. V_I4(&varField) = iField;
  817. TESTHR(hr, this->GetData(varField, pvarData));
  818. if (FAILED(hr))
  819. goto done;
  820. done:
  821. return hr;
  822. }
  823. // **************************************************************************
  824. HRESULT CPFDB::GetErrors(ADOErrors **ppErrs)
  825. {
  826. USE_TRACING("CPFDB::GetErrors");
  827. HRESULT hr = NOERROR;
  828. VALIDATEPARM(hr, (ppErrs == NULL));
  829. if (FAILED(hr))
  830. goto done;
  831. VALIDATEEXPR(hr, (m_pConn == NULL), E_FAIL);
  832. if (FAILED(hr))
  833. goto done;
  834. TESTHR(hr, m_pConn->get_Errors(ppErrs));
  835. if (FAILED(hr))
  836. goto done;
  837. done:
  838. return hr;
  839. }