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.

621 lines
16 KiB

  1. #include <tchar.h>
  2. #include <stddef.h>
  3. #include <mbctype.h>
  4. #define DBINITCONSTANTS
  5. #include <sqloledb.h>
  6. #undef DBINITCONSTANTS
  7. #include <oledberr.h>
  8. #include "simpledb.h"
  9. //
  10. // CSimpleDatabase
  11. //
  12. CSimpleDatabase::CSimpleDatabase(
  13. void
  14. ) : m_bCreated(false), m_bSession(false)
  15. {
  16. HRESULT hr;
  17. CoInitializeEx( NULL, COINIT_APARTMENTTHREADED );
  18. hr = CoCreateInstance( CLSID_MSDAINITIALIZE,
  19. NULL,
  20. CLSCTX_INPROC_SERVER,
  21. IID_IDataInitialize,
  22. (PVOID *)&m_pDataInit );
  23. if ( !FAILED(hr) )
  24. {
  25. m_bCreated = TRUE;
  26. }
  27. }
  28. CSimpleDatabase::~CSimpleDatabase(
  29. void
  30. )
  31. {
  32. if ( NULL != m_pDataInit )
  33. {
  34. m_pDataInit->Release();
  35. }
  36. if ( NULL != m_pSession )
  37. {
  38. m_pSession->Release();
  39. }
  40. CoUninitialize();
  41. }
  42. HRESULT
  43. CSimpleDatabase::Connect(
  44. LPCTSTR szServer,
  45. LPCTSTR szDatabase,
  46. LPCTSTR szUserName,
  47. LPCTSTR szPassword
  48. )
  49. {
  50. HRESULT hr;
  51. DBPROP props[4];
  52. DBPROPSET rgProps[1];
  53. DWORD dwNumProps = 0;
  54. IDBInitialize *pDBInitialize;
  55. IDBProperties *pDBProps;
  56. #ifndef UNICODE
  57. wchar_t *wszTemp;
  58. size_t lenTemp;
  59. #endif
  60. if ( !m_bCreated )
  61. {
  62. return E_HANDLE;
  63. }
  64. // If this is not the first connection, reset
  65. if ( m_bSession )
  66. {
  67. m_pSession->Release();
  68. m_pSession = NULL;
  69. m_bSession = FALSE;
  70. }
  71. //
  72. // Set the connection properties
  73. //
  74. for ( short i = 0; i < 4; i++ )
  75. {
  76. VariantInit( &props[i].vValue );
  77. }
  78. // Server
  79. props[0].dwPropertyID = DBPROP_INIT_DATASOURCE;
  80. props[0].vValue.vt = VT_BSTR;
  81. #ifndef UNICODE
  82. lenTemp = strlen(szServer) + 1;
  83. wszTemp = new wchar_t[lenTemp];
  84. if ( NULL == wszTemp )
  85. {
  86. return E_OUTOFMEMORY;
  87. }
  88. if ( 0 == MultiByteToWideChar( _getmbcp(),
  89. 0L,
  90. szServer,
  91. lenTemp,
  92. wszTemp,
  93. lenTemp ) )
  94. {
  95. return HRESULT_FROM_WIN32( GetLastError() );
  96. }
  97. props[0].vValue.bstrVal = SysAllocString( wszTemp );
  98. delete [] wszTemp;
  99. #else
  100. props[0].vValue.bstrVal = SysAllocString( szServer );
  101. #endif
  102. props[0].dwOptions = DBPROPOPTIONS_REQUIRED;
  103. props[0].colid = DB_NULLID;
  104. dwNumProps++;
  105. if ( szDatabase )
  106. {
  107. // Default Database
  108. props[1].dwPropertyID = DBPROP_INIT_CATALOG;
  109. props[1].vValue.vt = VT_BSTR;
  110. #ifndef UNICODE
  111. lenTemp = strlen(szDatabase) + 1;
  112. wszTemp = new wchar_t[lenTemp];
  113. if ( NULL == wszTemp )
  114. {
  115. return E_OUTOFMEMORY;
  116. }
  117. if ( 0 == MultiByteToWideChar( _getmbcp(),
  118. 0L,
  119. szDatabase,
  120. lenTemp,
  121. wszTemp,
  122. lenTemp ) )
  123. {
  124. return HRESULT_FROM_WIN32( GetLastError() );
  125. }
  126. props[1].vValue.bstrVal = SysAllocString( wszTemp );
  127. delete [] wszTemp;
  128. #else
  129. props[1].vValue.bstrVal = SysAllocString( szDatabase );
  130. #endif
  131. props[1].dwOptions = DBPROPOPTIONS_REQUIRED;
  132. props[1].colid = DB_NULLID;
  133. dwNumProps++;
  134. }
  135. if ( szUserName )
  136. {
  137. // Username
  138. props[2].dwPropertyID = DBPROP_AUTH_USERID;
  139. props[2].vValue.vt = VT_BSTR;
  140. #ifndef UNICODE
  141. lenTemp = strlen(szUserName) + 1;
  142. wszTemp = new wchar_t[lenTemp];
  143. if ( NULL == wszTemp )
  144. {
  145. return E_OUTOFMEMORY;
  146. }
  147. if ( 0 == MultiByteToWideChar( _getmbcp(),
  148. 0L,
  149. szUserName,
  150. lenTemp,
  151. wszTemp,
  152. lenTemp ) )
  153. {
  154. return HRESULT_FROM_WIN32( GetLastError() );
  155. }
  156. props[2].vValue.bstrVal = SysAllocString( wszTemp );
  157. delete [] wszTemp;
  158. #else
  159. props[2].vValue.bstrVal = SysAllocString( szUserName );
  160. #endif
  161. props[2].dwOptions = DBPROPOPTIONS_REQUIRED;
  162. props[2].colid = DB_NULLID;
  163. dwNumProps++;
  164. // Password
  165. props[3].dwPropertyID = DBPROP_AUTH_PASSWORD;
  166. props[3].vValue.vt = VT_BSTR;
  167. #ifndef UNICODE
  168. lenTemp = strlen(szPassword) + 1;
  169. wszTemp = new wchar_t[lenTemp];
  170. if ( NULL == wszTemp )
  171. {
  172. return E_OUTOFMEMORY;
  173. }
  174. if ( 0 == MultiByteToWideChar( _getmbcp(),
  175. 0L,
  176. szPassword,
  177. lenTemp,
  178. wszTemp,
  179. lenTemp ) )
  180. {
  181. return HRESULT_FROM_WIN32( GetLastError() );
  182. }
  183. props[3].vValue.bstrVal = SysAllocString( wszTemp );
  184. delete [] wszTemp;
  185. #else
  186. props[3].vValue.bstrVal = SysAllocString( szPassword );
  187. #endif
  188. props[3].dwOptions = DBPROPOPTIONS_REQUIRED;
  189. props[3].colid = DB_NULLID;
  190. dwNumProps++;
  191. }
  192. else
  193. {
  194. // Use Windows authentication
  195. props[3].dwPropertyID = DBPROP_AUTH_INTEGRATED;
  196. props[3].vValue.vt = VT_BSTR;
  197. props[3].vValue.bstrVal = NULL;
  198. props[3].dwOptions = DBPROPOPTIONS_REQUIRED;
  199. props[3].colid = DB_NULLID;
  200. dwNumProps++;
  201. }
  202. hr = m_pDataInit->CreateDBInstance( CLSID_SQLOLEDB,
  203. NULL,
  204. CLSCTX_INPROC_SERVER,
  205. NULL,
  206. IID_IDBInitialize,
  207. (IUnknown **)&pDBInitialize );
  208. if ( FAILED(hr) ) { return hr; }
  209. hr = pDBInitialize->QueryInterface( IID_IDBProperties, (PVOID *)&pDBProps );
  210. if ( FAILED(hr) ) { return hr; }
  211. rgProps[0].guidPropertySet = DBPROPSET_DBINIT;
  212. rgProps[0].cProperties = dwNumProps;
  213. rgProps[0].rgProperties = props;
  214. hr = pDBProps->SetProperties(1, rgProps);
  215. pDBProps->Release();
  216. if ( FAILED(hr) ) { return hr; }
  217. hr = pDBInitialize->Initialize();
  218. if ( FAILED(hr) )
  219. {
  220. pDBInitialize->Release();
  221. return hr;
  222. }
  223. hr = EstablishSession( pDBInitialize );
  224. pDBInitialize->Release();
  225. return hr;
  226. }
  227. HRESULT
  228. CSimpleDatabase::EstablishSession(
  229. IDBInitialize *pDBInitialize
  230. )
  231. {
  232. HRESULT hr;
  233. IDBCreateSession *pCreateSession = NULL;
  234. hr = pDBInitialize->QueryInterface( IID_IDBCreateSession,
  235. (PVOID *)&pCreateSession );
  236. if ( FAILED(hr) ) { return hr; }
  237. hr = pCreateSession->CreateSession( NULL, IID_IDBCreateCommand, (IUnknown **)&m_pSession );
  238. if ( FAILED(hr) )
  239. {
  240. pCreateSession->Release();
  241. return hr;
  242. }
  243. pCreateSession->Release();
  244. m_bSession = FALSE;
  245. return S_OK;
  246. }
  247. HRESULT
  248. CSimpleDatabase::Execute(
  249. LPCTSTR szCommand,
  250. CSimpleDBResults **ppOutResults
  251. )
  252. {
  253. HRESULT hr;
  254. ICommandText *pCommandText = NULL;
  255. IMultipleResults *pResults = NULL;
  256. DBROWCOUNT cRowsAffected;
  257. if ( NULL != ppOutResults )
  258. {
  259. *ppOutResults = NULL;
  260. }
  261. hr = m_pSession->CreateCommand( NULL, IID_ICommandText, (IUnknown **)&pCommandText );
  262. if ( FAILED(hr) ) { return hr; }
  263. #ifndef UNICODE
  264. size_t lenTemp = strlen(szCommand) + 1;
  265. wchar_t *wszTemp = new wchar_t[lenTemp];
  266. if ( NULL == wszTemp )
  267. {
  268. return E_OUTOFMEMORY;
  269. }
  270. if ( 0 == MultiByteToWideChar( _getmbcp(),
  271. 0L,
  272. szCommand,
  273. lenTemp,
  274. wszTemp,
  275. lenTemp ) )
  276. {
  277. pCommandText->Release();
  278. return HRESULT_FROM_WIN32( GetLastError() );
  279. }
  280. hr = pCommandText->SetCommandText( DBGUID_DBSQL, wszTemp );
  281. delete [] wszTemp;
  282. #else
  283. hr = pCommandText->SetCommandText( DBGUID_DBSQL, szCommand );
  284. #endif
  285. if ( FAILED(hr) )
  286. {
  287. pCommandText->Release();
  288. return hr;
  289. }
  290. hr = pCommandText->Execute( NULL, IID_IMultipleResults, NULL, &cRowsAffected, (IUnknown **)&pResults );
  291. if ( FAILED(hr) )
  292. {
  293. pCommandText->Release();
  294. return hr;
  295. }
  296. // If the command succeeded but didn't return any results, return successfully
  297. if ( cRowsAffected != -1 )
  298. {
  299. return S_FALSE;
  300. }
  301. *ppOutResults = new CSimpleDBResults( pResults );
  302. pResults->Release();
  303. if ( NULL == *ppOutResults )
  304. {
  305. return E_OUTOFMEMORY;
  306. }
  307. return S_OK;
  308. }
  309. //
  310. // CSimpleDBResults
  311. //
  312. CSimpleDBResults::CSimpleDBResults(
  313. IMultipleResults *pResults
  314. ) : m_pResults(NULL),
  315. m_pCurRowset(NULL),
  316. m_phRow(NULL),
  317. m_rgColumnInfo(NULL),
  318. m_pColumnBuf(NULL),
  319. m_colInfo(NULL),
  320. m_numColumns(0)
  321. {
  322. m_pResults = pResults;
  323. m_pResults->AddRef();
  324. NextResultSet();
  325. }
  326. CSimpleDBResults::~CSimpleDBResults(
  327. void
  328. )
  329. {
  330. FreeRow();
  331. FreeRowset();
  332. m_pResults->Release();
  333. }
  334. HRESULT
  335. CSimpleDBResults::NextResultSet(
  336. void
  337. )
  338. {
  339. HRESULT hr;
  340. DBROWCOUNT cRowsAffected;
  341. IColumnsInfo *pColInfo = NULL;
  342. FreeRowset();
  343. hr = m_pResults->GetResult( NULL, 0, IID_IRowset, &cRowsAffected, (IUnknown **)&m_pCurRowset );
  344. if ( FAILED(hr) ) { return hr; }
  345. // Store column info
  346. hr = m_pCurRowset->QueryInterface( IID_IColumnsInfo, (PVOID *)&pColInfo );
  347. if ( FAILED(hr) ) { return hr; }
  348. hr = pColInfo->GetColumnInfo( &m_numColumns, &m_rgColumnInfo, &m_pColumnBuf );
  349. pColInfo->Release();
  350. if ( FAILED(hr) ) { return hr; }
  351. m_colInfo = new ColInfo[m_numColumns];
  352. if ( NULL == m_colInfo )
  353. {
  354. return E_OUTOFMEMORY;
  355. }
  356. memset( (PVOID)m_colInfo, 0, sizeof(ColInfo) * m_numColumns );
  357. return S_OK;
  358. }
  359. void
  360. CSimpleDBResults::FreeRowset(
  361. void
  362. )
  363. {
  364. IAccessor *pAccessor = NULL;
  365. if ( m_pCurRowset )
  366. {
  367. if ( FAILED(m_pCurRowset->QueryInterface( IID_IAccessor, (PVOID *)&pAccessor )) )
  368. {
  369. pAccessor = NULL;
  370. }
  371. }
  372. if ( NULL != m_rgColumnInfo )
  373. {
  374. CoTaskMemFree( m_rgColumnInfo );
  375. m_rgColumnInfo = NULL;
  376. }
  377. if ( NULL != m_pColumnBuf )
  378. {
  379. CoTaskMemFree( m_pColumnBuf );
  380. m_pColumnBuf = NULL;
  381. }
  382. if ( NULL != m_colInfo )
  383. {
  384. for ( DWORD i = 0; i < m_numColumns; i++ )
  385. {
  386. #ifndef UNICODE
  387. if ( NULL != m_colInfo[i].szColumnName )
  388. {
  389. delete [] m_colInfo[i].szColumnName;
  390. }
  391. #endif
  392. if ( pAccessor && m_colInfo[i].hAccessor )
  393. {
  394. pAccessor->ReleaseAccessor( m_colInfo[i].hAccessor, NULL );
  395. }
  396. }
  397. delete [] m_colInfo;
  398. m_colInfo = NULL;
  399. }
  400. if ( pAccessor )
  401. {
  402. pAccessor->Release();
  403. }
  404. if ( m_pCurRowset )
  405. {
  406. m_pCurRowset->Release();
  407. }
  408. m_numColumns = 0;
  409. }
  410. void
  411. CSimpleDBResults::FreeRow(
  412. void
  413. )
  414. {
  415. if ( NULL != m_phRow )
  416. {
  417. m_pCurRowset->ReleaseRows( 1, m_phRow, NULL, NULL, NULL );
  418. m_phRow = NULL;
  419. }
  420. }
  421. HRESULT
  422. CSimpleDBResults::NextRow(
  423. void
  424. )
  425. {
  426. HRESULT hr;
  427. DBCOUNTITEM cRowsReturned;
  428. FreeRow();
  429. hr = m_pCurRowset->GetNextRows( DB_NULL_HCHAPTER, 0, 1, &cRowsReturned, &m_phRow );
  430. if ( DB_S_ENDOFROWSET == hr )
  431. {
  432. return S_FALSE;
  433. }
  434. else if ( FAILED(hr) )
  435. {
  436. return hr;
  437. }
  438. return S_OK;
  439. }
  440. HRESULT
  441. CSimpleDBResults::GetFieldValue(
  442. LPCTSTR szField,
  443. LPTSTR szValue,
  444. DWORD dwMaxChars
  445. )
  446. {
  447. HRESULT hr;
  448. DWORD col;
  449. IAccessor *pAccessor = NULL;
  450. DBBINDING rgBindings[1];
  451. DBBINDSTATUS rgStatus[1];
  452. PVOID pBuf;
  453. szValue[0] = _T('\0');
  454. // Look through column names for specified field
  455. for ( col = 0; col < m_numColumns; col++ )
  456. {
  457. TCHAR *szColName;
  458. #ifndef UNICODE
  459. if ( NULL == m_colInfo[col].szColumnName )
  460. {
  461. size_t lenName = wcslen(m_rgColumnInfo[col].pwszName) + 1;
  462. m_colInfo[col].szColumnName = new char[lenName];
  463. if ( NULL == m_colInfo[col].szColumnName )
  464. {
  465. return E_OUTOFMEMORY;
  466. }
  467. if ( 0 == WideCharToMultiByte( CP_ACP,
  468. 0L,
  469. m_rgColumnInfo[col].pwszName,
  470. lenName,
  471. m_colInfo[col].szColumnName,
  472. lenName,
  473. NULL,
  474. NULL ) ) {
  475. return HRESULT_FROM_WIN32( GetLastError() );
  476. }
  477. }
  478. szColName = m_colInfo[col].szColumnName;
  479. #else
  480. szColName = m_rgColumnInfo[col].pwszName;
  481. #endif
  482. if ( !_tcsicmp( szColName, szField ) )
  483. {
  484. break;
  485. }
  486. }
  487. // Column is not in current rowset
  488. if ( col >= m_numColumns )
  489. {
  490. return S_FALSE;
  491. }
  492. if ( !m_colInfo[col].hAccessor )
  493. {
  494. memset( rgBindings, 0, sizeof(DBBINDING) );
  495. rgBindings[0].iOrdinal = m_rgColumnInfo[col].iOrdinal;
  496. rgBindings[0].dwPart = DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS;
  497. rgBindings[0].dwFlags = 0;
  498. rgBindings[0].obStatus = offsetof(_BindResult, status);
  499. rgBindings[0].obLength = offsetof(_BindResult, length);
  500. rgBindings[0].obValue = offsetof(_BindResult, value);
  501. rgBindings[0].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
  502. rgBindings[0].eParamIO = DBPARAMIO_NOTPARAM;
  503. rgBindings[0].bPrecision = m_rgColumnInfo[col].bPrecision;
  504. rgBindings[0].bScale = m_rgColumnInfo[col].bScale;
  505. rgBindings[0].wType = DBTYPE_WSTR;
  506. rgBindings[0].cbMaxLen = dwMaxChars * sizeof(WCHAR);
  507. hr = m_pCurRowset->QueryInterface( IID_IAccessor, (PVOID *)&pAccessor );
  508. if ( FAILED(hr) ) { return hr; }
  509. hr = pAccessor->CreateAccessor( DBACCESSOR_ROWDATA,
  510. 1,
  511. rgBindings,
  512. 0,
  513. &m_colInfo[col].hAccessor,
  514. rgStatus );
  515. pAccessor->Release();
  516. if ( FAILED(hr) ) { return hr; }
  517. }
  518. // Setup a buffer large enough to hold max results
  519. pBuf = (PVOID)new BYTE[ sizeof(_BindResult) + dwMaxChars * sizeof(WCHAR) ];
  520. if ( NULL == pBuf )
  521. {
  522. return E_OUTOFMEMORY;
  523. }
  524. hr = m_pCurRowset->GetData( *m_phRow, m_colInfo[col].hAccessor, pBuf );
  525. if ( FAILED(hr) ) { return hr; }
  526. // Skip status and length and just get the result for now
  527. wchar_t *wszValue = (LPWSTR)((DWORD_PTR)pBuf + offsetof(_BindResult, value));
  528. #ifndef UNICODE
  529. if ( 0 == WideCharToMultiByte( CP_ACP,
  530. 0L,
  531. wszValue,
  532. -1,
  533. szValue,
  534. dwMaxChars,
  535. NULL,
  536. NULL ) ) {
  537. return HRESULT_FROM_WIN32( GetLastError() );
  538. }
  539. #else
  540. wcscpy( szValue, wszValue );
  541. #endif
  542. return S_OK;
  543. }