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.

515 lines
14 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 2000, Microsoft Corp. All rights reserved.
  4. //
  5. // FILE
  6. //
  7. // iasdb.cpp
  8. //
  9. // SYNOPSIS
  10. //
  11. // Defines functions for accessing OLE-DB databases.
  12. //
  13. // MODIFICATION HISTORY
  14. //
  15. // 04/13/2000 Original version.
  16. //
  17. ///////////////////////////////////////////////////////////////////////////////
  18. #include <windows.h>
  19. #include <iasdb.h>
  20. #include <oledb.h>
  21. #include <msjetoledb.h>
  22. #include <atlbase.h>
  23. #include <iastrace.h>
  24. VOID
  25. WINAPI
  26. IASCreateTmpDirectory()
  27. {
  28. // JetInit fails if the TMP directory doesn't exist, so we'll try to
  29. // create it just in case.
  30. DWORD needed = GetEnvironmentVariableW(L"TMP", NULL, 0);
  31. if (needed)
  32. {
  33. PWCHAR buf = (PWCHAR)_alloca(needed * sizeof(WCHAR));
  34. DWORD actual = GetEnvironmentVariableW(L"TMP", buf, needed);
  35. if (actual > 0 && actual < needed)
  36. {
  37. CreateDirectoryW(buf, NULL);
  38. }
  39. }
  40. }
  41. HRESULT
  42. WINAPI
  43. IASCreateJetProvider(
  44. OUT IDBInitialize** provider
  45. ) throw ()
  46. {
  47. IASCreateTmpDirectory();
  48. // Convert the ProgID to a ClsID.
  49. CLSID clsid;
  50. HRESULT hr = CLSIDFromProgID(
  51. L"Microsoft.Jet.OLEDB.4.0",
  52. &clsid
  53. );
  54. if (SUCCEEDED(hr))
  55. {
  56. // Create the OLE DB provider.
  57. hr = CoCreateInstance(
  58. clsid,
  59. NULL,
  60. CLSCTX_INPROC_SERVER,
  61. __uuidof(IDBInitialize),
  62. (PVOID*)provider
  63. );
  64. }
  65. return hr;
  66. }
  67. HRESULT
  68. WINAPI
  69. IASOpenJetDatabase(
  70. IN PCWSTR path,
  71. IN BOOL readOnly,
  72. OUT LPUNKNOWN* session
  73. )
  74. {
  75. IASTracePrintf("INFO Enter IASOpenJetDatabase. path = %S readonly = %d",
  76. path, readOnly);
  77. // Initialize the out parameter.
  78. if (session == NULL) { return E_POINTER; }
  79. *session = NULL;
  80. HRESULT hr;
  81. do
  82. {
  83. // Create the OLE DB provider.
  84. CComPtr<IDBInitialize> connection;
  85. hr = IASCreateJetProvider(&connection);
  86. if (FAILED(hr)) { break; }
  87. //////////
  88. // Set the properties for the data source.
  89. //////////
  90. CComPtr<IDBProperties> properties;
  91. hr = connection->QueryInterface(
  92. __uuidof(IDBProperties),
  93. (PVOID*)&properties
  94. );
  95. if (FAILED(hr)) { break; }
  96. CComBSTR bstrPath = SysAllocString(path);
  97. if (!bstrPath)
  98. {
  99. hr = E_OUTOFMEMORY;
  100. break;
  101. }
  102. DBPROP dbprop[2];
  103. dbprop[0].dwPropertyID = DBPROP_INIT_MODE;
  104. dbprop[0].dwOptions = DBPROPOPTIONS_REQUIRED;
  105. dbprop[0].colid = DB_NULLID;
  106. dbprop[0].vValue.vt = VT_I4;
  107. dbprop[0].vValue.lVal = readOnly ? DB_MODE_READ : DB_MODE_READWRITE;
  108. dbprop[1].dwPropertyID = DBPROP_INIT_DATASOURCE;
  109. dbprop[1].dwOptions = DBPROPOPTIONS_REQUIRED;
  110. dbprop[1].colid = DB_NULLID;
  111. dbprop[1].vValue.vt = VT_BSTR;
  112. dbprop[1].vValue.bstrVal = bstrPath;
  113. DBPROPSET dbpropSet;
  114. dbpropSet.guidPropertySet = DBPROPSET_DBINIT;
  115. dbpropSet.cProperties = 2;
  116. dbpropSet.rgProperties = dbprop;
  117. hr = properties->SetProperties(1, &dbpropSet);
  118. if (FAILED(hr))
  119. {
  120. hr = IASTraceJetError("IDBProperties::SetProperties", hr);
  121. break;
  122. }
  123. //////////
  124. // Set the Jet specific properties for the data source.
  125. //////////
  126. dbprop[0].dwPropertyID = DBPROP_JETOLEDB_DATABASELOCKMODE;
  127. dbprop[0].dwOptions = DBPROPOPTIONS_REQUIRED;
  128. dbprop[0].colid = DB_NULLID;
  129. dbprop[0].vValue.vt = VT_I4;
  130. dbprop[0].vValue.lVal = (LONG)DBPROPVAL_DL_OLDMODE;
  131. dbpropSet.guidPropertySet = DBPROPSET_JETOLEDB_DBINIT;
  132. dbpropSet.cProperties = 1;
  133. dbpropSet.rgProperties = dbprop;
  134. hr = properties->SetProperties(1, &dbpropSet);
  135. if (FAILED(hr))
  136. {
  137. hr = IASTraceJetError("IDBProperties::SetProperties", hr);
  138. break;
  139. }
  140. //////////
  141. // Initialize the connection.
  142. //////////
  143. // This is a bit of a hack. The right approach would be to either (1)
  144. // always connect to the local database and use DCOM handle the remoting
  145. // or (2) always impersonate the client. Unfortunately, both of these
  146. // would require considerable changes to the existing client code.
  147. // Instead, we'll only impersonate the client when running under the
  148. // local system account AND opening a remote database. We know this will
  149. // always fail if we don't impersonate, so we can't lose anything by
  150. // attempting to impersonate.
  151. bool revert = false;
  152. if ( !IASIsInprocServer() &&
  153. path[0] == L'\\' &&
  154. path[1] == L'\\' )
  155. {
  156. hr = CoImpersonateClient();
  157. if ( FAILED(hr) )
  158. {
  159. IASTraceFailure("CoImpersonateClient", hr);
  160. break;
  161. }
  162. else
  163. {
  164. revert = true;
  165. }
  166. }
  167. hr = connection->Initialize();
  168. if (revert) { CoRevertToSelf(); }
  169. if (FAILED(hr))
  170. {
  171. hr = IASTraceJetError("IDBInitialize::Initialize", hr);
  172. break;
  173. }
  174. //////////
  175. // Create a session.
  176. //////////
  177. CComPtr<IDBCreateSession> creator;
  178. hr = connection->QueryInterface(
  179. __uuidof(IDBCreateSession),
  180. (PVOID*)&creator
  181. );
  182. if (FAILED(hr)) { break; }
  183. hr = creator->CreateSession(
  184. NULL,
  185. __uuidof(IUnknown),
  186. session
  187. );
  188. if (FAILED(hr))
  189. {
  190. hr = IASTraceJetError("IDBCreateSession::CreateSession", hr);
  191. break;
  192. }
  193. }
  194. while(false);
  195. IASTracePrintf("INFO Leave IASOpenJetDatabase. hr = 0x%08X", hr);
  196. return hr;
  197. }
  198. HRESULT
  199. WINAPI
  200. IASExecuteSQLCommand(
  201. IN LPUNKNOWN session,
  202. IN PCWSTR commandText,
  203. OUT IRowset** result
  204. )
  205. {
  206. IASTracePrintf("INFO IASExecuteSQLCommand. Command = %S", commandText);
  207. // Initialize the out parameter.
  208. if (result) { *result = NULL; }
  209. HRESULT hr;
  210. CComPtr<IDBCreateCommand> creator;
  211. hr = session->QueryInterface(
  212. __uuidof(IDBCreateCommand),
  213. (PVOID*)&creator
  214. );
  215. if (FAILED(hr)) { return hr; }
  216. CComPtr<ICommandText> command;
  217. hr = creator->CreateCommand(
  218. NULL,
  219. __uuidof(ICommandText),
  220. (IUnknown**)&command
  221. );
  222. if (FAILED(hr))
  223. {
  224. return IASTraceJetError("IDBCreateCommand::CreateCommand", hr);
  225. }
  226. hr = command->SetCommandText(
  227. DBGUID_DBSQL,
  228. commandText
  229. );
  230. if (FAILED(hr))
  231. {
  232. return IASTraceJetError("ICommandText::SetCommandText", hr);
  233. }
  234. hr = command->Execute(
  235. NULL,
  236. (result ? __uuidof(IRowset) : IID_NULL),
  237. NULL,
  238. NULL,
  239. (IUnknown**)result
  240. );
  241. if (FAILED(hr))
  242. {
  243. return IASTraceJetError("ICommand::Execute", hr);
  244. }
  245. return S_OK;
  246. }
  247. HRESULT
  248. WINAPI
  249. IASExecuteSQLFunction(
  250. IN LPUNKNOWN session,
  251. IN PCWSTR functionText,
  252. OUT LONG* result
  253. )
  254. {
  255. // Initialize the out parameter.
  256. if (result == NULL) { return E_POINTER; }
  257. *result = 0;
  258. // Execute the function.
  259. HRESULT hr;
  260. CComPtr<IRowset> rowset;
  261. hr = IASExecuteSQLCommand(
  262. session,
  263. functionText,
  264. &rowset
  265. );
  266. if (FAILED(hr)) { return hr; }
  267. CComPtr<IAccessor> accessor;
  268. hr = rowset->QueryInterface(
  269. __uuidof(IAccessor),
  270. (PVOID*)&accessor
  271. );
  272. if (FAILED(hr)) { return hr; }
  273. // Get the result row.
  274. DBCOUNTITEM numRows;
  275. HROW hRow;
  276. HROW* pRow = &hRow;
  277. hr = rowset->GetNextRows(
  278. NULL,
  279. 0,
  280. 1,
  281. &numRows,
  282. &pRow
  283. );
  284. if (FAILED(hr))
  285. {
  286. return IASTraceJetError("IRowset::GetNextRows", hr);
  287. }
  288. if (numRows == 0) { return E_FAIL; }
  289. /////////
  290. // Create an accessor.
  291. /////////
  292. DBBINDING bind;
  293. memset(&bind, 0, sizeof(bind));
  294. bind.iOrdinal = 1;
  295. bind.dwPart = DBPART_VALUE;
  296. bind.wType = DBTYPE_I4;
  297. bind.cbMaxLen = 4;
  298. HACCESSOR hAccess;
  299. hr = accessor->CreateAccessor(
  300. DBACCESSOR_ROWDATA,
  301. 1,
  302. &bind,
  303. 4,
  304. &hAccess,
  305. NULL
  306. );
  307. if (SUCCEEDED(hr))
  308. {
  309. // Get the data.
  310. hr = rowset->GetData(
  311. hRow,
  312. hAccess,
  313. result
  314. );
  315. if (FAILED(hr))
  316. {
  317. hr = IASTraceJetError("IRowset::GetData", hr);
  318. }
  319. accessor->ReleaseAccessor(hAccess, NULL);
  320. }
  321. else
  322. {
  323. hr = IASTraceJetError("IAccessor::CreateAccessor", hr);
  324. }
  325. rowset->ReleaseRows(1, &hRow, NULL, NULL, NULL);
  326. return hr;
  327. }
  328. //////////////////////////////////////////////////////////////////////////////
  329. // IASCreateDatabase
  330. //////////////////////////////////////////////////////////////////////////////
  331. HRESULT
  332. WINAPI
  333. IASCreateJetDatabase(
  334. IN PCWSTR dataSource
  335. )
  336. {
  337. // Create the OLE DB provider.
  338. CComPtr<IDBInitialize> connection;
  339. HRESULT hr = IASCreateJetProvider(&connection);
  340. if (FAILED(hr)) { return hr; }
  341. //////////
  342. // Set the properties for the data source.
  343. //////////
  344. CComPtr<IDBProperties> properties;
  345. hr = connection->QueryInterface(
  346. __uuidof(IDBProperties),
  347. (PVOID*)&properties
  348. );
  349. if (FAILED(hr)) { return hr; }
  350. CComBSTR bstrDataSource(dataSource);
  351. if ( !bstrDataSource) { return E_OUTOFMEMORY; }
  352. DBPROP dbprop[2];
  353. dbprop[0].dwPropertyID = DBPROP_INIT_DATASOURCE;
  354. dbprop[0].dwOptions = DBPROPOPTIONS_REQUIRED;
  355. dbprop[0].colid = DB_NULLID;
  356. dbprop[0].vValue.vt = VT_BSTR;
  357. dbprop[0].vValue.bstrVal = bstrDataSource;
  358. dbprop[1].dwPropertyID = DBPROP_INIT_LOCATION;
  359. dbprop[1].dwOptions = DBPROPOPTIONS_OPTIONAL;
  360. dbprop[1].colid = DB_NULLID;
  361. dbprop[1].vValue.vt = VT_BSTR;
  362. dbprop[1].vValue.lVal = VT_NULL;
  363. DBPROPSET dbpropSet;
  364. dbpropSet.guidPropertySet = DBPROPSET_DBINIT;
  365. dbpropSet.cProperties = 2;
  366. dbpropSet.rgProperties = dbprop;
  367. hr = properties->SetProperties(1, &dbpropSet);
  368. if (FAILED(hr))
  369. {
  370. return IASTraceJetError("IDBProperties::SetProperties", hr);
  371. }
  372. // Create the Data Source
  373. CComPtr<IDBDataSourceAdmin> admin;
  374. hr = connection->QueryInterface(
  375. __uuidof(IDBDataSourceAdmin),
  376. (PVOID*)&admin
  377. );
  378. if (FAILED(hr)) { return hr; }
  379. hr = admin->CreateDataSource(
  380. 1,
  381. &dbpropSet,
  382. NULL,
  383. __uuidof(IDBCreateSession),
  384. NULL
  385. );
  386. if (FAILED(hr))
  387. {
  388. return IASTraceJetError("IDBDataSourceAdmin::CreateDataSource", hr);
  389. }
  390. return S_OK;
  391. }
  392. // Internal Jet error codes from msjeterr.h
  393. #define JET_errFileAccessDenied -1032
  394. #define JET_errKeyDuplicate -1605
  395. HRESULT
  396. WINAPI
  397. IASTraceJetError(
  398. PCSTR functionName,
  399. HRESULT errorCode
  400. )
  401. {
  402. IASTracePrintf("%s failed; return value = 0x%08X", functionName, errorCode);
  403. IErrorInfo* errInfo;
  404. if (GetErrorInfo(0, &errInfo) == S_OK)
  405. {
  406. BSTR description;
  407. if (SUCCEEDED(errInfo->GetDescription(&description)))
  408. {
  409. IASTracePrintf("\tDescription: %S", description);
  410. SysFreeString(description);
  411. }
  412. IErrorRecords* errRecords;
  413. if (SUCCEEDED(errInfo->QueryInterface(
  414. __uuidof(IErrorRecords),
  415. (PVOID*)&errRecords
  416. )))
  417. {
  418. ULONG numRecords = 0;
  419. errRecords->GetRecordCount(&numRecords);
  420. for (ULONG i = 0; i < numRecords; ++i)
  421. {
  422. ERRORINFO info;
  423. if (SUCCEEDED(errRecords->GetBasicErrorInfo(i, &info)))
  424. {
  425. IASTracePrintf(
  426. "\tRecord %lu: hrError = 0x%08X; dwMinor = 0x%08X",
  427. i, info.hrError, info.dwMinor
  428. );
  429. // Jolt does a poor job of mapping Jet error codes to HRESULTs,
  430. // so we handle a few ourselves. The Jet error code is the low
  431. // order 16 bits treated as a signed integer.
  432. switch ((WORD)info.dwMinor)
  433. {
  434. case JET_errFileAccessDenied:
  435. errorCode = E_ACCESSDENIED;
  436. break;
  437. case JET_errKeyDuplicate:
  438. errorCode = HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS);
  439. break;
  440. }
  441. }
  442. }
  443. errRecords->Release();
  444. }
  445. errInfo->Release();
  446. }
  447. return errorCode;
  448. }