Leaked source code of windows server 2003
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.

1986 lines
48 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name :
  4. odbcconn.cxx
  5. Abstract:
  6. This module defines member functions for ODBC_CONNECTION object.
  7. Author:
  8. Murali R. Krishnan ( MuraliK ) 16-Feb-1995
  9. Environment:
  10. User Mode - Win32.
  11. Project:
  12. Internet Services Common DLL
  13. Functions Exported:
  14. ODBC_PARAMETER::CopyValue( IN LPCWSTR pwszValue);
  15. ODBC_PARAMETER::Bind( IN HSTMT hstmt);
  16. ODBC_STATEMENT::~ODBC_STATEMENT()
  17. ODBC_STATEMENT::PrepareStatement( IN LPCSTR pszStatement)
  18. ODBC_STATEMENT::PrepareStatement( IN LPCWSTR pwszStatement)
  19. ODBC_STATEMENT::BindParameter( IN PODBC_PARAMETER pOdbcParam)
  20. ODBC_STATEMENT::ExecuteStatement( VOID)
  21. ODBC_STATEMENT::ExecDirect( IN LPCSTR pwszSqlCommand, IN DWORD cch)
  22. ODBC_STATEMENT::ExecDirect( IN LPCWSTR pwszSqlCommand, IN DWORD cch)
  23. ODBC_STATEMENT::QueryColNames( OUT STRA * * apstrCols,
  24. OUT DWORD * cCols,
  25. IN DWORD cchMaxFieldSize = 0 );
  26. ODBC_STATEMENT::QueryValuesAsStr( OUT STR * * apstrValues,
  27. OUT DWORD * * apcbValues,
  28. OUT BOOL * pfLast );
  29. ODBC_CONNECTION::~ODBC_CONNECTION();
  30. ODBC_CONNECTION::Open();
  31. ODBC_CONNECTION::Close();
  32. ODBC_CONNECTION::GetLastErrorCode();
  33. ODBC_CONNECTION::AllocStatement();
  34. Revision History:
  35. --*/
  36. /************************************************************
  37. * Include Headers
  38. ************************************************************/
  39. #include "precomp.hxx"
  40. #define TCP_ALLOC(cb) (VOID *)LocalAlloc( LPTR, cb )
  41. #define TCP_FREE(p) LocalFree( (HLOCAL) p )
  42. //
  43. // Since the ODBC does not support UNICODE APIs, we convert unicode to
  44. // ANSI to call the APIs. This will have to go away once we find some
  45. // other better way to do manage the same
  46. //
  47. //
  48. // Constants for display widths
  49. //
  50. #define MAX_NUM_PRECISION 15
  51. //
  52. // Constant for all non string and non binary data. 40 is chosen to
  53. // account for things such as Oracle's numeric types, which can have
  54. // up to 38 digits of precision
  55. //
  56. #define MAX_NONCHAR_DATA_LEN 40
  57. //
  58. // If no default maximum field size is specified, then use this value
  59. // as the maximum
  60. //
  61. #define DEFAULT_MAX_FIELD_SIZE 8192
  62. ALLOC_CACHE_HANDLER * ODBC_STATEMENT::sm_pachOdbcStatements;
  63. /************************************************************
  64. * Local Functions
  65. ************************************************************/
  66. static
  67. inline
  68. VOID
  69. CheckAndPrintErrorMessage(
  70. IN ODBC_CONNECTION * poc,
  71. IN RETCODE rc
  72. )
  73. {
  74. # if DBG
  75. if ( !ODBC_CONNECTION::Success( rc)) {
  76. STRA str;
  77. poc->GetLastErrorText( &str, NULL, rc );
  78. DBGPRINTF( ( DBG_CONTEXT,
  79. "ODBC Error Code( %d). Text: %s\n",
  80. rc,
  81. str.QueryStr() ));
  82. }
  83. # endif // DBG
  84. return;
  85. } // CheckAndPrintErrorMessage()
  86. static inline VOID
  87. CheckAndPrintErrorMessage(
  88. IN ODBC_STATEMENT * pos,
  89. IN RETCODE rc)
  90. {
  91. # if DBG
  92. if ( !ODBC_CONNECTION::Success( rc)) {
  93. STRA str;
  94. pos->GetLastErrorText( &str );
  95. DBGPRINTF( ( DBG_CONTEXT,
  96. "ODBC Error Code( %d). Text: %s\n",
  97. rc,
  98. str.QueryStr() ));
  99. }
  100. # endif // DBG
  101. return;
  102. } // CheckAndPrintErrorMessage()
  103. # if DBG
  104. # if 0
  105. static VOID
  106. PrintMultiString(
  107. IN char * pszMsg,
  108. IN DWORD cbLen,
  109. IN char * pmsz
  110. )
  111. {
  112. DBGPRINTF( ( DBG_CONTEXT,
  113. "Values of %s. %d bytes.\n", pszMsg, cbLen));
  114. for( char * psz = pmsz;
  115. *psz != '\0';
  116. psz += (strlen( psz) + 1))
  117. {
  118. DBGPRINTF( ( DBG_CONTEXT, "%s\n", psz));
  119. }
  120. return;
  121. } // PrintMultiString()
  122. static VOID
  123. AuxOdbcFunctions( IN HENV henv, IN HDBC hdbc)
  124. /*++
  125. Function useful in walking throug a few additional ODBC functions
  126. to find out the ODBC setup information.
  127. Not to be part of the shipped code. Useful for development purposes.
  128. - MuraliK
  129. --*/
  130. {
  131. RETCODE rc;
  132. //
  133. // Set the trace file to a standard file.
  134. //
  135. rc = SQLSetConnectOption( hdbc, SQL_OPT_TRACE, SQL_OPT_TRACE_ON);
  136. DBG_ASSERT( ODBC_CONNECTION::Success( rc));
  137. rc = SQLSetConnectOption( hdbc, SQL_OPT_TRACEFILE,
  138. ( SQLULEN )"%systemroot%\\system32\\gophsql.log" );
  139. DBG_ASSERT( ODBC_CONNECTION::Success( rc));
  140. UCHAR szDriverDesc[ 300];
  141. UCHAR szDriverAttrib[ 300];
  142. SWORD cbDD = 300;
  143. SWORD cbDA = 300;
  144. SWORD cbDDCur = 0;
  145. SWORD cbDACur = 0;
  146. szDriverDesc[0] = szDriverAttrib[0] = '\0';
  147. rc = SQLDriversA( henv, SQL_FETCH_FIRST,
  148. szDriverDesc, cbDD, &cbDDCur,
  149. szDriverAttrib, cbDA, &cbDACur);
  150. DBG_ASSERT( ODBC_CONNECTION::Success( rc));
  151. DBGPRINTF( ( DBG_CONTEXT,
  152. " SQLDrivers( %08x) ==> RetCode = %d."
  153. " Driver Desc. = ( %d bytes) %s. ",
  154. henv, rc, cbDDCur, szDriverDesc));
  155. PrintMultiString( " Driver Attributes",
  156. cbDACur,
  157. (char *) szDriverAttrib);
  158. szDriverDesc[0] = szDriverAttrib[0] = '\0';
  159. cbDDCur = cbDACur = 0;
  160. rc = SQLDataSourcesA( henv, SQL_FETCH_FIRST,
  161. szDriverDesc, cbDD, &cbDDCur,
  162. szDriverAttrib, cbDA, &cbDACur);
  163. DBG_ASSERT( ODBC_CONNECTION::Success( rc));
  164. DBGPRINTF( ( DBG_CONTEXT,
  165. " SQLDataSources( %08x) ==> RetCode = %d."
  166. " Data Sources. = ( %d bytes) %s. ",
  167. henv, rc, cbDDCur, szDriverDesc));
  168. PrintMultiString( " Data Source Description", cbDACur,
  169. (char *) szDriverAttrib);
  170. return;
  171. } // AuxOdbcFunctions()
  172. # endif // 0
  173. # endif // DBG
  174. /************************************************************
  175. * Member Functions of ODBC_PARAMETER
  176. ************************************************************/
  177. HRESULT
  178. ODBC_PARAMETER::CopyValue(
  179. IN LPCWSTR pwszValue
  180. )
  181. /*++
  182. Description:
  183. This function copies the given Unicode string as the value
  184. into current parameter marker to be used for future insertion.
  185. Arguments:
  186. pwszValue - pointer to null-terminated string containing
  187. Unicode value to be copied into the parameter
  188. marker.
  189. Returns:
  190. TRUE on success and FALSE if there is any error.
  191. Note:
  192. Since ODBC does not support Unicode directly right now, we
  193. convert string value to be ANSI before copying the value over.
  194. --*/
  195. {
  196. HRESULT hr;
  197. STRA strValue;
  198. hr = strValue.CopyW( pwszValue );
  199. if( FAILED( hr ) )
  200. {
  201. DBGPRINTF(( DBG_CONTEXT,
  202. "Error copying data, hr = 0x%x.\n",
  203. hr ));
  204. return hr;
  205. }
  206. return this->CopyValue( strValue.QueryStr() );
  207. } // ODBC_PARAMETER::CopyValue()
  208. HRESULT
  209. ODBC_PARAMETER::CopyValue(
  210. IN LPSYSTEMTIME lpst
  211. )
  212. /*++
  213. Description:
  214. This function copies the given system time into the ODBC
  215. timestamp structure for the current parameter marker to be
  216. used for future insertion.
  217. Arguments:
  218. lpSystemTime - pointer to System Time structure containing
  219. current time.
  220. Returns:
  221. TRUE on success and FALSE if there is any error.
  222. --*/
  223. {
  224. TIMESTAMP_STRUCT * ptsOdbc;
  225. DBG_ASSERT( lpst != NULL);
  226. DBG_ASSERT( m_CType == SQL_C_TIMESTAMP);
  227. DBG_ASSERT( m_SqlType == SQL_TIMESTAMP);
  228. DBG_ASSERT( m_cbValueMax >= sizeof(TIMESTAMP_STRUCT));
  229. ptsOdbc = ( TIMESTAMP_STRUCT * ) m_pValue;
  230. DBG_ASSERT( m_pValue != NULL);
  231. //
  232. // Copy the individual fields over properly
  233. // The types used in ODBC/Win32 are different
  234. // So do a type specific copy of the values.
  235. //
  236. ptsOdbc->year = (SWORD ) lpst->wYear;
  237. ptsOdbc->month = (UWORD ) lpst->wMonth;
  238. ptsOdbc->day = (UWORD ) lpst->wDay;
  239. ptsOdbc->hour = (UWORD ) lpst->wHour;
  240. ptsOdbc->minute = (UWORD ) lpst->wMinute;
  241. ptsOdbc->second = (UWORD ) lpst->wSecond;
  242. ptsOdbc->fraction = (UDWORD ) lpst->wMilliseconds;
  243. return S_OK;
  244. } // ODBC_PARAMETER::CopyValue()
  245. RETCODE
  246. ODBC_PARAMETER::Bind(
  247. IN HSTMT hStmt
  248. )
  249. /*++
  250. Description:
  251. This functions binds the data about the parameter marker 'this'
  252. ( this object) represents to the statement provided.
  253. Arguments:
  254. hStmt HANDLE for the statement to which this parameter
  255. is to be bound.
  256. Returns:
  257. RETCODE value returned by SQLBindParamater().
  258. --*/
  259. {
  260. RETCODE rc;
  261. DBG_ASSERT( hStmt != SQL_NULL_HSTMT);
  262. rc = SQLBindParameter( hStmt, // statement
  263. QueryParamNumber(),
  264. QueryParamType(),
  265. QueryCType(),
  266. QuerySqlType(),
  267. QueryPrecision(),
  268. QueryScale(),
  269. QueryValue(),
  270. QueryMaxCbValue(),
  271. &(QueryCbValueRef())
  272. );
  273. return ( rc);
  274. } // ODBC_STATEMENT::BindParameter()
  275. # if DBG
  276. VOID
  277. ODBC_PARAMETER::Print(
  278. VOID
  279. ) const
  280. {
  281. DBGPRINTF( ( DBG_CONTEXT,
  282. "Printing ODBC_PARAMETER ( %08x).\n"
  283. " Num=%u; Type=%d; CType=%d; SqlType=%d; Prec=%u;"
  284. " Scale=%d; CbMax=%d; Cb=%d.\n",
  285. this,
  286. QueryParamNumber(),
  287. QueryParamType(),
  288. QueryCType(),
  289. QuerySqlType(),
  290. QueryPrecision(),
  291. QueryScale(),
  292. QueryMaxCbValue(),
  293. QueryCbValue()));
  294. switch ( QuerySqlType() )
  295. {
  296. case SQL_INTEGER:
  297. {
  298. DWORD dwValue = *(DWORD *) QueryValue();
  299. DBGPRINTF( ( DBG_CONTEXT,
  300. " Integer Value = %u\n",
  301. dwValue ) );
  302. break;
  303. }
  304. case SQL_CHAR:
  305. {
  306. LPCSTR pszValue = (LPCSTR ) QueryValue();
  307. DBGPRINTF( ( DBG_CONTEXT,
  308. "String Value( %08x) = %s\n",
  309. pszValue,
  310. pszValue ) );
  311. break;
  312. }
  313. default:
  314. DBGPRINTF( ( DBG_CONTEXT,
  315. " Type=%d. Unknown value at %08x\n",
  316. QuerySqlType(),
  317. QueryValue() ) );
  318. break;
  319. } // switch
  320. return;
  321. } // ODBC_PARAMETER::Print()
  322. # endif // DBG
  323. /************************************************************
  324. * ODBC_STATEMENT member functions
  325. ************************************************************/
  326. ODBC_STATEMENT::~ODBC_STATEMENT( VOID)
  327. {
  328. //
  329. // Free the statement handle
  330. //
  331. if ( m_hStmt != SQL_NULL_HSTMT) {
  332. m_rc = SQLFreeStmt( m_hStmt, SQL_DROP);
  333. m_hStmt = SQL_NULL_HSTMT;
  334. // Ignore the error code here.
  335. DBG_ASSERT( ODBC_CONNECTION::Success( m_rc));
  336. IF_DEBUG( ODBC) {
  337. DBGPRINTF( ( DBG_CONTEXT,
  338. "SqlFreeStmt() return code %d.\n",
  339. m_rc));
  340. CheckAndPrintErrorMessage( this, m_rc);
  341. }
  342. }
  343. FreeColumnMemory();
  344. m_dwSignature = ODBC_STATEMENT_FREE_SIGNATURE;
  345. } // ODBC_STATEMENT::~ODBC_STATEMENT()
  346. HRESULT
  347. ODBC_STATEMENT::ExecDirect(
  348. IN LPCSTR pszSqlCommand,
  349. IN DWORD cchSqlCommand
  350. )
  351. {
  352. DBG_ASSERT( CheckSignature() );
  353. BOOL fReturn;
  354. IF_DEBUG( ODBC )
  355. {
  356. DBGPRINTF( ( DBG_CONTEXT,
  357. " Executing the SQL command (%d bytes) %s.\n",
  358. cchSqlCommand * sizeof( CHAR),
  359. pszSqlCommand));
  360. }
  361. //
  362. // SQLExecDirect only likes Unsigned chars !
  363. //
  364. m_rc = SQLExecDirectA( m_hStmt,
  365. (UCHAR FAR *) pszSqlCommand,
  366. cchSqlCommand);
  367. fReturn = ODBC_CONNECTION::Success( m_rc);
  368. IF_DEBUG( ODBC)
  369. {
  370. DBGPRINTF( ( DBG_CONTEXT,
  371. " SQLExecDirect() returns code %d\n",
  372. m_rc));
  373. CheckAndPrintErrorMessage( this, m_rc);
  374. }
  375. if( fReturn )
  376. {
  377. return S_OK;
  378. }
  379. return E_FAIL;
  380. } // ODBC_STATEMENT::ExecDirect()
  381. HRESULT
  382. ODBC_STATEMENT::ExecDirect(
  383. IN LPCWSTR pszSqlCommand,
  384. IN DWORD cchSqlCommand
  385. )
  386. {
  387. HRESULT hr;
  388. STRA strCommand;
  389. DBG_ASSERT( CheckSignature() );
  390. hr = strCommand.CopyW( pszSqlCommand );
  391. if( FAILED( hr ) )
  392. {
  393. DBGPRINTF(( DBG_CONTEXT,
  394. "Error copying sql command, hr = 0x%x.\n",
  395. hr ));
  396. return hr;
  397. }
  398. return ExecDirect( strCommand.QueryStr(), strCommand.QueryCCH() );
  399. } // ODBC_STATEMENT::ExecDirect()
  400. HRESULT
  401. ODBC_STATEMENT::PrepareStatement(
  402. IN LPCSTR pszStatement
  403. )
  404. /*++
  405. This function prepares the SQL statement for future execution.
  406. Arguments:
  407. pszStatement - pointer to null terminated string containing the
  408. statement.
  409. Returns:
  410. HRESULT
  411. --*/
  412. {
  413. DBG_ASSERT( CheckSignature() );
  414. DBG_ASSERT( QueryErrorCode() == SQL_SUCCESS &&
  415. pszStatement != NULL);
  416. m_rc = SQLPrepareA( m_hStmt, (UCHAR FAR *) pszStatement, SQL_NTS);
  417. IF_DEBUG( ODBC )
  418. {
  419. DBGPRINTF( ( DBG_CONTEXT,
  420. " SQLPrepare( %s) returns ErrorCode = %d.\n",
  421. pszStatement, m_rc));
  422. CheckAndPrintErrorMessage( this, m_rc);
  423. }
  424. m_fPreparedStmt = ODBC_CONNECTION::Success( m_rc );
  425. if( m_fPreparedStmt )
  426. {
  427. return S_OK;
  428. }
  429. return E_FAIL;
  430. } // ODBC_STATEMENT::PrepareStatment()
  431. HRESULT
  432. ODBC_STATEMENT::PrepareStatement(
  433. IN LPCWSTR pwszCommand
  434. )
  435. /*++
  436. This function prepares an ODBC statement for execution.
  437. Since ODBC does not support UNICODE, we convert the statement
  438. into ANSI before calling the APIs.
  439. Arguments:
  440. pwszCommand - pointer to null-terminated string containing the
  441. statement to be prepared.
  442. Returns:
  443. HRESULT
  444. --*/
  445. {
  446. STRA strCommand;
  447. HRESULT hr;
  448. DBG_ASSERT( CheckSignature() );
  449. hr = strCommand.CopyW( pwszCommand );
  450. if( FAILED( hr ) )
  451. {
  452. DBGPRINTF(( DBG_CONTEXT,
  453. "Error copying command, hr = 0x%x.\n",
  454. hr ));
  455. return hr;
  456. }
  457. return PrepareStatement( strCommand.QueryStr() );
  458. } // ODBC_STATEMENT::PrepareStatement()
  459. HRESULT
  460. ODBC_STATEMENT::BindParameter(
  461. IN PODBC_PARAMETER pOdbcParameter
  462. )
  463. {
  464. DBG_ASSERT( CheckSignature() );
  465. DBG_ASSERT( ODBC_CONNECTION::Success( m_rc) &&
  466. pOdbcParameter != NULL);
  467. m_rc = pOdbcParameter->Bind( m_hStmt);
  468. IF_DEBUG( ODBC) {
  469. CheckAndPrintErrorMessage( this, m_rc );
  470. }
  471. if( ODBC_CONNECTION::Success( m_rc ) )
  472. {
  473. return S_OK;
  474. }
  475. return E_FAIL;
  476. } // ODBC_STATEMENT::BindParameter()
  477. HRESULT
  478. ODBC_STATEMENT::ExecuteStatement(
  479. VOID
  480. )
  481. /*++
  482. This function executes a prepared ODBC statement. At the end of
  483. execution, the transaction is also committed to ensure that the
  484. record is automatically written to the database.
  485. Arguments:
  486. None
  487. Returns:
  488. HRESULT
  489. --*/
  490. {
  491. DBG_ASSERT( CheckSignature() );
  492. DBG_ASSERT( m_fPreparedStmt != FALSE);
  493. if ( !ODBC_CONNECTION::Success( QueryErrorCode()) )
  494. {
  495. DBGPRINTF(( DBG_CONTEXT,
  496. "!!WARNING!! - Attempting to use Invalid ODBC Connection!\n" ));
  497. }
  498. m_rc = SQLExecute( m_hStmt);
  499. IF_DEBUG( ODBC)
  500. {
  501. CheckAndPrintErrorMessage( this, m_rc);
  502. }
  503. if( ODBC_CONNECTION::Success( m_rc ) )
  504. {
  505. return S_OK;
  506. }
  507. return E_FAIL;
  508. } // ODBC_STATEMENT::ExecuteStatement()
  509. HRESULT
  510. ODBC_STATEMENT::QueryRowCount(
  511. OUT SQLLEN *pcRows
  512. )
  513. /*++
  514. Calls SQLRowCount on the current result set.
  515. NOTE: Not all database implementations support this!!
  516. Arguments:
  517. pcRows - Receives count of rows
  518. Returns:
  519. TRUE on success and FALSE if there are any failures.
  520. Note:
  521. --*/
  522. {
  523. DBG_ASSERT( CheckSignature() );
  524. m_rc = SQLRowCount( m_hStmt,
  525. pcRows );
  526. if( ODBC_CONNECTION::Success( m_rc ) )
  527. {
  528. return S_OK;
  529. }
  530. return E_FAIL;
  531. }
  532. HRESULT
  533. ODBC_STATEMENT::QueryColNames(
  534. STRA * * pastrCols,
  535. DWORD * cCols,
  536. DWORD cchMaxFieldSize,
  537. BOOL * pfHaveResultSet
  538. )
  539. /*++
  540. This method returns the list of column names from the result table
  541. Arguments:
  542. pastrCols - Receives an array of STRAs containing the column names
  543. cCols - Count of columns returned (zero for no result set)
  544. cchMaxFieldSize - Maximum buffer size to allocate for any data
  545. fields, zero means use the default value.
  546. pfHaveResultSet - Set to TRUE if the current query was a SELECT
  547. and thus has rows that can be enumerated
  548. Returns:
  549. TRUE on success and FALSE if there are any failures.
  550. Note:
  551. --*/
  552. {
  553. HRESULT hr;
  554. SWORD nresultcols;
  555. SWORD i;
  556. CHAR achColName[64];
  557. SWORD cchColName;
  558. SWORD ColType;
  559. DWORD cchColLength;
  560. SWORD scale;
  561. SWORD nullable;
  562. *pastrCols = NULL;
  563. *cCols = 0;
  564. *pfHaveResultSet = TRUE;
  565. DBG_ASSERT( CheckSignature() );
  566. //
  567. // Return the old binding info if we already have it
  568. //
  569. if ( m_astrColNames )
  570. {
  571. *pastrCols = m_astrColNames;
  572. *cCols = m_cCols;
  573. return S_OK;
  574. }
  575. //
  576. // Provide a default maximum field size if none was specified
  577. //
  578. if ( !cchMaxFieldSize )
  579. {
  580. cchMaxFieldSize = DEFAULT_MAX_FIELD_SIZE;
  581. }
  582. //
  583. // See what kind of statement it was. If there are no result
  584. // columns, the statement is not a SELECT statement.
  585. //
  586. m_rc = SQLNumResultCols( m_hStmt,
  587. &nresultcols );
  588. if ( !ODBC_CONNECTION::Success( m_rc ) )
  589. {
  590. return E_FAIL;
  591. }
  592. if ( nresultcols > 0 )
  593. {
  594. //
  595. // Allocate an array of strings for the column names and
  596. // the column values
  597. //
  598. m_cCols = nresultcols;
  599. *cCols = m_cCols;
  600. m_astrColNames = new STRA[m_cCols];
  601. m_astrValues = new STRA[m_cCols];
  602. m_acbValue = new SQLLEN[m_cCols];
  603. if( m_astrColNames == NULL ||
  604. m_astrValues == NULL ||
  605. m_acbValue == NULL )
  606. {
  607. return HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  608. }
  609. //
  610. // Otherwise, get the column names of the result set and
  611. // use the display_size() function to compute the length
  612. // needed by each data type. Next, bind the columns and
  613. // specify all data will be converted to char.
  614. //
  615. for (i = 0; i < m_cCols; i++ )
  616. {
  617. m_rc = SQLDescribeColA( m_hStmt,
  618. i + 1,
  619. (UCHAR *) achColName,
  620. (SWORD)sizeof(achColName),
  621. &cchColName,
  622. &ColType,
  623. &cchColLength,
  624. &scale,
  625. &nullable );
  626. if ( !ODBC_CONNECTION::Success( m_rc ) )
  627. {
  628. return E_FAIL;
  629. }
  630. //
  631. // Select the buffer size for the retrieved data for
  632. // this column
  633. //
  634. cchColLength = ODBC_CONNECTION::DisplaySize( ColType,
  635. min( cchColLength, cchMaxFieldSize ) );
  636. //
  637. // Copy the column name and set the column data size
  638. //
  639. hr = m_astrColNames[i].Copy( achColName );
  640. if( FAILED( hr ) )
  641. {
  642. DBGPRINTF(( DBG_CONTEXT,
  643. "Error copying colume name, hr = 0x%x.\n",
  644. hr ));
  645. return hr;
  646. }
  647. hr = m_astrValues[i].Resize( cchColLength + 1 );
  648. if ( FAILED( hr ) )
  649. {
  650. DBGPRINTF(( DBG_CONTEXT,
  651. "Error resizing string buffer, hr = 0x%x.\n",
  652. hr ));
  653. return hr;
  654. }
  655. m_rc = SQLBindCol( m_hStmt,
  656. i + 1,
  657. SQL_C_CHAR,
  658. m_astrValues[i].QueryStr(),
  659. cchColLength,
  660. &m_acbValue[i] );
  661. if ( !ODBC_CONNECTION::Success( m_rc ) )
  662. {
  663. return E_FAIL;
  664. }
  665. }
  666. *pastrCols = m_astrColNames;
  667. *cCols = m_cCols;
  668. }
  669. else
  670. {
  671. *pfHaveResultSet = FALSE;
  672. }
  673. return S_OK;
  674. }
  675. HRESULT
  676. ODBC_STATEMENT::QueryValuesAsStr(
  677. STRA * * pastrValues,
  678. OUT DWORD * * pacbValues,
  679. BOOL * pfLast
  680. )
  681. /*++
  682. This method gets the data at the current position.
  683. Arguments:
  684. pastrValues - Receives a pointer to an array of strings that contains
  685. the alphanumeric representation of that field
  686. pacbValues - Receives pointer to array of DWORDs that contain the length
  687. of the field
  688. pfLast - Set to TRUE if there are no more values to retrieve
  689. Returns:
  690. HRESULT
  691. Note:
  692. --*/
  693. {
  694. HRESULT hr;
  695. DBG_ASSERT( CheckSignature() );
  696. *pastrValues = NULL;
  697. //
  698. // Build the bindings if we haven't already
  699. //
  700. if ( !m_astrColNames )
  701. {
  702. STRA * astrCols;
  703. DWORD cCols;
  704. BOOL fHaveResultSet;
  705. hr = QueryColNames( &astrCols,
  706. &cCols,
  707. 0,
  708. &fHaveResultSet );
  709. if ( FAILED( hr ) )
  710. {
  711. return hr;
  712. }
  713. }
  714. //
  715. // If there are columns to enumerate, get them now
  716. //
  717. if ( m_astrColNames )
  718. {
  719. DWORD i;
  720. //
  721. // Zero terminate the columns as some drivers don't write
  722. // anything for NULL fields
  723. //
  724. for ( i = 0; i < m_cCols; i++ )
  725. {
  726. *((CHAR *) m_astrValues[i].QueryStr()) = '\0';
  727. m_acbValue[i] = 0;
  728. }
  729. //
  730. // Fill in the binding values
  731. //
  732. m_rc = SQLFetch( m_hStmt );
  733. if ( m_rc == SQL_NO_DATA_FOUND )
  734. {
  735. *pfLast = TRUE;
  736. }
  737. else
  738. {
  739. if ( !ODBC_CONNECTION::Success( m_rc ) )
  740. {
  741. return E_FAIL;
  742. }
  743. *pfLast = FALSE;
  744. }
  745. *pastrValues = m_astrValues;
  746. *pacbValues = ( DWORD * ) m_acbValue;
  747. }
  748. else
  749. {
  750. *pfLast = TRUE;
  751. }
  752. return S_OK;
  753. }
  754. HRESULT
  755. ODBC_STATEMENT::MoreResults(
  756. BOOL * pfMoreResults
  757. )
  758. /*++
  759. Determines if there are any more results sets to return to
  760. the user
  761. pfMoreResults - Set to TRUE if there are more results in the
  762. result set
  763. --*/
  764. {
  765. DBG_ASSERT( CheckSignature() );
  766. *pfMoreResults = TRUE;
  767. m_rc = SQLMoreResults( m_hStmt );
  768. if ( m_rc == SQL_NO_DATA_FOUND )
  769. {
  770. *pfMoreResults = FALSE;
  771. return S_OK;
  772. }
  773. if ( !ODBC_CONNECTION::Success( m_rc ))
  774. {
  775. return E_FAIL;
  776. }
  777. return S_OK;
  778. }
  779. VOID
  780. ODBC_STATEMENT::FreeColumnMemory(
  781. VOID
  782. )
  783. /*++
  784. This method frees memory allocated by the QueryColNames and
  785. QueryValuesAsStr methods.
  786. --*/
  787. {
  788. DBG_ASSERT( CheckSignature() );
  789. if ( m_astrColNames ) delete [] m_astrColNames;
  790. if ( m_astrValues ) delete [] m_astrValues;
  791. if ( m_acbValue ) delete [] m_acbValue;
  792. m_astrColNames = NULL;
  793. m_astrValues = NULL;
  794. m_acbValue = NULL;
  795. }
  796. //static
  797. HRESULT
  798. ODBC_STATEMENT::Initialize(
  799. VOID
  800. )
  801. /*++
  802. Routine Description:
  803. Initialize ODBC_STATEMENT lookaside
  804. Arguments:
  805. None
  806. Return Value:
  807. HRESULT
  808. --*/
  809. {
  810. ALLOC_CACHE_CONFIGURATION acConfig;
  811. acConfig.nConcurrency = 1;
  812. acConfig.nThreshold = 100;
  813. acConfig.cbSize = sizeof( ODBC_STATEMENT );
  814. DBG_ASSERT( sm_pachOdbcStatements == NULL );
  815. sm_pachOdbcStatements = new ALLOC_CACHE_HANDLER( "ODBC_STATEMENT",
  816. &acConfig );
  817. if ( sm_pachOdbcStatements == NULL )
  818. {
  819. return HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  820. }
  821. return NO_ERROR;
  822. }
  823. //static
  824. VOID
  825. ODBC_STATEMENT::Terminate(
  826. VOID
  827. )
  828. /*++
  829. Routine Description:
  830. Terminate ODBC_STATEMENT lookaside
  831. Arguments:
  832. None
  833. Return Value:
  834. None
  835. --*/
  836. {
  837. if ( sm_pachOdbcStatements != NULL )
  838. {
  839. delete sm_pachOdbcStatements;
  840. sm_pachOdbcStatements = NULL;
  841. }
  842. }
  843. # if DBG
  844. VOID
  845. ODBC_STATEMENT::Print( VOID) const
  846. {
  847. DBGPRINTF( ( DBG_CONTEXT,
  848. " Printing ODBC_STATEMENT( %08x)."
  849. " HStmt = %08x. OdbcConn=%08x. RetCode = %d\n",
  850. m_hStmt, m_pOdbcConnection, m_rc));
  851. } // ODBC_STATEMENT::Print()
  852. # endif // DBG
  853. /**************************************************
  854. * Member Functions of class ODBC_CONNECTION
  855. **************************************************/
  856. ODBC_CONNECTION::~ODBC_CONNECTION( VOID)
  857. /*++
  858. This function closes the odbc connection ( if open) and cleans up.
  859. --*/
  860. {
  861. DBG_REQUIRE( SUCCEEDED( Close() ) );
  862. return;
  863. } // ODBC_CONNECTION::~ODBC_CONNECTION()
  864. HRESULT
  865. ODBC_CONNECTION::Open(
  866. IN LPCSTR pszDataSource,
  867. IN LPCSTR pszUserName,
  868. IN LPCSTR pszPassword
  869. )
  870. /*++
  871. This function opens a new odbc connection to given data source
  872. using the user name and password supplied.
  873. Arguments:
  874. pszDataSource - pointer to null-terminated string containing ODBC
  875. data source name
  876. pszUserName - pointer to null-terminated string containing
  877. UserName
  878. pszPassword - pointer to null-terminated string containing
  879. Password
  880. Returns:
  881. HRESULT
  882. --*/
  883. {
  884. HRESULT hr = S_OK;
  885. BOOL fReturn = FALSE;
  886. DBG_ASSERT( pszDataSource != NULL &&
  887. pszUserName != NULL &&
  888. pszPassword != NULL );
  889. //
  890. // Allocate an ODBC environment
  891. //
  892. m_rc = SQLAllocEnv( &m_henv );
  893. fReturn = Success( m_rc );
  894. IF_DEBUG( ODBC ) {
  895. DBGPRINTF( ( DBG_CONTEXT,
  896. "SQLAllocEnv() returned ErrorCode %d. henv = %08x\n",
  897. m_rc, m_henv));
  898. CheckAndPrintErrorMessage( this, m_rc);
  899. }
  900. if ( fReturn ) {
  901. //
  902. // Establish memory for connection handle within the environment
  903. //
  904. m_rc = SQLAllocConnect( m_henv, &m_hdbc);
  905. fReturn = Success( m_rc);
  906. IF_DEBUG( ODBC) {
  907. DBGPRINTF( ( DBG_CONTEXT,
  908. "SQLAllocConnect() returns code %d. hdbc = %08x\n",
  909. m_rc, m_hdbc));
  910. CheckAndPrintErrorMessage( this, m_rc);
  911. }
  912. }
  913. if ( fReturn) {
  914. //
  915. // Use Following call to just printout the dynamic values for ODBC
  916. //
  917. // AuxOdbcFunctions( m_henv, m_hdbc);
  918. #if 0
  919. {
  920. STRA str;
  921. STRA strOut;
  922. SWORD swStrOut;
  923. if ( FAILED( str.Append( pszDataSource ) ) ||
  924. FAILED( str.Append( ";UID=" ) ) ||
  925. FAILED( str.Append( pszUserName ) ) ||
  926. FAILED( str.Append( ";PWD=" ) ) ||
  927. FAILED( str.Append( pszPassword ) ) ||
  928. FAILED( str.Append( ";APP=Internet Services") ) ||
  929. FAILED( strOut.Resize( 255 ) ) )
  930. {
  931. return HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  932. }
  933. m_rc = SQLDriverConnect( m_hdbc,
  934. NULL,
  935. (UCHAR *) str.QueryStr(),
  936. SQL_NTS,
  937. (UCHAR *) strOut.QueryStr(),
  938. strOut.QuerySize(),
  939. &swStrOut,
  940. SQL_DRIVER_NOPROMPT );
  941. }
  942. #else
  943. {
  944. m_rc = SQLConnectA( m_hdbc,
  945. (UCHAR FAR *) pszDataSource, SQL_NTS,
  946. (UCHAR FAR *) pszUserName, SQL_NTS,
  947. (UCHAR FAR *) pszPassword, SQL_NTS );
  948. }
  949. #endif
  950. fReturn = Success( m_rc);
  951. IF_DEBUG( ODBC) {
  952. DBGPRINTF( ( DBG_CONTEXT,
  953. "SQLConnect( %s, %s, %s) returns code %d.\n",
  954. pszDataSource,
  955. pszUserName,
  956. pszPassword,
  957. m_rc ) );
  958. CheckAndPrintErrorMessage( this, m_rc );
  959. }
  960. }
  961. m_fValid = fReturn;
  962. if ( !fReturn ) {
  963. hr = HRESULT_FROM_WIN32( ERROR_GEN_FAILURE );
  964. }
  965. return hr;
  966. } // ODBC_CONNECTION::Open()
  967. HRESULT
  968. ODBC_CONNECTION::Open(
  969. IN LPCWSTR pwszDataSource,
  970. IN LPCWSTR pwszUserName,
  971. IN LPCWSTR pwszPassword
  972. )
  973. /*++
  974. This function opens a new odbc connection to given data source
  975. using the user name and password supplied.
  976. Arguments:
  977. pwszDataSource - pointer to null-terminated string containing ODBC
  978. data source name
  979. pwszUserName - pointer to null-terminated string containing
  980. UserName
  981. pwszPassword - pointer to null-terminated string containing
  982. Password
  983. Returns:
  984. TRUE on success and FALSE if there is an error.
  985. Note:
  986. Poor me. ODBC Does not take UNICODE strings :(. 2/15/95
  987. So we will explicitly convert parameters to ANSI on stack.
  988. --*/
  989. {
  990. HRESULT hr;
  991. STRA strDataSource;
  992. STRA strUserName;
  993. STRA strPassword;
  994. //
  995. // Convert all parameters from UNICODE to ANSI
  996. //
  997. hr = strDataSource.CopyW( pwszDataSource );
  998. if( FAILED( hr ) )
  999. {
  1000. return hr;
  1001. }
  1002. hr = strUserName.CopyW( pwszUserName );
  1003. if( FAILED( hr ) )
  1004. {
  1005. return hr;
  1006. }
  1007. hr = strPassword.CopyW( pwszPassword );
  1008. if( FAILED( hr ) )
  1009. {
  1010. return hr;
  1011. }
  1012. //
  1013. // Make an ANSI open call.
  1014. //
  1015. hr = Open( strDataSource.QueryStr(),
  1016. strUserName.QueryStr(),
  1017. strPassword.QueryStr() );
  1018. //
  1019. // Zero the password for security reasons.
  1020. //
  1021. SecureZeroMemory( strPassword.QueryStr(), strPassword.QueryCB() );
  1022. return hr;
  1023. } // ODBC_CONNECTION::Open()
  1024. HRESULT
  1025. ODBC_CONNECTION::Close(
  1026. VOID
  1027. )
  1028. /*++
  1029. This function closes the connection established with the ODBC
  1030. and frees up and dynamic memory used.
  1031. Returns:
  1032. TRUE on success and FALSE if there are any failures.
  1033. Note:
  1034. Intermediate failures are ignored. Normally they should not occur.
  1035. --*/
  1036. {
  1037. BOOL fReturn = TRUE;
  1038. //
  1039. // Disconnect and free the connection.
  1040. //
  1041. if ( m_hdbc != SQL_NULL_HDBC)
  1042. {
  1043. m_rc = SQLDisconnect( m_hdbc );
  1044. //
  1045. // Disconnect is allowed to fail w/o being fatal so don't set
  1046. // fReturn
  1047. //
  1048. IF_DEBUG( ODBC)
  1049. {
  1050. DBGPRINTF( ( DBG_CONTEXT,
  1051. "Warning: SQLDisconnect() returns code %d.\n",
  1052. m_rc));
  1053. CheckAndPrintErrorMessage( this, m_rc);
  1054. }
  1055. m_rc = SQLFreeConnect( m_hdbc);
  1056. m_hdbc = SQL_NULL_HDBC;
  1057. fReturn = fReturn && Success( m_rc);
  1058. IF_DEBUG( ODBC)
  1059. {
  1060. DBGPRINTF( ( DBG_CONTEXT,
  1061. "SQLFreeConnect() returns code %d.\n",
  1062. m_rc));
  1063. CheckAndPrintErrorMessage( this, m_rc);
  1064. }
  1065. if( !fReturn )
  1066. {
  1067. return E_FAIL;
  1068. }
  1069. }
  1070. //
  1071. // Free the ODBC environment handle.
  1072. //
  1073. if ( m_henv != SQL_NULL_HENV) {
  1074. m_rc = SQLFreeEnv( m_henv);
  1075. m_henv = SQL_NULL_HENV;
  1076. fReturn = fReturn && Success( m_rc);
  1077. IF_DEBUG( ODBC)
  1078. {
  1079. DBGPRINTF( ( DBG_CONTEXT,
  1080. "SQLFreeEnv() returns code %d.\n",
  1081. m_rc));
  1082. CheckAndPrintErrorMessage( this, m_rc);
  1083. }
  1084. if( !fReturn )
  1085. {
  1086. return E_FAIL;
  1087. }
  1088. }
  1089. return S_OK;
  1090. } // ODBC_CONNECTION::Close()
  1091. PODBC_STATEMENT
  1092. ODBC_CONNECTION::AllocStatement( VOID)
  1093. /*++
  1094. Description:
  1095. This function allocates a new ODBC statement object and also
  1096. calls SQLAllocStatement to create the state required for
  1097. establishing the statement in the ODBC Manager.
  1098. Arguments:
  1099. None
  1100. Returns:
  1101. TRUE on success and FALSE if there is any failure.
  1102. --*/
  1103. {
  1104. PODBC_STATEMENT pOdbcStmt = NULL;
  1105. HSTMT hstmt = SQL_NULL_HSTMT;
  1106. DBG_ASSERT( Success( m_rc));
  1107. //
  1108. // Allocate a statement handle and associate it with the connection.
  1109. //
  1110. m_rc = SQLAllocStmt( m_hdbc, &hstmt);
  1111. IF_DEBUG( ODBC) {
  1112. DBGPRINTF( ( DBG_CONTEXT,
  1113. "SqlAllocStmt() returns code %d."
  1114. " New Hstmt is : %08x\n",
  1115. m_rc, hstmt));
  1116. CheckAndPrintErrorMessage( this, m_rc);
  1117. }
  1118. if ( ODBC_CONNECTION::Success( m_rc)) {
  1119. pOdbcStmt = new ODBC_STATEMENT( this, hstmt);
  1120. }
  1121. return ( pOdbcStmt );
  1122. } // ODBC_CONNECTION::AllocStatement()
  1123. HRESULT
  1124. ODBC_CONNECTION::SetConnectOption(
  1125. IN UWORD Option,
  1126. IN SQLULEN Param
  1127. )
  1128. /*++
  1129. Sets various options on this connection
  1130. Arguments:
  1131. Option - Option to set
  1132. Param - Option value (32 bit dword or pointer to null terminated
  1133. string )
  1134. Returns:
  1135. HRESULT. Failures are considered to be soft errors as the problem
  1136. may be the driver doesn't support the option etc.
  1137. Note:
  1138. --*/
  1139. {
  1140. BOOL fReturn = TRUE;
  1141. RETCODE rc;
  1142. if ( m_hdbc != SQL_NULL_HDBC)
  1143. {
  1144. rc = SQLSetConnectOption( m_hdbc, Option, Param );
  1145. fReturn = Success( rc );
  1146. IF_DEBUG( ODBC )
  1147. {
  1148. DBGPRINTF( ( DBG_CONTEXT,
  1149. "SQLSetConnectOption( %d, %d ) returns code %d.\n",
  1150. Option,
  1151. Param,
  1152. rc ) );
  1153. CheckAndPrintErrorMessage( this, rc);
  1154. }
  1155. }
  1156. else
  1157. {
  1158. DBGPRINTF( ( DBG_CONTEXT,
  1159. "[SetConnectOption] Warning: "
  1160. "Setting option on closed connection\n" ));
  1161. }
  1162. if( fReturn )
  1163. {
  1164. return S_OK;
  1165. }
  1166. return E_FAIL;
  1167. }
  1168. BOOL
  1169. ODBC_CONNECTION::GetLastErrorText(
  1170. OUT STRA * pstrError,
  1171. IN HSTMT hstmt,
  1172. IN RETCODE rc
  1173. ) const
  1174. /*++
  1175. This method returns the textual representation of the last ODBC or
  1176. windows error that occurred. Even though the ODBC methods return
  1177. FALSE on failure, if it was an ODBC call that failed, then
  1178. GetLastError won't return the needed error code. Clients of this
  1179. class should call this method to get a descriptive text string of
  1180. the failure.
  1181. Returns:
  1182. TRUE on success and FALSE if there are any failures.
  1183. Note:
  1184. If this function returns FALSE, then a client should call
  1185. GetLastError for the error code.
  1186. --*/
  1187. {
  1188. BOOL fReturn = TRUE;
  1189. if ( ODBC_CONNECTION::Success( rc)) {
  1190. fReturn = SUCCEEDED(pstrError->LoadString( GetLastError() ));
  1191. }
  1192. else
  1193. {
  1194. CHAR rgchMsg[ SQL_MAX_MESSAGE_LENGTH + 10];
  1195. CHAR achState[30];
  1196. CHAR rgchFullMsg[ sizeof(rgchMsg) + sizeof(achState) + 60];
  1197. SWORD cbMsg;
  1198. LONG lError;
  1199. //
  1200. // If we're formatting as HTML, we bullet list the items
  1201. //
  1202. pstrError->Reset();
  1203. //
  1204. // Loop to pick up all of the errors
  1205. //
  1206. do {
  1207. cbMsg = SQL_MAX_MESSAGE_LENGTH;
  1208. rc = SQLErrorA( m_henv,
  1209. m_hdbc,
  1210. hstmt,
  1211. (UCHAR *) achState,
  1212. &lError,
  1213. (UCHAR *) rgchMsg,
  1214. cbMsg,
  1215. &cbMsg );
  1216. if ( ODBC_CONNECTION::Success( rc))
  1217. {
  1218. wsprintfA( rgchFullMsg,
  1219. "[State=%s][Error=%d]%s\n",
  1220. achState, lError, rgchMsg);
  1221. if ( FAILED( pstrError->Append( rgchFullMsg ) ) )
  1222. {
  1223. fReturn = FALSE;
  1224. break;
  1225. }
  1226. }
  1227. else
  1228. {
  1229. //
  1230. // This is indicates there are no more error strings
  1231. // to pick up so we should get out
  1232. //
  1233. if ( rc == SQL_NO_DATA_FOUND )
  1234. {
  1235. //
  1236. // Append the end of unorder list marker
  1237. //
  1238. rc = SQL_SUCCESS;
  1239. break;
  1240. }
  1241. }
  1242. } while ( ODBC_CONNECTION::Success( rc ) );
  1243. if ( !ODBC_CONNECTION::Success( rc ) )
  1244. {
  1245. DBGPRINTF( ( DBG_CONTEXT,
  1246. "[GetLastErrorText] SqlError() returned error %d.\n",
  1247. rc));
  1248. SetLastError( ERROR_GEN_FAILURE );
  1249. fReturn = FALSE;
  1250. }
  1251. }
  1252. return ( fReturn);
  1253. } // ODBC_CONNECTION::GetLastErrorText()
  1254. /*******************************************************************
  1255. NAME: EncodeStringToHTML2
  1256. SYNOPSIS: Enode string in HTML format - same as w3/server/doget.cxx:EncodeStringToHTML
  1257. ENTRY: szSrc - Source string to be encoded, in system codepage
  1258. szDest - Space to output HTML (in system codepage)
  1259. cbDest - Size of space in szDest (number of bytes)
  1260. RETURNS: number of bytes required for HTML text
  1261. NOTES: If cbDest is less than target HTML, then we fit
  1262. as much characters as possible into szDest. But the
  1263. return value remains the same and is greater than
  1264. cbDest. szDest is not zero terminated in this case.
  1265. HISTORY:
  1266. markzh 17-Jan-2002 Created
  1267. minglu 17-Jan-2002 Ported to IIS6
  1268. ********************************************************************/
  1269. UINT EncodeStringToHTML2(CHAR *szSrc, CHAR *szDest, UINT cbDest)
  1270. {
  1271. CHAR *pSrc = szSrc;
  1272. CHAR *pDest = szDest;
  1273. BOOL isSecondByte=FALSE;
  1274. do {
  1275. CHAR *szAppend = pSrc;
  1276. UINT cbAppend = 1;
  1277. // We may be running on DBCS. Ideally we should encode them to &#nnnnn
  1278. // but we dont want that many code here
  1279. if (isSecondByte)
  1280. {
  1281. isSecondByte = FALSE;
  1282. }
  1283. else if (IsDBCSLeadByte(*pSrc))
  1284. {
  1285. isSecondByte = TRUE;
  1286. }
  1287. else switch (*pSrc)
  1288. {
  1289. #define SetAppend(s) (szAppend=(s), cbAppend=sizeof(s)-1)
  1290. case '&': SetAppend("&amp;");
  1291. break;
  1292. case '"': SetAppend("&quot;");
  1293. break;
  1294. case '<': SetAppend("&lt;");
  1295. break;
  1296. case '>': SetAppend("&gt;");
  1297. break;
  1298. default:
  1299. break;
  1300. #undef SetAppend
  1301. }
  1302. if (pDest - szDest + cbAppend <= cbDest)
  1303. {
  1304. memcpy(pDest, szAppend, cbAppend);
  1305. }
  1306. pDest += cbAppend;
  1307. }while (*pSrc++);
  1308. return (UINT) (pDest - szDest);
  1309. }
  1310. BOOL
  1311. ODBC_CONNECTION::GetLastErrorTextAsHtml(
  1312. OUT STRA * pstrError,
  1313. IN HSTMT hstmt,
  1314. IN RETCODE rc
  1315. ) const
  1316. /*++
  1317. This method returns the textual representation of the last ODBC or
  1318. windows error that occurred. Even though the ODBC methods return
  1319. FALSE on failure, if it was an ODBC call that failed, then
  1320. GetLastError won't return the needed error code. Clients of this
  1321. class should call this method to get a descriptive text string of
  1322. the failure.
  1323. Returns:
  1324. TRUE on success and FALSE if there are any failures.
  1325. Note:
  1326. If this function returns FALSE, then a client should call
  1327. GetLastError for the error code.
  1328. --*/
  1329. {
  1330. BOOL fReturn = TRUE;
  1331. HRESULT hr;
  1332. if ( ODBC_CONNECTION::Success( rc)) {
  1333. fReturn = SUCCEEDED(pstrError->LoadString( GetLastError()));
  1334. } else {
  1335. CHAR rgchMsg[ SQL_MAX_MESSAGE_LENGTH + 10];
  1336. CHAR achState[30];
  1337. CHAR rgchFullMsg[ sizeof(rgchMsg) + sizeof(achState) + 60];
  1338. SWORD cbMsg;
  1339. LONG lError;
  1340. //
  1341. // If we're formatting as HTML, we bullet list the items
  1342. //
  1343. if ( FAILED( hr = pstrError->Copy( "<UL>" ) ) )
  1344. {
  1345. DBGPRINTF(( DBG_CONTEXT,
  1346. "Error copying error data, hr = 0x%x.\n",
  1347. hr ));
  1348. return FALSE;
  1349. }
  1350. //
  1351. // Loop to pick up all of the errors
  1352. //
  1353. do {
  1354. cbMsg = SQL_MAX_MESSAGE_LENGTH;
  1355. rc = SQLErrorA( m_henv,
  1356. m_hdbc,
  1357. hstmt,
  1358. (UCHAR *) achState,
  1359. &lError,
  1360. (UCHAR *) rgchMsg,
  1361. cbMsg,
  1362. &cbMsg );
  1363. if ( ODBC_CONNECTION::Success( rc))
  1364. {
  1365. wsprintfA( rgchFullMsg,
  1366. "<LI>[State=%s][Error=%d]",
  1367. achState, lError);
  1368. if ( FAILED( hr = pstrError->Append( rgchFullMsg ) ) )
  1369. {
  1370. DBGPRINTF(( DBG_CONTEXT,
  1371. "Error appending error msg, hr = 0x%x.\n",
  1372. hr ));
  1373. fReturn = FALSE;
  1374. break;
  1375. }
  1376. //
  1377. // since we call it "AsHTML", we need to encode it as such
  1378. //
  1379. DWORD cbRequired = EncodeStringToHTML2(rgchMsg, rgchFullMsg, sizeof(rgchFullMsg));
  1380. if (cbRequired > sizeof(rgchFullMsg)-1)
  1381. {
  1382. //truncate error message when overflow
  1383. strcpy(&rgchFullMsg[ sizeof(rgchFullMsg)-5 ], "...\n");
  1384. }
  1385. else
  1386. {
  1387. strcpy(&rgchFullMsg[ cbRequired-1 ], "\n");
  1388. }
  1389. if ( FAILED( hr = pstrError->Append( rgchFullMsg ) ) )
  1390. {
  1391. DBGPRINTF(( DBG_CONTEXT,
  1392. "Error appending error msg, hr = 0x%x.\n",
  1393. hr ));
  1394. fReturn = FALSE;
  1395. break;
  1396. }
  1397. }
  1398. else
  1399. {
  1400. //
  1401. // This is indicates there are no more error strings
  1402. // to pick up so we should get out
  1403. //
  1404. if ( rc == SQL_NO_DATA_FOUND )
  1405. {
  1406. //
  1407. // Append the end of unorder list marker
  1408. //
  1409. if ( FAILED( hr = pstrError->Append( "</UL>" ) ) )
  1410. {
  1411. DBGPRINTF(( DBG_CONTEXT,
  1412. "Error appending error, hr = 0x%x.\n",
  1413. hr ));
  1414. return FALSE;
  1415. }
  1416. rc = SQL_SUCCESS;
  1417. break;
  1418. }
  1419. }
  1420. } while ( ODBC_CONNECTION::Success( rc ) );
  1421. if ( !ODBC_CONNECTION::Success( rc) )
  1422. {
  1423. DBGPRINTF( ( DBG_CONTEXT,
  1424. "[GetLastErrorText] SqlError() returned error %d.\n",
  1425. rc ) );
  1426. SetLastError( ERROR_GEN_FAILURE );
  1427. fReturn = FALSE;
  1428. }
  1429. }
  1430. return ( fReturn);
  1431. } // ODBC_CONNECTION::GetLastErrorTextAsHtml()
  1432. BOOL
  1433. ODBC_CONNECTION::GetInfo(IN DWORD fInfoType,
  1434. IN PVOID rgbInfoValue,
  1435. IN DWORD cbInfoValueMax,
  1436. IN OUT DWORD * pcbInfoValue)
  1437. /*++
  1438. This function obtains the value of the fInfoType for a specific
  1439. ODBC Connection. It mimicks the SQLGetInfo() and uses it to obtain
  1440. this value. On successful return the pointer rgbInfoValue contains
  1441. the requested value and pcbInfoValue contains the size in bytes of
  1442. data.
  1443. Arguments:
  1444. fInfoType - flag containing the Information Type (name) to be
  1445. fetched.
  1446. rgbInfoValue - pointer to buffer which will contain the return
  1447. data.
  1448. cbInfoValue - size of rgbInfoValue in bytes.
  1449. pcbInfoValue - pointer to location that will contain the size of
  1450. information stored in rgbInfoValue, on successful
  1451. return. If buffer is insufficient, this location
  1452. will contain the required number of bytes.
  1453. Returns:
  1454. TRUE on success and FALSE if there is any failure.
  1455. --*/
  1456. {
  1457. BOOL fReturn = FALSE;
  1458. if ( m_hdbc != SQL_NULL_HDBC)
  1459. {
  1460. RETCODE rc;
  1461. rc = SQLGetInfo( m_hdbc, (UWORD ) fInfoType,
  1462. (PTR) rgbInfoValue,
  1463. (SWORD) cbInfoValueMax,
  1464. (SWORD FAR *) pcbInfoValue );
  1465. fReturn = Success( rc );
  1466. IF_DEBUG( ODBC)
  1467. {
  1468. DBGPRINTF( ( DBG_CONTEXT,
  1469. "SQLGetInfo( %08x, %d, %08x, %d, %08x) returns %d.\n",
  1470. m_hdbc, fInfoType, rgbInfoValue, cbInfoValueMax,
  1471. pcbInfoValue, rc ) );
  1472. CheckAndPrintErrorMessage( this, rc );
  1473. }
  1474. }
  1475. else
  1476. {
  1477. DBGPRINTF( ( DBG_CONTEXT,
  1478. "[SQLGetInfo] Invalid Connection to ODBC\n"));
  1479. }
  1480. return ( fReturn );
  1481. } // ODBC_CONNECTION::GetInfo()
  1482. DWORD
  1483. ODBC_CONNECTION::DisplaySize(
  1484. SWORD coltype,
  1485. DWORD collen
  1486. )
  1487. {
  1488. DWORD cbSize = MAX_NONCHAR_DATA_LEN;
  1489. //
  1490. // Note that we always set the size to at least four bytes.
  1491. // This prevents any possible problems if the column to be
  1492. // bound is NULLable, which can cause a NULL to be written
  1493. // for the data during a fetch
  1494. //
  1495. switch ( coltype )
  1496. {
  1497. case SQL_CHAR:
  1498. case SQL_VARCHAR:
  1499. case SQL_LONGVARCHAR:
  1500. case SQL_BINARY:
  1501. case SQL_VARBINARY:
  1502. case SQL_LONGVARBINARY:
  1503. cbSize = max(collen + sizeof(CHAR), sizeof(PVOID));
  1504. break;
  1505. default:
  1506. break;
  1507. }
  1508. return ( cbSize);
  1509. } // ODBC_CONNECTION::DisplaySize()
  1510. # if DBG
  1511. VOID
  1512. ODBC_CONNECTION::Print(
  1513. VOID
  1514. ) const
  1515. {
  1516. DBGPRINTF( ( DBG_CONTEXT,
  1517. "Printing ODBC_CONNECTION ( %08x). fValid = %d\n"
  1518. " HENV = %08x. HDBC = %08x. ReturnCode =%d\n",
  1519. this, m_fValid,
  1520. m_henv, m_hdbc, m_rc));
  1521. return;
  1522. } // ODBC_CONNECTION::Print()
  1523. # endif // DBG