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.

1721 lines
41 KiB

  1. /*++
  2. Copyright (c) 1997 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. Functions Exported:
  10. ODBC_PARAMETER::CopyValue( IN LPCWSTR pwszValue);
  11. ODBC_PARAMETER::Bind( IN HSTMT hstmt);
  12. ODBC_STATEMENT::~ODBC_STATEMENT()
  13. ODBC_STATEMENT::PrepareStatement( IN LPCSTR pszStatement)
  14. ODBC_STATEMENT::PrepareStatement( IN LPCWSTR pwszStatement)
  15. ODBC_STATEMENT::BindParameter( IN PODBC_PARAMETER pOdbcParam)
  16. ODBC_STATEMENT::ExecuteStatement( VOID)
  17. ODBC_STATEMENT::ExecDirect( IN LPCSTR pwszSqlCommand, IN DWORD cch)
  18. ODBC_STATEMENT::ExecDirect( IN LPCWSTR pwszSqlCommand, IN DWORD cch)
  19. ODBC_STATEMENT::QueryColNames( OUT STR * * apstrCols,
  20. OUT DWORD * cCols,
  21. IN DWORD cchMaxFieldSize = 0 );
  22. ODBC_STATEMENT::QueryValuesAsStr( OUT STR * * apstrValues,
  23. OUT BOOL * pfLast );
  24. ODBC_CONNECTION::~ODBC_CONNECTION();
  25. ODBC_CONNECTION::Open();
  26. ODBC_CONNECTION::Close();
  27. ODBC_CONNECTION::GetLastErrorCode();
  28. ODBC_CONNECTION::AllocStatement();
  29. Revision History:
  30. --*/
  31. /************************************************************
  32. * Include Headers
  33. ************************************************************/
  34. # include "precomp.hxx"
  35. # include "odbcconn.hxx"
  36. LPSTR
  37. ConvertUnicodeToAnsi(
  38. IN LPCWSTR lpszUnicode
  39. );
  40. //
  41. // Constants for display widths
  42. //
  43. #define MAX_NUM_PRECISION 15
  44. //
  45. // Constant for all non string and non binary data. 40 is chosen to account
  46. // for things such as Oracle's numeric types, which can have up to 38 digits
  47. // of precision
  48. //
  49. #define MAX_NONCHAR_DATA_LEN 40
  50. //
  51. // If no default maximum field size is specified, then use this value
  52. // as the maximum
  53. //
  54. #define DEFAULT_MAX_FIELD_SIZE 8192
  55. /************************************************************
  56. * Local Functions
  57. ************************************************************/
  58. #if DBG
  59. static inline VOID
  60. CheckAndPrintErrorMessage( IN ODBC_CONNECTION * poc,
  61. IN RETCODE rc)
  62. {
  63. if ( !ODBC_CONNECTION::Success( rc)) {
  64. STR str;
  65. poc->GetLastErrorText( &str, NULL, rc );
  66. DBGPRINTF( ( DBG_CONTEXT,
  67. "ODBC Error Code( %d). Text: %s\n",
  68. rc,
  69. str.QueryStr() ));
  70. }
  71. return;
  72. } // CheckAndPrintErrorMessage()
  73. # else
  74. static VOID
  75. CheckAndPrintErrorMessage( IN ODBC_CONNECTION *,
  76. IN RETCODE)
  77. {}
  78. # endif // DBG
  79. # if DBG
  80. static inline VOID
  81. CheckAndPrintErrorMessage( IN ODBC_STATEMENT * pos,
  82. IN RETCODE rc)
  83. {
  84. if ( !ODBC_CONNECTION::Success( rc)) {
  85. STR str;
  86. pos->GetLastErrorText( &str );
  87. DBGPRINTF( ( DBG_CONTEXT,
  88. "ODBC Error Code( %d). Text: %s\n",
  89. rc,
  90. str.QueryStr() ));
  91. }
  92. return;
  93. } // CheckAndPrintErrorMessage()
  94. # else
  95. static VOID
  96. CheckAndPrintErrorMessage( IN ODBC_STATEMENT *,
  97. IN RETCODE)
  98. {}
  99. # endif // DBG
  100. /************************************************************
  101. * Member Functions of ODBC_PARAMETER
  102. ************************************************************/
  103. BOOL
  104. ODBC_PARAMETER::CopyValue( IN LPCWSTR pwszValue)
  105. /*++
  106. Description:
  107. This function copies the given Unicode string as the value into
  108. current parameter marker to be used for future insertion.
  109. Arguments:
  110. pwszValue pointer to null-terminated string containing Unicode value to
  111. be copied into the parameter marker.
  112. Returns:
  113. TRUE on success and FALSE if there is any error.
  114. Note:
  115. Since ODBC does not support Unicode directly right now, we convert
  116. string value to be ANSI before copying the value over.
  117. --*/
  118. {
  119. BOOL fReturn = FALSE;
  120. CHAR * pszValue = ConvertUnicodeToAnsi( pwszValue );
  121. //
  122. // If successful then Copy ASCII value to buffer in the parameter block.
  123. //
  124. if ( pszValue != NULL) {
  125. fReturn = this->CopyValue( pszValue);
  126. LocalFree( pszValue);
  127. }
  128. return ( fReturn);
  129. } // ODBC_PARAMETER::CopyValue()
  130. BOOL
  131. ODBC_PARAMETER::CopyValue( IN LPSYSTEMTIME lpst)
  132. /*++
  133. Description:
  134. This function copies the given system time into the ODBC timestamp
  135. structure for the current parameter marker to be used for
  136. future insertion.
  137. Arguments:
  138. lpSystemTime pointer to System Time structure containing current time.
  139. Returns:
  140. TRUE on success and FALSE if there is any error.
  141. --*/
  142. {
  143. TIMESTAMP_STRUCT * ptsOdbc;
  144. DBG_ASSERT( lpst != NULL);
  145. DBG_ASSERT( m_CType == SQL_C_TIMESTAMP);
  146. DBG_ASSERT( m_SqlType == SQL_TIMESTAMP);
  147. DBG_ASSERT( m_cbValueMax >= sizeof(TIMESTAMP_STRUCT));
  148. ptsOdbc = (TIMESTAMP_STRUCT * ) m_pValue;
  149. DBG_ASSERT( m_pValue != NULL);
  150. //
  151. // Copy the individual fields over properly
  152. // The types used in ODBC/Win32 are different
  153. // So do a type specific copy of the values.
  154. //
  155. ptsOdbc->year = (SWORD ) lpst->wYear;
  156. ptsOdbc->month = (UWORD ) lpst->wMonth;
  157. ptsOdbc->day = (UWORD ) lpst->wDay;
  158. ptsOdbc->hour = (UWORD ) lpst->wHour;
  159. ptsOdbc->minute = (UWORD ) lpst->wMinute;
  160. ptsOdbc->second = (UWORD ) lpst->wSecond;
  161. ptsOdbc->fraction = (UDWORD ) lpst->wMilliseconds;
  162. return ( TRUE);
  163. } // ODBC_PARAMETER::CopyValue()
  164. RETCODE
  165. ODBC_PARAMETER::Bind( IN HSTMT hStmt)
  166. /*++
  167. Description:
  168. This functions binds the data about the parameter marker 'this'
  169. ( this object) represents to the statement provided.
  170. Arguments:
  171. hStmt HANDLE for the statement to which this parameter
  172. is to be bound.
  173. Returns:
  174. RETCODE value returned by SQLBindParamater().
  175. --*/
  176. {
  177. RETCODE rc;
  178. DBG_ASSERT( hStmt != SQL_NULL_HSTMT);
  179. rc = SQLBindParameter( hStmt, // statement
  180. QueryParamNumber(),
  181. QueryParamType(),
  182. QueryCType(),
  183. QuerySqlType(),
  184. QueryPrecision(),
  185. QueryScale(),
  186. QueryValue(),
  187. QueryMaxCbValue(),
  188. &(QueryCbValueRef())
  189. );
  190. return ( rc);
  191. } // ODBC_STATEMENT::BindParameter()
  192. # if DBG
  193. VOID
  194. ODBC_PARAMETER::Print( VOID) const
  195. {
  196. DBGPRINTF( ( DBG_CONTEXT,
  197. "Printing ODBC_PARAMETER ( %08x).\n"
  198. " Num=%u; Type=%d; CType=%d; SqlType=%d; Prec=%u; Scale=%d;"
  199. " CbMax=%d; Cb=%d.\n",
  200. this,
  201. QueryParamNumber(),
  202. QueryParamType(),
  203. QueryCType(),
  204. QuerySqlType(),
  205. QueryPrecision(),
  206. QueryScale(),
  207. QueryMaxCbValue(),
  208. QueryCbValue()));
  209. switch ( QuerySqlType()) {
  210. case SQL_INTEGER:
  211. {
  212. DWORD dwValue = *(DWORD *) QueryValue();
  213. DBGPRINTF( ( DBG_CONTEXT, " Integer Value = %u\n", dwValue));
  214. break;
  215. }
  216. case SQL_CHAR:
  217. {
  218. LPCSTR pszValue = (LPCSTR ) QueryValue();
  219. DBGPRINTF( ( DBG_CONTEXT, " String Value( %08x) = %s\n",
  220. pszValue, pszValue));
  221. break;
  222. }
  223. default:
  224. {
  225. DBGPRINTF( ( DBG_CONTEXT, " Type=%d. Unknown value at %08x\n",
  226. QuerySqlType(), QueryValue()));
  227. break;
  228. }
  229. } // switch
  230. return;
  231. } // ODBC_PARAMETER::Print()
  232. # endif // DBG
  233. /************************************************************
  234. * ODBC_STATEMENT member functions
  235. ************************************************************/
  236. ODBC_STATEMENT::~ODBC_STATEMENT( VOID)
  237. {
  238. //
  239. // Free the statement handle
  240. //
  241. if ( m_hStmt != SQL_NULL_HSTMT) {
  242. m_rc = SQLFreeStmt( m_hStmt, SQL_DROP);
  243. m_hStmt = SQL_NULL_HSTMT;
  244. // Ignore the error code here.
  245. DBG_ASSERT( ODBC_CONNECTION::Success( m_rc));
  246. IF_DEBUG( API_ENTRY) {
  247. DBGPRINTF( ( DBG_CONTEXT,
  248. "SqlFreeStmt() return code %d.\n",
  249. m_rc));
  250. CheckAndPrintErrorMessage( this, m_rc);
  251. }
  252. }
  253. FreeColumnMemory();
  254. } // ODBC_STATEMENT::~ODBC_STATEMENT()
  255. BOOL
  256. ODBC_STATEMENT::ExecDirect(
  257. IN LPCSTR pszSqlCommand,
  258. IN DWORD cchSqlCommand)
  259. {
  260. BOOL fReturn;
  261. IF_DEBUG( API_ENTRY) {
  262. DBGPRINTF( ( DBG_CONTEXT,
  263. " Executing the SQL command (%d bytes) %s.\n",
  264. cchSqlCommand * sizeof( CHAR),
  265. pszSqlCommand));
  266. }
  267. //
  268. // SQLExecDirect only likes Unsigned chars !
  269. //
  270. m_rc = SQLExecDirect( m_hStmt, (UCHAR FAR *) pszSqlCommand, cchSqlCommand);
  271. fReturn = ODBC_CONNECTION::Success( m_rc);
  272. IF_DEBUG( API_ENTRY) {
  273. DBGPRINTF( ( DBG_CONTEXT,
  274. " SQLExecDirect() returns code %d\n",
  275. m_rc));
  276. CheckAndPrintErrorMessage( this, m_rc);
  277. }
  278. return ( fReturn);
  279. } // ODBC_STATEMENT::ExecDirect()
  280. #if 0
  281. BOOL
  282. ODBC_STATEMENT::ExecDirect(
  283. IN LPCWSTR pszSqlCommand,
  284. IN DWORD cchSqlCommand)
  285. {
  286. BOOL fReturn = FALSE;
  287. char * pszCommand;
  288. if ( ( pszCommand = ConvertUnicodeToAnsi( pszSqlCommand ))
  289. != NULL ) {
  290. fReturn = ExecDirect( pszCommand, strlen( pszCommand));
  291. LocalFree( pszCommand);
  292. }
  293. return ( fReturn);
  294. } // ODBC_STATEMENT::ExecDirect()
  295. #endif
  296. BOOL
  297. ODBC_STATEMENT::PrepareStatement(IN LPCSTR pszStatement)
  298. /*++
  299. This function prepares the SQL statement for future execution.
  300. Arguments:
  301. pszStatement pointer to null terminated string containing the
  302. statement.
  303. Returns:
  304. TRUE on success and FALSE if there is any failure.
  305. --*/
  306. {
  307. DBG_ASSERT( QueryErrorCode() == SQL_SUCCESS && pszStatement != NULL);
  308. m_rc = SQLPrepare( m_hStmt, (UCHAR FAR *) pszStatement, SQL_NTS);
  309. IF_DEBUG( API_ENTRY) {
  310. DBGPRINTF( ( DBG_CONTEXT,
  311. " SQLPrepare( %s) returns ErrorCode = %d.\n",
  312. pszStatement, m_rc));
  313. CheckAndPrintErrorMessage( this, m_rc);
  314. }
  315. return ( m_fPreparedStmt = ODBC_CONNECTION::Success( m_rc));
  316. } // ODBC_STATEMENT::PrepareStatment()
  317. #if 0
  318. BOOL
  319. ODBC_STATEMENT::PrepareStatement( IN LPCWSTR pwszCommand)
  320. /*++
  321. This function prepares an ODBC statement for execution.
  322. Since ODBC does not support UNICODE, we convert the statement into ANSI
  323. before calling the APIs.
  324. Arguments:
  325. pwszCommand pointer to null-terminated string containing the
  326. statement to be prepared.
  327. Returns:
  328. TRUE on success and FALSE if there is any failure.
  329. --*/
  330. {
  331. BOOL fReturn = FALSE;
  332. CHAR * pszCommand = NULL;
  333. DBG_ASSERT( pwszCommand != NULL);
  334. pszCommand = ConvertUnicodeToAnsi( pwszCommand );
  335. if ( pszCommand != NULL) {
  336. fReturn = PrepareStatement( pszCommand);
  337. LocalFree( pszCommand);
  338. } // pszCommand != NULL
  339. return ( fReturn);
  340. } // ODBC_STATEMENT::PrepareStatement()
  341. #endif
  342. BOOL
  343. ODBC_STATEMENT::BindParameter( IN PODBC_PARAMETER pOdbcParameter)
  344. {
  345. DBG_ASSERT( ODBC_CONNECTION::Success( m_rc) && pOdbcParameter != NULL);
  346. m_rc = pOdbcParameter->Bind( m_hStmt);
  347. IF_DEBUG( API_ENTRY) {
  348. CheckAndPrintErrorMessage( this, m_rc);
  349. }
  350. return ( ODBC_CONNECTION::Success( m_rc));
  351. } // ODBC_STATEMENT::BindParameter()
  352. BOOL
  353. ODBC_STATEMENT::ExecuteStatement( VOID)
  354. /*++
  355. This function executes a prepared ODBC statement. At the end of execution,
  356. the transaction is also committed to ensure that the record is automatically
  357. written to the database.
  358. Arguments:
  359. None
  360. Returns:
  361. TRUE on success and FALSE if there is any failure.
  362. --*/
  363. {
  364. DBG_ASSERT( m_fPreparedStmt != FALSE);
  365. if ( !ODBC_CONNECTION::Success( QueryErrorCode()) ) {
  366. DBGPRINTF(( DBG_CONTEXT,
  367. "!!WARNING!! - Attempting to use Invalid ODBC Connection!\n" ));
  368. }
  369. m_rc = SQLExecute( m_hStmt);
  370. IF_DEBUG( API_ENTRY) {
  371. CheckAndPrintErrorMessage( this, m_rc);
  372. }
  373. return ( ODBC_CONNECTION::Success( m_rc));
  374. } // ODBC_STATEMENT::ExecuteStatement()
  375. BOOL
  376. ODBC_STATEMENT::QueryRowCount(
  377. OUT SQLLEN *pcRows
  378. )
  379. /*++
  380. Calls SQLRowCount on the current result set.
  381. NOTE: Not all database implementations support this!!
  382. Arguments:
  383. pcRows - Receives count of rows
  384. Returns:
  385. TRUE on success and FALSE if there are any failures.
  386. Note:
  387. --*/
  388. {
  389. m_rc = SQLRowCount( m_hStmt,
  390. pcRows );
  391. return ( ODBC_CONNECTION::Success( m_rc));
  392. }
  393. BOOL
  394. ODBC_STATEMENT::QueryColNames(
  395. STR * * pastrCols,
  396. DWORD * cCols,
  397. DWORD cchMaxFieldSize,
  398. BOOL * pfHaveResultSet
  399. )
  400. /*++
  401. This method returns the list of column names from the result table
  402. Arguments:
  403. pastrCols - Receives an array of STRs containing the column names
  404. cCols - Count of columns returned (zero for no result set)
  405. cchMaxFieldSize - Maximum buffer size to allocate for any data fields,
  406. zero means use the default value.
  407. pfHaveResultSet - Set to TRUE if the current query was a SELECT and thus has
  408. rows that can be enumerated
  409. Returns:
  410. TRUE on success and FALSE if there are any failures.
  411. Note:
  412. --*/
  413. {
  414. SWORD nresultcols;
  415. SWORD i;
  416. CHAR achColName[64];
  417. SWORD cchColName;
  418. SWORD ColType;
  419. SQLULEN cchColLength;
  420. SWORD scale;
  421. SWORD nullable;
  422. *pastrCols = NULL;
  423. *cCols = 0;
  424. *pfHaveResultSet = TRUE;
  425. //
  426. // Return the old binding info if we already have it
  427. //
  428. if ( m_astrColNames )
  429. {
  430. *pastrCols = m_astrColNames;
  431. *cCols = m_cCols;
  432. return TRUE;
  433. }
  434. //
  435. // Provide a default maximum field size if none was specified
  436. //
  437. if ( !cchMaxFieldSize )
  438. cchMaxFieldSize = DEFAULT_MAX_FIELD_SIZE;
  439. //
  440. // See what kind of statement it was. If there are no result
  441. // columns, the statement is not a SELECT statement.
  442. //
  443. m_rc = SQLNumResultCols( m_hStmt,
  444. &nresultcols);
  445. if ( !ODBC_CONNECTION::Success( m_rc ))
  446. return FALSE;
  447. if ( nresultcols > 0 )
  448. {
  449. //
  450. // Allocate an array of strings for the column names and the column
  451. // values
  452. //
  453. m_cCols = nresultcols;
  454. *cCols = m_cCols;
  455. m_astrColNames = new STR[m_cCols];
  456. m_astrValues = new STR[m_cCols];
  457. m_acbValue = new SQLLEN[m_cCols];
  458. if (m_astrColNames == NULL ||
  459. m_astrValues == NULL ||
  460. m_acbValue == NULL)
  461. {
  462. return FALSE;
  463. }
  464. //
  465. // Otherwise, get the column names of the result set and use the
  466. // display_size() function to compute the length needed by each data
  467. // type. Next, bind the columns and specify all data will be
  468. // converted to char.
  469. //
  470. for (i = 0; i < m_cCols; i++)
  471. {
  472. m_rc = SQLDescribeCol( m_hStmt,
  473. i + 1,
  474. (UCHAR *) achColName,
  475. (SWORD)sizeof(achColName),
  476. &cchColName,
  477. &ColType,
  478. &cchColLength,
  479. &scale,
  480. &nullable);
  481. if ( !ODBC_CONNECTION::Success( m_rc ))
  482. return FALSE;
  483. //
  484. // Select the buffer size for the retrieved data for this column
  485. //
  486. cchColLength = ODBC_CONNECTION::DisplaySize( ColType,
  487. min( cchColLength, cchMaxFieldSize) );
  488. //
  489. // Copy the column name and set the column data size
  490. //
  491. if ( !m_astrColNames[i].Copy( achColName ) ||
  492. !m_astrValues[i].Resize( (DWORD)cchColLength + 1 ))
  493. {
  494. return FALSE;
  495. }
  496. m_rc = SQLBindCol( m_hStmt,
  497. i + 1,
  498. SQL_C_CHAR,
  499. m_astrValues[i].QueryPtr(),
  500. cchColLength,
  501. &m_acbValue[i] );
  502. if ( !ODBC_CONNECTION::Success( m_rc ))
  503. return FALSE;
  504. }
  505. *pastrCols = m_astrColNames;
  506. *cCols = m_cCols;
  507. }
  508. else
  509. {
  510. *pfHaveResultSet = FALSE;
  511. }
  512. return TRUE;
  513. }
  514. BOOL
  515. ODBC_STATEMENT::QueryValuesAsStr(
  516. STR * * pastrValues,
  517. BOOL * pfLast
  518. )
  519. /*++
  520. This method gets the data at the current position.
  521. Arguments:
  522. pastrValues - Receives a pointer to an array of strings that contains
  523. the alphanumeric representation of that field
  524. pfLast - Set to TRUE if there are no more values to retrieve
  525. Returns:
  526. TRUE on success and FALSE if there are any failures.
  527. Note:
  528. --*/
  529. {
  530. *pastrValues = NULL;
  531. //
  532. // Build the bindings if we haven't already
  533. //
  534. if ( !m_astrColNames )
  535. {
  536. STR * astrCols;
  537. DWORD cCols;
  538. BOOL fHaveResultSet;
  539. if ( !QueryColNames( &astrCols,
  540. &cCols,
  541. 0,
  542. &fHaveResultSet ))
  543. {
  544. return FALSE;
  545. }
  546. }
  547. //
  548. // If there are columns to enumerate, get them now
  549. //
  550. if ( m_astrColNames )
  551. {
  552. DWORD i;
  553. //
  554. // Zero terminate the columns as some drivers don't write anything
  555. // for NULL fields
  556. //
  557. for ( i = 0; i < m_cCols; i++ )
  558. {
  559. *((CHAR *) m_astrValues[i].QueryPtr()) = '\0';
  560. }
  561. //
  562. // Fill in the binding values
  563. //
  564. m_rc = SQLFetch( m_hStmt );
  565. if ( m_rc == SQL_NO_DATA_FOUND )
  566. {
  567. *pfLast = TRUE;
  568. }
  569. else
  570. {
  571. if ( !ODBC_CONNECTION::Success( m_rc ))
  572. return FALSE;
  573. *pfLast = FALSE;
  574. }
  575. *pastrValues = m_astrValues;
  576. }
  577. else
  578. {
  579. *pfLast = TRUE;
  580. }
  581. return TRUE;
  582. }
  583. BOOL
  584. ODBC_STATEMENT::MoreResults(
  585. BOOL * pfMoreResults
  586. )
  587. /*++
  588. Determines if there are any more results sets to return to the user
  589. pfMoreResults - Set to TRUE if there are more results in the result set
  590. --*/
  591. {
  592. *pfMoreResults = TRUE;
  593. m_rc = SQLMoreResults( m_hStmt );
  594. if ( m_rc == SQL_NO_DATA_FOUND )
  595. {
  596. *pfMoreResults = FALSE;
  597. return TRUE;
  598. }
  599. if ( !ODBC_CONNECTION::Success( m_rc ))
  600. return FALSE;
  601. return TRUE;
  602. }
  603. VOID
  604. ODBC_STATEMENT::FreeColumnMemory(
  605. VOID
  606. )
  607. /*++
  608. This method frees memory allocated by the QueryColNames and
  609. QueryValuesAsStr methods.
  610. --*/
  611. {
  612. if ( m_astrColNames ) delete [] m_astrColNames;
  613. if ( m_astrValues ) delete [] m_astrValues;
  614. if ( m_acbValue ) delete [] m_acbValue;
  615. m_astrColNames = NULL;
  616. m_astrValues = NULL;
  617. m_acbValue = NULL;
  618. }
  619. # if DBG
  620. VOID
  621. ODBC_STATEMENT::Print( VOID) const
  622. {
  623. DBGPRINTF( ( DBG_CONTEXT,
  624. " Printing ODBC_STATEMENT( %08x)."
  625. " HStmt = %08x. OdbcConn=%08x. RetCode = %d\n",
  626. m_hStmt, m_pOdbcConnection, m_rc));
  627. } // ODBC_STATEMENT::Print()
  628. # endif // DBG
  629. /**************************************************
  630. * Member Functions of class ODBC_CONNECTION
  631. **************************************************/
  632. ODBC_CONNECTION::~ODBC_CONNECTION( VOID)
  633. /*++
  634. This function closes the odbc connection ( if open) and cleans up.
  635. --*/
  636. {
  637. DBG_REQUIRE( Close());
  638. return;
  639. } // ODBC_CONNECTION::~ODBC_CONNECTION()
  640. BOOL
  641. ODBC_CONNECTION::Open(
  642. IN LPCSTR pszDataSource,
  643. IN LPCSTR pszUserName,
  644. IN LPCSTR pszPassword,
  645. IN BOOL fLogFailureEvent)
  646. /*++
  647. This function opens a new odbc connection to given data source
  648. using the user name and password supplied.
  649. Arguments:
  650. pszDataSource pointer to null-terminated string containing ODBC
  651. data source name
  652. pszUserName pointer to null-terminated string containing UserName
  653. pszPassword pointer to null-terminated string containing Password
  654. Returns:
  655. TRUE on success and FALSE if there is an error.
  656. --*/
  657. {
  658. BOOL fReturn = FALSE;
  659. DBG_ASSERT( pszDataSource != NULL &&
  660. pszUserName != NULL &&
  661. pszPassword != NULL);
  662. //
  663. // Allocate an ODBC environment
  664. //
  665. m_rc = SQLAllocEnv( &m_henv);
  666. fReturn = Success( m_rc);
  667. IF_DEBUG( API_ENTRY) {
  668. DBGPRINTF( ( DBG_CONTEXT,
  669. "SQLAllocEnv() returned ErrorCode %d. henv = %08x\n",
  670. m_rc, m_henv));
  671. CheckAndPrintErrorMessage( this, m_rc);
  672. }
  673. if ( fReturn) {
  674. //
  675. // Establish memory for connection handle within the environment
  676. //
  677. m_rc = SQLAllocConnect( m_henv, &m_hdbc);
  678. fReturn = Success( m_rc);
  679. IF_DEBUG( API_ENTRY) {
  680. DBGPRINTF( ( DBG_CONTEXT,
  681. "SQLAllocConnect() returns code %d. hdbc = %08x\n",
  682. m_rc, m_hdbc));
  683. CheckAndPrintErrorMessage( this, m_rc);
  684. }
  685. }
  686. if ( fReturn) {
  687. //
  688. // Use Following call to just printout the dynamic values for ODBC
  689. //
  690. // AuxOdbcFunctions( m_henv, m_hdbc);
  691. #if 0
  692. {
  693. STR str;
  694. STR strOut;
  695. SWORD swStrOut;
  696. if ( !str.Append( pszDataSource ) ||
  697. !str.Append( ";UID=" ) ||
  698. !str.Append( pszUserName ) ||
  699. !str.Append( ";PWD=" ) ||
  700. !str.Append( pszPassword ) ||
  701. !str.Append( ";APP=Internet Services") ||
  702. !strOut.Resize( 255 ))
  703. {
  704. return FALSE;
  705. }
  706. m_rc = pSQLDriverConnect( m_hdbc,
  707. NULL,
  708. (UCHAR *) str.QueryStr(),
  709. SQL_NTS,
  710. (UCHAR *) strOut.QueryStr(),
  711. strOut.QuerySize(),
  712. &swStrOut,
  713. SQL_DRIVER_NOPROMPT );
  714. }
  715. #else
  716. {
  717. m_rc = SQLConnect( m_hdbc,
  718. (UCHAR FAR *) pszDataSource, SQL_NTS,
  719. (UCHAR FAR *) pszUserName, SQL_NTS,
  720. (UCHAR FAR *) pszPassword, SQL_NTS);
  721. }
  722. #endif
  723. fReturn = Success( m_rc);
  724. if ( !fReturn ) {
  725. //
  726. // Log it
  727. //
  728. if ( (g_eventLog != NULL ) && fLogFailureEvent)
  729. {
  730. STR str;
  731. const CHAR* tmpString[2];
  732. GetLastErrorText( &str, NULL, m_rc );
  733. tmpString[0] = pszDataSource;
  734. tmpString[1] = str.QueryStr();
  735. g_eventLog->LogEvent(
  736. LOG_EVENT_ODBC_CONNECT_ERROR,
  737. 2,
  738. tmpString,
  739. m_rc);
  740. }
  741. }
  742. IF_DEBUG( API_ENTRY) {
  743. DBGPRINTF( ( DBG_CONTEXT,
  744. "SQLConnect( %s, %s, %s) returns code %d.\n",
  745. pszDataSource,
  746. pszUserName,
  747. pszPassword,
  748. m_rc));
  749. CheckAndPrintErrorMessage( this, m_rc);
  750. }
  751. }
  752. m_fValid = fReturn;
  753. if ( !fReturn) {
  754. SetLastError( ERROR_GEN_FAILURE );
  755. }
  756. return ( fReturn);
  757. } // ODBC_CONNECTION::Open()
  758. #if 0
  759. BOOL
  760. ODBC_CONNECTION::Open(
  761. IN LPCWSTR pwszDataSource,
  762. IN LPCWSTR pwszUserName,
  763. IN LPCWSTR pwszPassword)
  764. /*++
  765. This function opens a new odbc connection to given data source
  766. using the user name and password supplied.
  767. Arguments:
  768. pwszDataSource pointer to null-terminated string containing ODBC
  769. data source name
  770. pwszUserName pointer to null-terminated string containing UserName
  771. pwszPassword pointer to null-terminated string containing Password
  772. Returns:
  773. TRUE on success and FALSE if there is an error.
  774. Note:
  775. Poor me. ODBC Does not take UNICODE strings :(. 2/15/95
  776. So we will explicitly convert parameters to ANSI on stack.
  777. --*/
  778. {
  779. BOOL fReturn;
  780. DWORD dwError = NO_ERROR;
  781. CHAR * pszDataSource;
  782. CHAR * pszUserName;
  783. CHAR * pszPassword;
  784. //
  785. // Convert all parameters from UNICODE to ANSI
  786. //
  787. pszDataSource = ConvertUnicodeToAnsi( pwszDataSource );
  788. pszUserName = ConvertUnicodeToAnsi( pwszUserName );
  789. pszPassword = ConvertUnicodeToAnsi( pwszPassword );
  790. //
  791. // Make an ANSI open call.
  792. //
  793. fReturn = Open( pszDataSource, pszUserName, pszPassword);
  794. if ( !fReturn) {
  795. dwError = GetLastError();
  796. }
  797. //
  798. // Freeup the space allocated.
  799. //
  800. if ( pszDataSource != NULL) {
  801. LocalFree( pszDataSource);
  802. pszDataSource = NULL;
  803. }
  804. if ( pszUserName != NULL) {
  805. LocalFree( pszUserName);
  806. pszUserName = NULL;
  807. }
  808. if ( pszPassword != NULL) {
  809. //
  810. // Zero the password for security reasons.
  811. //
  812. SecureZeroMemory( pszPassword, 0, strlen( pszPassword));
  813. LocalFree( pszPassword);
  814. pszPassword = NULL;
  815. }
  816. if ( !fReturn) {
  817. SetLastError( dwError);
  818. }
  819. return ( fReturn);
  820. } // ODBC_CONNECTION::Open()
  821. #endif
  822. BOOL
  823. ODBC_CONNECTION::Close( VOID)
  824. /*++
  825. This function closes the connection established with the ODBC
  826. and frees up and dynamic memory used.
  827. Returns:
  828. TRUE on success and FALSE if there are any failures.
  829. Note:
  830. Intermediate failures are ignored. Normally they should not occur.
  831. --*/
  832. {
  833. BOOL fReturn = TRUE;
  834. //
  835. // Disconnect and free the connection.
  836. //
  837. if ( m_hdbc != SQL_NULL_HDBC) {
  838. m_rc = SQLDisconnect( m_hdbc );
  839. //
  840. // Disconnect is allowed to fail w/o being fatal so don't set
  841. // fReturn
  842. //
  843. IF_DEBUG( API_ENTRY) {
  844. DBGPRINTF( ( DBG_CONTEXT,
  845. "Warning: SQLDisconnect() returns code %d.\n",
  846. m_rc));
  847. CheckAndPrintErrorMessage( this, m_rc);
  848. }
  849. m_rc = SQLFreeConnect( m_hdbc);
  850. m_hdbc = SQL_NULL_HDBC;
  851. fReturn = fReturn && Success( m_rc);
  852. IF_DEBUG( API_ENTRY) {
  853. DBGPRINTF( ( DBG_CONTEXT,
  854. "SQLFreeConnect() returns code %d.\n",
  855. m_rc));
  856. CheckAndPrintErrorMessage( this, m_rc);
  857. }
  858. }
  859. //
  860. // Free the ODBC environment handle.
  861. //
  862. if ( m_henv != SQL_NULL_HENV) {
  863. m_rc = SQLFreeEnv( m_henv);
  864. m_henv = SQL_NULL_HENV;
  865. fReturn = fReturn && Success( m_rc);
  866. IF_DEBUG( API_ENTRY) {
  867. DBGPRINTF( ( DBG_CONTEXT,
  868. "SQLFreeEnv() returns code %d.\n",
  869. m_rc));
  870. CheckAndPrintErrorMessage( this, m_rc);
  871. }
  872. }
  873. return ( fReturn);
  874. } // ODBC_CONNECTION::Close()
  875. PODBC_STATEMENT
  876. ODBC_CONNECTION::AllocStatement( VOID)
  877. /*++
  878. Description:
  879. This function allocates a new ODBC statement object and also calls
  880. SQLAllocStatement to create the state required for establishing the
  881. statement in the ODBC Manager.
  882. Arguments:
  883. None
  884. Returns:
  885. TRUE on success and FALSE if there is any failure.
  886. --*/
  887. {
  888. PODBC_STATEMENT pOdbcStmt = NULL;
  889. HSTMT hstmt = SQL_NULL_HSTMT;
  890. DBG_ASSERT( Success( m_rc));
  891. //
  892. // Allocate a statement handle and associate it with the connection.
  893. //
  894. m_rc = SQLAllocStmt( m_hdbc, &hstmt);
  895. IF_DEBUG( API_ENTRY) {
  896. DBGPRINTF( ( DBG_CONTEXT,
  897. "SqlAllocStmt() returns code %d."
  898. " New Hstmt is : %08x\n",
  899. m_rc, hstmt));
  900. CheckAndPrintErrorMessage( this, m_rc);
  901. }
  902. if ( ODBC_CONNECTION::Success( m_rc)) {
  903. pOdbcStmt = new ODBC_STATEMENT( this, hstmt);
  904. }
  905. return ( pOdbcStmt);
  906. } // ODBC_CONNECTION::AllocStatement()
  907. BOOL
  908. ODBC_CONNECTION::SetConnectOption(
  909. IN UWORD Option,
  910. IN SQLULEN Param
  911. )
  912. /*++
  913. Sets various options on this connection
  914. Arguments:
  915. Option - Option to set
  916. Param - Option value (32 bit dword or pointer to null terminated string)
  917. Returns:
  918. TRUE on success and FALSE if there are any failures. Failures are
  919. considered to be soft errors as the problem may be the driver doesn't
  920. support the option etc.
  921. Note:
  922. --*/
  923. {
  924. BOOL fReturn = TRUE;
  925. RETCODE rc;
  926. if ( m_hdbc != SQL_NULL_HDBC)
  927. {
  928. rc = SQLSetConnectOption( m_hdbc, Option, Param );
  929. fReturn = Success( rc);
  930. IF_DEBUG( API_ENTRY) {
  931. DBGPRINTF( ( DBG_CONTEXT,
  932. "SQLSetConnectOption( %d, %d ) returns code %d.\n",
  933. Option,
  934. Param,
  935. rc));
  936. CheckAndPrintErrorMessage( this, rc);
  937. }
  938. }
  939. else
  940. {
  941. DBGPRINTF( ( DBG_CONTEXT,
  942. "[SetConnectOption] Warning: Setting option on closed connection\n" ));
  943. }
  944. return fReturn;
  945. }
  946. BOOL
  947. ODBC_CONNECTION::GetLastErrorText(
  948. OUT STR * pstrError,
  949. IN HSTMT hstmt,
  950. IN RETCODE rc
  951. ) const
  952. /*++
  953. This method returns the textual representation of the last ODBC or windows
  954. error that occurred. Even though the ODBC methods return FALSE on failure,
  955. if it was an ODBC call that failed, then GetLastError won't return the
  956. needed error code. Clients of this class should call this method to get
  957. a descriptive text string of the failure.
  958. Returns:
  959. TRUE on success and FALSE if there are any failures.
  960. Note:
  961. If this function returns FALSE, then a client should call GetLastError
  962. for the error code.
  963. --*/
  964. {
  965. BOOL fReturn = TRUE;
  966. if ( ODBC_CONNECTION::Success( rc)) {
  967. fReturn = pstrError->LoadString( GetLastError());
  968. } else {
  969. CHAR rgchMsg[ SQL_MAX_MESSAGE_LENGTH + 10];
  970. CHAR achState[30];
  971. CHAR rgchFullMsg[ sizeof(rgchMsg) + sizeof(achState) + 60];
  972. SWORD cbMsg;
  973. LONG lError;
  974. //
  975. // If we're formatting as HTML, we bullet list the items
  976. //
  977. if ( !pstrError->Copy( (CHAR *) NULL ) )
  978. {
  979. return FALSE;
  980. }
  981. //
  982. // Loop to pick up all of the errors
  983. //
  984. do {
  985. cbMsg = SQL_MAX_MESSAGE_LENGTH;
  986. rc = SQLError( m_henv,
  987. m_hdbc,
  988. hstmt,
  989. (UCHAR *) achState,
  990. &lError,
  991. (UCHAR *) rgchMsg,
  992. cbMsg,
  993. &cbMsg );
  994. if ( ODBC_CONNECTION::Success( rc)) {
  995. wsprintf( rgchFullMsg,
  996. "[State=%s][Error=%d]%s\n",
  997. achState, lError, rgchMsg);
  998. if ( !pstrError->Append( rgchFullMsg )) {
  999. fReturn = FALSE;
  1000. break;
  1001. }
  1002. } else {
  1003. //
  1004. // This is indicates there are no more error strings
  1005. // to pick up so we should get out
  1006. //
  1007. if ( rc == SQL_NO_DATA_FOUND ) {
  1008. //
  1009. // Append the end of unorder list marker
  1010. //
  1011. rc = SQL_SUCCESS;
  1012. break;
  1013. }
  1014. }
  1015. } while ( ODBC_CONNECTION::Success( rc) );
  1016. if ( !ODBC_CONNECTION::Success( rc) )
  1017. {
  1018. DBGPRINTF( ( DBG_CONTEXT,
  1019. "[GetLastErrorText] SqlError() returned error %d.\n",
  1020. rc));
  1021. SetLastError( ERROR_GEN_FAILURE );
  1022. fReturn = FALSE;
  1023. }
  1024. }
  1025. return ( fReturn);
  1026. } // ODBC_CONNECTION::GetLastErrorText()
  1027. BOOL
  1028. ODBC_CONNECTION::GetLastErrorTextAsHtml(
  1029. OUT STR * pstrError,
  1030. IN HSTMT hstmt,
  1031. IN RETCODE rc
  1032. ) const
  1033. /*++
  1034. This method returns the textual representation of the last ODBC or windows
  1035. error that occurred. Even though the ODBC methods return FALSE on failure,
  1036. if it was an ODBC call that failed, then GetLastError won't return the
  1037. needed error code. Clients of this class should call this method to get
  1038. a descriptive text string of the failure.
  1039. Returns:
  1040. TRUE on success and FALSE if there are any failures.
  1041. Note:
  1042. If this function returns FALSE, then a client should call GetLastError
  1043. for the error code.
  1044. --*/
  1045. {
  1046. BOOL fReturn = TRUE;
  1047. if ( ODBC_CONNECTION::Success( rc)) {
  1048. fReturn = pstrError->LoadString( GetLastError());
  1049. } else {
  1050. CHAR rgchMsg[ SQL_MAX_MESSAGE_LENGTH + 10];
  1051. CHAR achState[30];
  1052. CHAR rgchFullMsg[ sizeof(rgchMsg) + sizeof(achState) + 60];
  1053. SWORD cbMsg;
  1054. LONG lError;
  1055. //
  1056. // If we're formatting as HTML, we bullet list the items
  1057. //
  1058. if ( !pstrError->Copy( "<UL>" ))
  1059. {
  1060. return FALSE;
  1061. }
  1062. //
  1063. // Loop to pick up all of the errors
  1064. //
  1065. do {
  1066. cbMsg = SQL_MAX_MESSAGE_LENGTH;
  1067. rc = SQLError( m_henv,
  1068. m_hdbc,
  1069. hstmt,
  1070. (UCHAR *) achState,
  1071. &lError,
  1072. (UCHAR *) rgchMsg,
  1073. cbMsg,
  1074. &cbMsg );
  1075. if ( ODBC_CONNECTION::Success( rc)) {
  1076. wsprintf( rgchFullMsg,
  1077. "<LI>[State=%s][Error=%d]%s\n",
  1078. achState, lError, rgchMsg);
  1079. if ( !pstrError->Append( rgchFullMsg )) {
  1080. fReturn = FALSE;
  1081. break;
  1082. }
  1083. } else {
  1084. //
  1085. // This is indicates there are no more error strings
  1086. // to pick up so we should get out
  1087. //
  1088. if ( rc == SQL_NO_DATA_FOUND ) {
  1089. //
  1090. // Append the end of unorder list marker
  1091. //
  1092. if ( !pstrError->Append( "</UL>" )) {
  1093. return FALSE;
  1094. }
  1095. rc = SQL_SUCCESS;
  1096. break;
  1097. }
  1098. }
  1099. } while ( ODBC_CONNECTION::Success( rc) );
  1100. if ( !ODBC_CONNECTION::Success( rc) )
  1101. {
  1102. DBGPRINTF( ( DBG_CONTEXT,
  1103. "[GetLastErrorText] SqlError() returned error %d.\n",
  1104. rc));
  1105. SetLastError( ERROR_GEN_FAILURE );
  1106. fReturn = FALSE;
  1107. }
  1108. }
  1109. return ( fReturn);
  1110. } // ODBC_CONNECTION::GetLastErrorTextAsHtml()
  1111. BOOL
  1112. ODBC_CONNECTION::GetInfo(IN DWORD fInfoType,
  1113. IN PVOID rgbInfoValue,
  1114. IN DWORD cbInfoValueMax,
  1115. IN OUT DWORD * pcbInfoValue)
  1116. /*++
  1117. This function obtains the value of the fInfoType for a specific
  1118. ODBC Connection. It mimicks the SQLGetInfo() and uses it to obtain
  1119. this value. On successful return the pointer rgbInfoValue contains
  1120. the requested value and pcbInfoValue contains the size in bytes of
  1121. data.
  1122. Arguments:
  1123. fInfoType - flag containing the Information Type (name) to be fetched.
  1124. rgbInfoValue - pointer to buffer which will contain the return data.
  1125. cbInfoValue - size of rgbInfoValue in bytes.
  1126. pcbInfoValue - pointer to location that will contain the size of
  1127. information stored in rgbInfoValue, on successful return.
  1128. If buffer is insufficient, this location will contain the
  1129. required number of bytes.
  1130. Returns:
  1131. TRUE on success and FALSE if there is any failure.
  1132. --*/
  1133. {
  1134. BOOL fReturn = FALSE;
  1135. if ( m_hdbc != SQL_NULL_HDBC) {
  1136. RETCODE rc;
  1137. rc = SQLGetInfo( m_hdbc, (UWORD ) fInfoType,
  1138. (PTR) rgbInfoValue,
  1139. (SWORD) cbInfoValueMax,
  1140. (SWORD FAR *) pcbInfoValue);
  1141. fReturn = Success( rc);
  1142. IF_DEBUG( API_ENTRY) {
  1143. DBGPRINTF( ( DBG_CONTEXT,
  1144. "SQLGetInfo( %08x, %d, %08x, %d, %08x) returns %d.\n",
  1145. m_hdbc, fInfoType, rgbInfoValue, cbInfoValueMax,
  1146. pcbInfoValue, rc));
  1147. CheckAndPrintErrorMessage( this, rc);
  1148. }
  1149. } else {
  1150. DBGPRINTF( ( DBG_CONTEXT,
  1151. "[SQLGetInfo] Invalid Connection to ODBC\n"));
  1152. }
  1153. return (fReturn);
  1154. } // ODBC_CONNECTION::GetInfo()
  1155. SQLULEN
  1156. ODBC_CONNECTION::DisplaySize(
  1157. SWORD coltype,
  1158. SQLULEN collen
  1159. )
  1160. {
  1161. SQLULEN cbSize = MAX_NONCHAR_DATA_LEN;
  1162. //
  1163. // Note that we always set the size to at least four bytes. This prevents
  1164. // any possible problems if the column to be bound is NULLable, which can
  1165. // cause a NULL to be written for the data during a fetch
  1166. //
  1167. switch (coltype)
  1168. {
  1169. case SQL_CHAR:
  1170. case SQL_VARCHAR:
  1171. case SQL_LONGVARCHAR:
  1172. case SQL_BINARY:
  1173. case SQL_VARBINARY:
  1174. case SQL_LONGVARBINARY:
  1175. cbSize = max(collen + sizeof(CHAR), sizeof(PVOID));
  1176. break;
  1177. default:
  1178. break;
  1179. }
  1180. return ( cbSize);
  1181. } // ODBC_CONNECTION::DisplaySize()
  1182. # if DBG
  1183. VOID
  1184. ODBC_CONNECTION::Print( VOID) const
  1185. {
  1186. DBGPRINTF( ( DBG_CONTEXT,
  1187. "Printing ODBC_CONNECTION ( %08x). fValid = %d\n"
  1188. " HENV = %08x. HDBC = %08x. ReturnCode =%d\n",
  1189. this, m_fValid,
  1190. m_henv, m_hdbc, m_rc));
  1191. return;
  1192. } // ODBC_CONNECTION::Print()
  1193. # endif // DBG
  1194. LPSTR
  1195. ConvertUnicodeToAnsi(
  1196. IN LPCWSTR lpszUnicode
  1197. )
  1198. /*++
  1199. Description:
  1200. Converts given null-terminated string into ANSI in the buffer supplied.
  1201. Arguments:
  1202. lpszUnicode null-terminated string in Unicode
  1203. Returns:
  1204. pointer to converted ANSI string. NULL on errors.
  1205. --*/
  1206. {
  1207. DWORD cchLen;
  1208. DWORD nBytes;
  1209. LPSTR lpszAlloc = NULL;
  1210. if ( lpszUnicode == NULL) {
  1211. return (NULL);
  1212. }
  1213. //
  1214. // multiply by 2 to accomodate DBCS
  1215. //
  1216. cchLen = (DWORD)wcslen( lpszUnicode);
  1217. nBytes = (cchLen+1) * sizeof(CHAR) * 2;
  1218. lpszAlloc = (LPSTR ) LocalAlloc( 0, nBytes );
  1219. if ( lpszAlloc != NULL) {
  1220. cchLen = WideCharToMultiByte( CP_ACP,
  1221. WC_COMPOSITECHECK,
  1222. lpszUnicode,
  1223. -1,
  1224. lpszAlloc,
  1225. nBytes,
  1226. NULL, // lpszDefaultChar
  1227. NULL // lpfDefaultUsed
  1228. );
  1229. DBG_ASSERT(cchLen == (strlen(lpszAlloc)+1) );
  1230. if ( cchLen == 0 ) {
  1231. //
  1232. // There was a failure. Free up buffer if need be.
  1233. //
  1234. DBGPRINTF((DBG_CONTEXT,"WideCharToMultiByte failed with %d\n",
  1235. GetLastError()));
  1236. LocalFree( lpszAlloc);
  1237. lpszAlloc = NULL;
  1238. } else {
  1239. DBG_ASSERT( cchLen <= nBytes );
  1240. DBG_ASSERT(lpszAlloc[cchLen-1] == '\0');
  1241. lpszAlloc[cchLen-1] = '\0';
  1242. }
  1243. }
  1244. return ( lpszAlloc);
  1245. } // ConvertUnicodeToAnsi