PageRenderTime 102ms CodeModel.GetById 29ms RepoModel.GetById 1ms app.codeStats 1ms

/wine-1.5.9/dlls/msi/tests/db.c

#
C | 9704 lines | 9317 code | 307 blank | 80 comment | 358 complexity | 3f02e5e703b9a8c20cea89b6dc369415 MD5 | raw file
Possible License(s): LGPL-2.1, LGPL-2.0

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. * Copyright (C) 2005 Mike McCormack for CodeWeavers
  3. *
  4. * A test program for MSI database files.
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2.1 of the License, or (at your option) any later version.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this library; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  19. */
  20. #define COBJMACROS
  21. #include <stdio.h>
  22. #include <windows.h>
  23. #include <msi.h>
  24. #include <msidefs.h>
  25. #include <msiquery.h>
  26. #include <objidl.h>
  27. #include "wine/test.h"
  28. static const char *msifile = "winetest-db.msi";
  29. static const char *msifile2 = "winetst2-db.msi";
  30. static const char *mstfile = "winetst-db.mst";
  31. static const WCHAR msifileW[] = {'w','i','n','e','t','e','s','t','-','d','b','.','m','s','i',0};
  32. static void test_msidatabase(void)
  33. {
  34. MSIHANDLE hdb = 0, hdb2 = 0;
  35. UINT res;
  36. DeleteFile(msifile);
  37. res = MsiOpenDatabase( msifile, msifile2, &hdb );
  38. ok( res == ERROR_OPEN_FAILED, "expected failure\n");
  39. res = MsiOpenDatabase( msifile, (LPSTR) 0xff, &hdb );
  40. ok( res == ERROR_INVALID_PARAMETER, "expected failure\n");
  41. res = MsiCloseHandle( hdb );
  42. ok( res == ERROR_SUCCESS , "Failed to close database\n" );
  43. /* create an empty database */
  44. res = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb );
  45. ok( res == ERROR_SUCCESS , "Failed to create database\n" );
  46. res = MsiDatabaseCommit( hdb );
  47. ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
  48. ok( INVALID_FILE_ATTRIBUTES != GetFileAttributes( msifile ), "database should exist\n");
  49. res = MsiCloseHandle( hdb );
  50. ok( res == ERROR_SUCCESS , "Failed to close database\n" );
  51. res = MsiOpenDatabase( msifile, msifile2, &hdb2 );
  52. ok( res == ERROR_SUCCESS , "Failed to open database\n" );
  53. ok( INVALID_FILE_ATTRIBUTES != GetFileAttributes( msifile2 ), "database should exist\n");
  54. res = MsiDatabaseCommit( hdb2 );
  55. ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
  56. res = MsiCloseHandle( hdb2 );
  57. ok( res == ERROR_SUCCESS , "Failed to close database\n" );
  58. res = MsiOpenDatabase( msifile, msifile2, &hdb2 );
  59. ok( res == ERROR_SUCCESS , "Failed to open database\n" );
  60. res = MsiCloseHandle( hdb2 );
  61. ok( res == ERROR_SUCCESS , "Failed to close database\n" );
  62. ok( INVALID_FILE_ATTRIBUTES == GetFileAttributes( msifile2 ), "uncommitted database should not exist\n");
  63. res = MsiOpenDatabase( msifile, msifile2, &hdb2 );
  64. ok( res == ERROR_SUCCESS , "Failed to close database\n" );
  65. res = MsiDatabaseCommit( hdb2 );
  66. ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
  67. res = MsiCloseHandle( hdb2 );
  68. ok( res == ERROR_SUCCESS , "Failed to close database\n" );
  69. ok( INVALID_FILE_ATTRIBUTES != GetFileAttributes( msifile2 ), "committed database should exist\n");
  70. res = MsiOpenDatabase( msifile, MSIDBOPEN_READONLY, &hdb );
  71. ok( res == ERROR_SUCCESS , "Failed to open database\n" );
  72. res = MsiDatabaseCommit( hdb );
  73. ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
  74. res = MsiCloseHandle( hdb );
  75. ok( res == ERROR_SUCCESS , "Failed to close database\n" );
  76. res = MsiOpenDatabase( msifile, MSIDBOPEN_DIRECT, &hdb );
  77. ok( res == ERROR_SUCCESS , "Failed to open database\n" );
  78. res = MsiCloseHandle( hdb );
  79. ok( res == ERROR_SUCCESS , "Failed to close database\n" );
  80. res = MsiOpenDatabase( msifile, MSIDBOPEN_TRANSACT, &hdb );
  81. ok( res == ERROR_SUCCESS , "Failed to open database\n" );
  82. res = MsiCloseHandle( hdb );
  83. ok( res == ERROR_SUCCESS , "Failed to close database\n" );
  84. ok( INVALID_FILE_ATTRIBUTES != GetFileAttributes( msifile ), "database should exist\n");
  85. /* MSIDBOPEN_CREATE deletes the database if MsiCommitDatabase isn't called */
  86. res = MsiOpenDatabase( msifile, MSIDBOPEN_CREATE, &hdb );
  87. ok( res == ERROR_SUCCESS , "Failed to open database\n" );
  88. ok( INVALID_FILE_ATTRIBUTES != GetFileAttributes( msifile ), "database should exist\n");
  89. res = MsiCloseHandle( hdb );
  90. ok( res == ERROR_SUCCESS , "Failed to close database\n" );
  91. ok( INVALID_FILE_ATTRIBUTES == GetFileAttributes( msifile ), "database should exist\n");
  92. res = MsiOpenDatabase( msifile, MSIDBOPEN_CREATE, &hdb );
  93. ok( res == ERROR_SUCCESS , "Failed to open database\n" );
  94. res = MsiDatabaseCommit( hdb );
  95. ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
  96. ok( INVALID_FILE_ATTRIBUTES != GetFileAttributes( msifile ), "database should exist\n");
  97. res = MsiCloseHandle( hdb );
  98. ok( res == ERROR_SUCCESS , "Failed to close database\n" );
  99. res = DeleteFile( msifile2 );
  100. ok( res == TRUE, "Failed to delete database\n" );
  101. res = DeleteFile( msifile );
  102. ok( res == TRUE, "Failed to delete database\n" );
  103. }
  104. static UINT do_query(MSIHANDLE hdb, const char *query, MSIHANDLE *phrec)
  105. {
  106. MSIHANDLE hview = 0;
  107. UINT r, ret;
  108. if (phrec)
  109. *phrec = 0;
  110. /* open a select query */
  111. r = MsiDatabaseOpenView(hdb, query, &hview);
  112. if (r != ERROR_SUCCESS)
  113. return r;
  114. r = MsiViewExecute(hview, 0);
  115. if (r != ERROR_SUCCESS)
  116. return r;
  117. ret = MsiViewFetch(hview, phrec);
  118. r = MsiViewClose(hview);
  119. if (r != ERROR_SUCCESS)
  120. return r;
  121. r = MsiCloseHandle(hview);
  122. if (r != ERROR_SUCCESS)
  123. return r;
  124. return ret;
  125. }
  126. static UINT run_query( MSIHANDLE hdb, MSIHANDLE hrec, const char *query )
  127. {
  128. MSIHANDLE hview = 0;
  129. UINT r;
  130. r = MsiDatabaseOpenView(hdb, query, &hview);
  131. if( r != ERROR_SUCCESS )
  132. return r;
  133. r = MsiViewExecute(hview, hrec);
  134. if( r == ERROR_SUCCESS )
  135. r = MsiViewClose(hview);
  136. MsiCloseHandle(hview);
  137. return r;
  138. }
  139. static UINT run_queryW( MSIHANDLE hdb, MSIHANDLE hrec, const WCHAR *query )
  140. {
  141. MSIHANDLE hview = 0;
  142. UINT r;
  143. r = MsiDatabaseOpenViewW(hdb, query, &hview);
  144. if( r != ERROR_SUCCESS )
  145. return r;
  146. r = MsiViewExecute(hview, hrec);
  147. if( r == ERROR_SUCCESS )
  148. r = MsiViewClose(hview);
  149. MsiCloseHandle(hview);
  150. return r;
  151. }
  152. static UINT create_component_table( MSIHANDLE hdb )
  153. {
  154. return run_query( hdb, 0,
  155. "CREATE TABLE `Component` ( "
  156. "`Component` CHAR(72) NOT NULL, "
  157. "`ComponentId` CHAR(38), "
  158. "`Directory_` CHAR(72) NOT NULL, "
  159. "`Attributes` SHORT NOT NULL, "
  160. "`Condition` CHAR(255), "
  161. "`KeyPath` CHAR(72) "
  162. "PRIMARY KEY `Component`)" );
  163. }
  164. static UINT create_custom_action_table( MSIHANDLE hdb )
  165. {
  166. return run_query( hdb, 0,
  167. "CREATE TABLE `CustomAction` ( "
  168. "`Action` CHAR(72) NOT NULL, "
  169. "`Type` SHORT NOT NULL, "
  170. "`Source` CHAR(72), "
  171. "`Target` CHAR(255) "
  172. "PRIMARY KEY `Action`)" );
  173. }
  174. static UINT create_directory_table( MSIHANDLE hdb )
  175. {
  176. return run_query( hdb, 0,
  177. "CREATE TABLE `Directory` ( "
  178. "`Directory` CHAR(255) NOT NULL, "
  179. "`Directory_Parent` CHAR(255), "
  180. "`DefaultDir` CHAR(255) NOT NULL "
  181. "PRIMARY KEY `Directory`)" );
  182. }
  183. static UINT create_feature_components_table( MSIHANDLE hdb )
  184. {
  185. return run_query( hdb, 0,
  186. "CREATE TABLE `FeatureComponents` ( "
  187. "`Feature_` CHAR(38) NOT NULL, "
  188. "`Component_` CHAR(72) NOT NULL "
  189. "PRIMARY KEY `Feature_`, `Component_` )" );
  190. }
  191. static UINT create_std_dlls_table( MSIHANDLE hdb )
  192. {
  193. return run_query( hdb, 0,
  194. "CREATE TABLE `StdDlls` ( "
  195. "`File` CHAR(255) NOT NULL, "
  196. "`Binary_` CHAR(72) NOT NULL "
  197. "PRIMARY KEY `File` )" );
  198. }
  199. static UINT create_binary_table( MSIHANDLE hdb )
  200. {
  201. return run_query( hdb, 0,
  202. "CREATE TABLE `Binary` ( "
  203. "`Name` CHAR(72) NOT NULL, "
  204. "`Data` CHAR(72) NOT NULL "
  205. "PRIMARY KEY `Name` )" );
  206. }
  207. #define make_add_entry(type, qtext) \
  208. static UINT add##_##type##_##entry( MSIHANDLE hdb, const char *values ) \
  209. { \
  210. char insert[] = qtext; \
  211. char *query; \
  212. UINT sz, r; \
  213. sz = strlen(values) + sizeof insert; \
  214. query = HeapAlloc(GetProcessHeap(),0,sz); \
  215. sprintf(query,insert,values); \
  216. r = run_query( hdb, 0, query ); \
  217. HeapFree(GetProcessHeap(), 0, query); \
  218. return r; \
  219. }
  220. make_add_entry(component,
  221. "INSERT INTO `Component` "
  222. "(`Component`, `ComponentId`, `Directory_`, "
  223. "`Attributes`, `Condition`, `KeyPath`) VALUES( %s )")
  224. make_add_entry(custom_action,
  225. "INSERT INTO `CustomAction` "
  226. "(`Action`, `Type`, `Source`, `Target`) VALUES( %s )")
  227. make_add_entry(feature_components,
  228. "INSERT INTO `FeatureComponents` "
  229. "(`Feature_`, `Component_`) VALUES( %s )")
  230. make_add_entry(std_dlls,
  231. "INSERT INTO `StdDlls` (`File`, `Binary_`) VALUES( %s )")
  232. make_add_entry(binary,
  233. "INSERT INTO `Binary` (`Name`, `Data`) VALUES( %s )")
  234. static void test_msiinsert(void)
  235. {
  236. MSIHANDLE hdb = 0, hview = 0, hview2 = 0, hrec = 0;
  237. UINT r;
  238. const char *query;
  239. char buf[80];
  240. DWORD sz;
  241. DeleteFile(msifile);
  242. /* just MsiOpenDatabase should not create a file */
  243. r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
  244. ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
  245. /* create a table */
  246. query = "CREATE TABLE `phone` ( "
  247. "`id` INT, `name` CHAR(32), `number` CHAR(32) "
  248. "PRIMARY KEY `id`)";
  249. r = MsiDatabaseOpenView(hdb, query, &hview);
  250. ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
  251. r = MsiViewExecute(hview, 0);
  252. ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
  253. r = MsiViewClose(hview);
  254. ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
  255. r = MsiCloseHandle(hview);
  256. ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
  257. query = "SELECT * FROM phone WHERE number = '8675309'";
  258. r = MsiDatabaseOpenView(hdb, query, &hview2);
  259. ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
  260. r = MsiViewExecute(hview2, 0);
  261. ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
  262. r = MsiViewFetch(hview2, &hrec);
  263. ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch produced items\n");
  264. /* insert a value into it */
  265. query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
  266. "VALUES('1', 'Abe', '8675309')";
  267. r = MsiDatabaseOpenView(hdb, query, &hview);
  268. ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
  269. r = MsiViewExecute(hview, 0);
  270. ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
  271. r = MsiViewClose(hview);
  272. ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
  273. r = MsiCloseHandle(hview);
  274. ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
  275. r = MsiViewFetch(hview2, &hrec);
  276. ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch produced items\n");
  277. r = MsiViewExecute(hview2, 0);
  278. ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
  279. r = MsiViewFetch(hview2, &hrec);
  280. ok(r == ERROR_SUCCESS, "MsiViewFetch failed: %u\n", r);
  281. r = MsiCloseHandle(hrec);
  282. ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
  283. r = MsiViewClose(hview2);
  284. ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
  285. r = MsiCloseHandle(hview2);
  286. ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
  287. query = "SELECT * FROM `phone` WHERE `id` = 1";
  288. r = do_query(hdb, query, &hrec);
  289. ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
  290. /* check the record contains what we put in it */
  291. r = MsiRecordGetFieldCount(hrec);
  292. ok(r == 3, "record count wrong\n");
  293. r = MsiRecordIsNull(hrec, 0);
  294. ok(r == FALSE, "field 0 not null\n");
  295. r = MsiRecordGetInteger(hrec, 1);
  296. ok(r == 1, "field 1 contents wrong\n");
  297. sz = sizeof buf;
  298. r = MsiRecordGetString(hrec, 2, buf, &sz);
  299. ok(r == ERROR_SUCCESS, "field 2 content fetch failed\n");
  300. ok(!strcmp(buf,"Abe"), "field 2 content incorrect\n");
  301. sz = sizeof buf;
  302. r = MsiRecordGetString(hrec, 3, buf, &sz);
  303. ok(r == ERROR_SUCCESS, "field 3 content fetch failed\n");
  304. ok(!strcmp(buf,"8675309"), "field 3 content incorrect\n");
  305. r = MsiCloseHandle(hrec);
  306. ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
  307. /* open a select query */
  308. hrec = 100;
  309. query = "SELECT * FROM `phone` WHERE `id` >= 10";
  310. r = do_query(hdb, query, &hrec);
  311. ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch failed\n");
  312. ok(hrec == 0, "hrec should be null\n");
  313. r = MsiCloseHandle(hrec);
  314. ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
  315. query = "SELECT * FROM `phone` WHERE `id` < 0";
  316. r = do_query(hdb, query, &hrec);
  317. ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch failed\n");
  318. query = "SELECT * FROM `phone` WHERE `id` <= 0";
  319. r = do_query(hdb, query, &hrec);
  320. ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch failed\n");
  321. query = "SELECT * FROM `phone` WHERE `id` <> 1";
  322. r = do_query(hdb, query, &hrec);
  323. ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch failed\n");
  324. query = "SELECT * FROM `phone` WHERE `id` > 10";
  325. r = do_query(hdb, query, &hrec);
  326. ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch failed\n");
  327. /* now try a few bad INSERT xqueries */
  328. query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
  329. "VALUES(?, ?)";
  330. r = MsiDatabaseOpenView(hdb, query, &hview);
  331. ok(r == ERROR_BAD_QUERY_SYNTAX, "MsiDatabaseOpenView failed\n");
  332. /* construct a record to insert */
  333. hrec = MsiCreateRecord(4);
  334. r = MsiRecordSetInteger(hrec, 1, 2);
  335. ok(r == ERROR_SUCCESS, "MsiRecordSetInteger failed\n");
  336. r = MsiRecordSetString(hrec, 2, "Adam");
  337. ok(r == ERROR_SUCCESS, "MsiRecordSetString failed\n");
  338. r = MsiRecordSetString(hrec, 3, "96905305");
  339. ok(r == ERROR_SUCCESS, "MsiRecordSetString failed\n");
  340. /* insert another value, using a record and wildcards */
  341. query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
  342. "VALUES(?, ?, ?)";
  343. r = MsiDatabaseOpenView(hdb, query, &hview);
  344. ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
  345. if (r == ERROR_SUCCESS)
  346. {
  347. r = MsiViewExecute(hview, hrec);
  348. ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
  349. r = MsiViewClose(hview);
  350. ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
  351. r = MsiCloseHandle(hview);
  352. ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
  353. }
  354. r = MsiCloseHandle(hrec);
  355. ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
  356. r = MsiViewFetch(0, NULL);
  357. ok(r == ERROR_INVALID_PARAMETER, "MsiViewFetch failed\n");
  358. r = MsiDatabaseCommit(hdb);
  359. ok(r == ERROR_SUCCESS, "MsiDatabaseCommit failed\n");
  360. r = MsiCloseHandle(hdb);
  361. ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
  362. r = DeleteFile(msifile);
  363. ok(r == TRUE, "file didn't exist after commit\n");
  364. }
  365. static void test_msidecomposedesc(void)
  366. {
  367. UINT (WINAPI *pMsiDecomposeDescriptorA)(LPCSTR, LPCSTR, LPSTR, LPSTR, DWORD *);
  368. char prod[MAX_FEATURE_CHARS+1], comp[MAX_FEATURE_CHARS+1], feature[MAX_FEATURE_CHARS+1];
  369. const char *desc;
  370. UINT r;
  371. DWORD len;
  372. HMODULE hmod;
  373. hmod = GetModuleHandle("msi.dll");
  374. pMsiDecomposeDescriptorA = (void*)GetProcAddress(hmod, "MsiDecomposeDescriptorA");
  375. if (!pMsiDecomposeDescriptorA)
  376. return;
  377. /* test a valid feature descriptor */
  378. desc = "']gAVn-}f(ZXfeAR6.jiFollowTheWhiteRabbit>3w2x^IGfe?CxI5heAvk.";
  379. len = 0;
  380. r = pMsiDecomposeDescriptorA(desc, prod, feature, comp, &len);
  381. ok(r == ERROR_SUCCESS, "returned an error\n");
  382. ok(len == strlen(desc), "length was wrong\n");
  383. ok(strcmp(prod,"{90110409-6000-11D3-8CFE-0150048383C9}")==0, "product wrong\n");
  384. ok(strcmp(feature,"FollowTheWhiteRabbit")==0, "feature wrong\n");
  385. ok(strcmp(comp,"{A7CD68DB-EF74-49C8-FBB2-A7C463B2AC24}")==0,"component wrong\n");
  386. /* test an invalid feature descriptor with too many characters */
  387. desc = "']gAVn-}f(ZXfeAR6.ji"
  388. "ThisWillFailIfTheresMoreThanAGuidsChars>"
  389. "3w2x^IGfe?CxI5heAvk.";
  390. len = 0;
  391. r = pMsiDecomposeDescriptorA(desc, prod, feature, comp, &len);
  392. ok(r == ERROR_INVALID_PARAMETER, "returned wrong error\n");
  393. /*
  394. * Test a valid feature descriptor with the
  395. * maximum number of characters and some trailing characters.
  396. */
  397. desc = "']gAVn-}f(ZXfeAR6.ji"
  398. "ThisWillWorkIfTheresLTEThanAGuidsChars>"
  399. "3w2x^IGfe?CxI5heAvk."
  400. "extra";
  401. len = 0;
  402. r = pMsiDecomposeDescriptorA(desc, prod, feature, comp, &len);
  403. ok(r == ERROR_SUCCESS, "returned wrong error\n");
  404. ok(len == (strlen(desc) - strlen("extra")), "length wrong\n");
  405. len = 0;
  406. r = pMsiDecomposeDescriptorA(desc, prod, feature, NULL, &len);
  407. ok(r == ERROR_SUCCESS, "returned wrong error\n");
  408. ok(len == (strlen(desc) - strlen("extra")), "length wrong\n");
  409. len = 0;
  410. r = pMsiDecomposeDescriptorA(desc, prod, NULL, NULL, &len);
  411. ok(r == ERROR_SUCCESS, "returned wrong error\n");
  412. ok(len == (strlen(desc) - strlen("extra")), "length wrong\n");
  413. len = 0;
  414. r = pMsiDecomposeDescriptorA(desc, NULL, NULL, NULL, &len);
  415. ok(r == ERROR_SUCCESS, "returned wrong error\n");
  416. ok(len == (strlen(desc) - strlen("extra")), "length wrong\n");
  417. len = 0;
  418. r = pMsiDecomposeDescriptorA(NULL, NULL, NULL, NULL, &len);
  419. ok(r == ERROR_INVALID_PARAMETER, "returned wrong error\n");
  420. ok(len == 0, "length wrong\n");
  421. r = pMsiDecomposeDescriptorA(desc, NULL, NULL, NULL, NULL);
  422. ok(r == ERROR_SUCCESS, "returned wrong error\n");
  423. }
  424. static UINT try_query_param( MSIHANDLE hdb, LPCSTR szQuery, MSIHANDLE hrec )
  425. {
  426. MSIHANDLE htab = 0;
  427. UINT res;
  428. res = MsiDatabaseOpenView( hdb, szQuery, &htab );
  429. if(res == ERROR_SUCCESS )
  430. {
  431. UINT r;
  432. r = MsiViewExecute( htab, hrec );
  433. if(r != ERROR_SUCCESS )
  434. res = r;
  435. r = MsiViewClose( htab );
  436. if(r != ERROR_SUCCESS )
  437. res = r;
  438. r = MsiCloseHandle( htab );
  439. if(r != ERROR_SUCCESS )
  440. res = r;
  441. }
  442. return res;
  443. }
  444. static UINT try_query( MSIHANDLE hdb, LPCSTR szQuery )
  445. {
  446. return try_query_param( hdb, szQuery, 0 );
  447. }
  448. static UINT try_insert_query( MSIHANDLE hdb, LPCSTR szQuery )
  449. {
  450. MSIHANDLE hrec = 0;
  451. UINT r;
  452. hrec = MsiCreateRecord( 1 );
  453. MsiRecordSetString( hrec, 1, "Hello");
  454. r = try_query_param( hdb, szQuery, hrec );
  455. MsiCloseHandle( hrec );
  456. return r;
  457. }
  458. static void test_msibadqueries(void)
  459. {
  460. MSIHANDLE hdb = 0;
  461. UINT r;
  462. DeleteFile(msifile);
  463. /* just MsiOpenDatabase should not create a file */
  464. r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
  465. ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
  466. r = MsiDatabaseCommit( hdb );
  467. ok(r == ERROR_SUCCESS , "Failed to commit database\n");
  468. r = MsiCloseHandle( hdb );
  469. ok(r == ERROR_SUCCESS , "Failed to close database\n");
  470. /* open it readonly */
  471. r = MsiOpenDatabase(msifile, MSIDBOPEN_READONLY, &hdb );
  472. ok(r == ERROR_SUCCESS , "Failed to open database r/o\n");
  473. /* add a table to it */
  474. r = try_query( hdb, "select * from _Tables");
  475. ok(r == ERROR_SUCCESS , "query 1 failed\n");
  476. r = MsiCloseHandle( hdb );
  477. ok(r == ERROR_SUCCESS , "Failed to close database r/o\n");
  478. /* open it read/write */
  479. r = MsiOpenDatabase(msifile, MSIDBOPEN_TRANSACT, &hdb );
  480. ok(r == ERROR_SUCCESS , "Failed to open database r/w\n");
  481. /* a bunch of test queries that fail with the native MSI */
  482. r = try_query( hdb, "CREATE TABLE");
  483. ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2a return code\n");
  484. r = try_query( hdb, "CREATE TABLE `a`");
  485. ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2b return code\n");
  486. r = try_query( hdb, "CREATE TABLE `a` ()");
  487. ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2c return code\n");
  488. r = try_query( hdb, "CREATE TABLE `a` (`b`)");
  489. ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2d return code\n");
  490. r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) )");
  491. ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2e return code\n");
  492. r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL)");
  493. ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2f return code\n");
  494. r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY)");
  495. ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2g return code\n");
  496. r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY)");
  497. ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2h return code\n");
  498. r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY)");
  499. ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2i return code\n");
  500. r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY 'b')");
  501. ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2j return code\n");
  502. r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY `b')");
  503. ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2k return code\n");
  504. r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY `b')");
  505. ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2l return code\n");
  506. r = try_query( hdb, "CREATE TABLE `a` (`b` CHA(72) NOT NULL PRIMARY KEY `b`)");
  507. ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2m return code\n");
  508. r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(-1) NOT NULL PRIMARY KEY `b`)");
  509. ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2n return code\n");
  510. r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(720) NOT NULL PRIMARY KEY `b`)");
  511. ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2o return code\n");
  512. r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL KEY `b`)");
  513. ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2p return code\n");
  514. r = try_query( hdb, "CREATE TABLE `a` (`` CHAR(72) NOT NULL PRIMARY KEY `b`)");
  515. ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2p return code\n");
  516. r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY `b`)");
  517. ok(r == ERROR_SUCCESS , "valid query 2z failed\n");
  518. r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY `b`)");
  519. ok(r == ERROR_BAD_QUERY_SYNTAX , "created same table again\n");
  520. r = try_query( hdb, "CREATE TABLE `aa` (`b` CHAR(72) NOT NULL, `c` "
  521. "CHAR(72), `d` CHAR(255) NOT NULL LOCALIZABLE PRIMARY KEY `b`)");
  522. ok(r == ERROR_SUCCESS , "query 4 failed\n");
  523. r = MsiDatabaseCommit( hdb );
  524. ok(r == ERROR_SUCCESS , "Failed to commit database after write\n");
  525. r = try_query( hdb, "CREATE TABLE `blah` (`foo` CHAR(72) NOT NULL "
  526. "PRIMARY KEY `foo`)");
  527. ok(r == ERROR_SUCCESS , "query 4 failed\n");
  528. r = try_insert_query( hdb, "insert into a ( `b` ) VALUES ( ? )");
  529. ok(r == ERROR_SUCCESS , "failed to insert record in db\n");
  530. r = MsiDatabaseCommit( hdb );
  531. ok(r == ERROR_SUCCESS , "Failed to commit database after write\n");
  532. r = try_query( hdb, "CREATE TABLE `boo` (`foo` CHAR(72) NOT NULL "
  533. "PRIMARY KEY `ba`)");
  534. ok(r != ERROR_SUCCESS , "query 5 succeeded\n");
  535. r = try_query( hdb,"CREATE TABLE `bee` (`foo` CHAR(72) NOT NULL )");
  536. ok(r != ERROR_SUCCESS , "query 6 succeeded\n");
  537. r = try_query( hdb, "CREATE TABLE `temp` (`t` CHAR(72) NOT NULL "
  538. "PRIMARY KEY `t`)");
  539. ok(r == ERROR_SUCCESS , "query 7 failed\n");
  540. r = try_query( hdb, "CREATE TABLE `c` (`b` CHAR NOT NULL PRIMARY KEY `b`)");
  541. ok(r == ERROR_SUCCESS , "query 8 failed\n");
  542. r = try_query( hdb, "select * from c");
  543. ok(r == ERROR_SUCCESS , "query failed\n");
  544. r = try_query( hdb, "select * from c where b = 'x");
  545. ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
  546. r = try_query( hdb, "select * from c where b = 'x'");
  547. ok(r == ERROR_SUCCESS, "query failed\n");
  548. r = try_query( hdb, "select * from 'c'");
  549. ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
  550. r = try_query( hdb, "select * from ''");
  551. ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
  552. r = try_query( hdb, "select * from c where b = x");
  553. ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
  554. r = try_query( hdb, "select * from c where b = \"x\"");
  555. ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
  556. r = try_query( hdb, "select * from c where b = 'x'");
  557. ok(r == ERROR_SUCCESS, "query failed\n");
  558. r = try_query( hdb, "select * from c where b = '\"x'");
  559. ok(r == ERROR_SUCCESS, "query failed\n");
  560. if (0) /* FIXME: this query causes trouble with other tests */
  561. {
  562. r = try_query( hdb, "select * from c where b = '\\\'x'");
  563. ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
  564. }
  565. r = try_query( hdb, "select * from 'c'");
  566. ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
  567. r = try_query( hdb, "select `c`.`b` from `c` order by `c`.`order`");
  568. ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %u\n", r );
  569. r = try_query( hdb, "select `c`.b` from `c`");
  570. ok( r == ERROR_SUCCESS, "query failed: %u\n", r );
  571. r = try_query( hdb, "select `c`.`b from `c`");
  572. ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %u\n", r );
  573. r = try_query( hdb, "select `c`.b from `c`");
  574. ok( r == ERROR_SUCCESS, "query failed: %u\n", r );
  575. r = try_query( hdb, "select `c.`b` from `c`");
  576. ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %u\n", r );
  577. r = try_query( hdb, "select c`.`b` from `c`");
  578. ok( r == ERROR_SUCCESS, "query failed: %u\n", r );
  579. r = try_query( hdb, "select c.`b` from `c`");
  580. ok( r == ERROR_SUCCESS, "query failed: %u\n", r );
  581. r = try_query( hdb, "select `c`.`b` from c`");
  582. ok( r == ERROR_SUCCESS, "query failed: %u\n", r );
  583. r = try_query( hdb, "select `c`.`b` from `c");
  584. ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %u\n", r );
  585. r = try_query( hdb, "select `c`.`b` from c");
  586. ok( r == ERROR_SUCCESS, "query failed: %u\n", r );
  587. r = try_query( hdb, "CREATE TABLE `\5a` (`b` CHAR NOT NULL PRIMARY KEY `b`)" );
  588. ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
  589. r = try_query( hdb, "SELECT * FROM \5a" );
  590. ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
  591. r = try_query( hdb, "CREATE TABLE `a\5` (`b` CHAR NOT NULL PRIMARY KEY `b`)" );
  592. ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
  593. r = try_query( hdb, "SELECT * FROM a\5" );
  594. ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
  595. r = try_query( hdb, "CREATE TABLE `-a` (`b` CHAR NOT NULL PRIMARY KEY `b`)" );
  596. ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
  597. r = try_query( hdb, "SELECT * FROM -a" );
  598. todo_wine ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
  599. r = try_query( hdb, "CREATE TABLE `a-` (`b` CHAR NOT NULL PRIMARY KEY `b`)" );
  600. ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
  601. r = try_query( hdb, "SELECT * FROM a-" );
  602. ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
  603. r = MsiCloseHandle( hdb );
  604. ok(r == ERROR_SUCCESS , "Failed to close database transact\n");
  605. r = DeleteFile( msifile );
  606. ok(r == TRUE, "file didn't exist after commit\n");
  607. }
  608. static void test_viewmodify(void)
  609. {
  610. MSIHANDLE hdb = 0, hview = 0, hrec = 0;
  611. UINT r;
  612. MSIDBERROR err;
  613. const char *query;
  614. char buffer[0x100];
  615. DWORD sz;
  616. DeleteFile(msifile);
  617. /* just MsiOpenDatabase should not create a file */
  618. r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
  619. ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
  620. query = "CREATE TABLE `phone` ( "
  621. "`id` INT, `name` CHAR(32), `number` CHAR(32) "
  622. "PRIMARY KEY `id`)";
  623. r = run_query( hdb, 0, query );
  624. ok(r == ERROR_SUCCESS, "query failed\n");
  625. query = "CREATE TABLE `_Validation` ( "
  626. "`Table` CHAR(32) NOT NULL, `Column` CHAR(32) NOT NULL, "
  627. "`Nullable` CHAR(4) NOT NULL, `MinValue` INT, `MaxValue` INT, "
  628. "`KeyTable` CHAR(255), `KeyColumn` SHORT, `Category` CHAR(32), "
  629. "`Set` CHAR(255), `Description` CHAR(255) PRIMARY KEY `Table`, `Column`)";
  630. r = run_query( hdb, 0, query );
  631. ok(r == ERROR_SUCCESS, "query failed\n");
  632. query = "INSERT INTO `_Validation` ( `Table`, `Column`, `Nullable` ) "
  633. "VALUES('phone', 'id', 'N')";
  634. r = run_query( hdb, 0, query );
  635. ok(r == ERROR_SUCCESS, "query failed\n");
  636. /* check what the error function reports without doing anything */
  637. sz = 0;
  638. /* passing NULL as the 3rd param make function to crash on older platforms */
  639. err = MsiViewGetError( 0, NULL, &sz );
  640. ok(err == MSIDBERROR_INVALIDARG, "MsiViewGetError return\n");
  641. /* open a view */
  642. query = "SELECT * FROM `phone`";
  643. r = MsiDatabaseOpenView(hdb, query, &hview);
  644. ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
  645. /* see what happens with a good hview and bad args */
  646. err = MsiViewGetError( hview, NULL, NULL );
  647. ok(err == MSIDBERROR_INVALIDARG || err == MSIDBERROR_NOERROR,
  648. "MsiViewGetError returns %u (expected -3)\n", err);
  649. err = MsiViewGetError( hview, buffer, NULL );
  650. ok(err == MSIDBERROR_INVALIDARG, "MsiViewGetError return\n");
  651. /* see what happens with a zero length buffer */
  652. sz = 0;
  653. buffer[0] = 'x';
  654. err = MsiViewGetError( hview, buffer, &sz );
  655. ok(err == MSIDBERROR_MOREDATA, "MsiViewGetError return\n");
  656. ok(buffer[0] == 'x', "buffer cleared\n");
  657. ok(sz == 0, "size not zero\n");
  658. /* ok this one is strange */
  659. sz = 0;
  660. err = MsiViewGetError( hview, NULL, &sz );
  661. ok(err == MSIDBERROR_NOERROR, "MsiViewGetError return\n");
  662. ok(sz == 0, "size not zero\n");
  663. /* see if it really has an error */
  664. sz = sizeof buffer;
  665. buffer[0] = 'x';
  666. err = MsiViewGetError( hview, buffer, &sz );
  667. ok(err == MSIDBERROR_NOERROR, "MsiViewGetError return\n");
  668. ok(buffer[0] == 0, "buffer not cleared\n");
  669. ok(sz == 0, "size not zero\n");
  670. r = MsiViewExecute(hview, 0);
  671. ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
  672. /* try some invalid records */
  673. r = MsiViewModify(hview, MSIMODIFY_INSERT, 0 );
  674. ok(r == ERROR_INVALID_HANDLE, "MsiViewModify failed\n");
  675. r = MsiViewModify(hview, -1, 0 );
  676. ok(r == ERROR_INVALID_HANDLE, "MsiViewModify failed\n");
  677. /* try an small record */
  678. hrec = MsiCreateRecord(1);
  679. r = MsiViewModify(hview, -1, hrec );
  680. ok(r == ERROR_INVALID_DATA, "MsiViewModify failed\n");
  681. sz = sizeof buffer;
  682. buffer[0] = 'x';
  683. err = MsiViewGetError( hview, buffer, &sz );
  684. ok(err == MSIDBERROR_NOERROR, "MsiViewGetError return\n");
  685. ok(buffer[0] == 0, "buffer not cleared\n");
  686. ok(sz == 0, "size not zero\n");
  687. r = MsiCloseHandle(hrec);
  688. ok(r == ERROR_SUCCESS, "failed to close record\n");
  689. /* insert a valid record */
  690. hrec = MsiCreateRecord(3);
  691. r = MsiRecordSetInteger(hrec, 1, 1);
  692. ok(r == ERROR_SUCCESS, "failed to set integer\n");
  693. r = MsiRecordSetString(hrec, 2, "bob");
  694. ok(r == ERROR_SUCCESS, "failed to set string\n");
  695. r = MsiRecordSetString(hrec, 3, "7654321");
  696. ok(r == ERROR_SUCCESS, "failed to set string\n");
  697. r = MsiViewExecute(hview, 0);
  698. ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
  699. r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec );
  700. ok(r == ERROR_SUCCESS, "MsiViewModify failed\n");
  701. /* validate it */
  702. r = MsiViewExecute(hview, 0);
  703. ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
  704. r = MsiViewModify(hview, MSIMODIFY_VALIDATE_NEW, hrec );
  705. ok(r == ERROR_INVALID_DATA, "MsiViewModify failed %u\n", r);
  706. sz = sizeof buffer;
  707. buffer[0] = 'x';
  708. err = MsiViewGetError( hview, buffer, &sz );
  709. ok(err == MSIDBERROR_DUPLICATEKEY, "MsiViewGetError returned %u\n", err);
  710. ok(!strcmp(buffer, "id"), "expected \"id\" c, got \"%s\"\n", buffer);
  711. ok(sz == 2, "size not 2\n");
  712. /* insert the same thing again */
  713. r = MsiViewExecute(hview, 0);
  714. ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
  715. /* should fail ... */
  716. r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec );
  717. ok(r == ERROR_FUNCTION_FAILED, "MsiViewModify failed\n");
  718. /* try to merge the same record */
  719. r = MsiViewExecute(hview, 0);
  720. ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
  721. r = MsiViewModify(hview, MSIMODIFY_MERGE, hrec );
  722. ok(r == ERROR_SUCCESS, "MsiViewModify failed\n");
  723. r = MsiCloseHandle(hrec);
  724. ok(r == ERROR_SUCCESS, "failed to close record\n");
  725. /* try merging a new record */
  726. hrec = MsiCreateRecord(3);
  727. r = MsiRecordSetInteger(hrec, 1, 10);
  728. ok(r == ERROR_SUCCESS, "failed to set integer\n");
  729. r = MsiRecordSetString(hrec, 2, "pepe");
  730. ok(r == ERROR_SUCCESS, "failed to set string\n");
  731. r = MsiRecordSetString(hrec, 3, "7654321");
  732. ok(r == ERROR_SUCCESS, "failed to set string\n");
  733. r = MsiViewModify(hview, MSIMODIFY_MERGE, hrec );
  734. ok(r == ERROR_SUCCESS, "MsiViewModify failed\n");
  735. r = MsiViewExecute(hview, 0);
  736. ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
  737. r = MsiCloseHandle(hrec);
  738. ok(r == ERROR_SUCCESS, "failed to close record\n");
  739. r = MsiViewClose(hview);
  740. ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
  741. r = MsiCloseHandle(hview);
  742. ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
  743. query = "SELECT * FROM `phone`";
  744. r = MsiDatabaseOpenView(hdb, query, &hview);
  745. ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
  746. r = MsiViewExecute(hview, 0);
  747. ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
  748. r = MsiViewFetch(hview, &hrec);
  749. ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
  750. r = MsiRecordGetInteger(hrec, 1);
  751. ok(r == 1, "Expected 1, got %d\n", r);
  752. sz = sizeof(buffer);
  753. r = MsiRecordGetString(hrec, 2, buffer, &sz);
  754. ok(r == ERROR_SUCCESS, "MsiRecordGetString failed\n");
  755. ok(!lstrcmp(buffer, "bob"), "Expected bob, got %s\n", buffer);
  756. sz = sizeof(buffer);
  757. r = MsiRecordGetString(hrec, 3, buffer, &sz);
  758. ok(r == ERROR_SUCCESS, "MsiRecordGetString failed\n");
  759. ok(!lstrcmp(buffer, "7654321"), "Expected 7654321, got %s\n", buffer);
  760. /* update the view, non-primary key */
  761. r = MsiRecordSetString(hrec, 3, "3141592");
  762. ok(r == ERROR_SUCCESS, "MsiRecordSetString failed\n");
  763. r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
  764. ok(r == ERROR_SUCCESS, "MsiViewModify failed\n");
  765. /* do it again */
  766. r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
  767. ok(r == ERROR_SUCCESS, "MsiViewModify failed: %d\n", r);
  768. /* update the view, primary key */
  769. r = MsiRecordSetInteger(hrec, 1, 5);
  770. ok(r == ERROR_SUCCESS, "MsiRecordSetInteger failed\n");
  771. r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
  772. ok(r == ERROR_FUNCTION_FAILED, "MsiViewModify failed\n");
  773. r = MsiCloseHandle(hrec);
  774. ok(r == ERROR_SUCCESS, "failed to close record\n");
  775. r = MsiViewClose(hview);
  776. ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
  777. r = MsiCloseHandle(hview);
  778. ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
  779. query = "SELECT * FROM `phone`";
  780. r = MsiDatabaseOpenView(hdb, query, &hview);
  781. ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
  782. r = MsiViewExecute(hview, 0);
  783. ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
  784. r = MsiViewFetch(hview, &hrec);
  785. ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
  786. r = MsiRecordGetInteger(hrec, 1);
  787. ok(r == 1, "Expected 1, got %d\n", r);
  788. sz = sizeof(buffer);
  789. r = MsiRecordGetString(hrec, 2, buffer, &sz);
  790. ok(r == ERROR_SUCCESS, "MsiRecordGetString failed\n");
  791. ok(!lstrcmp(buffer, "bob"), "Expected bob, got %s\n", buffer);
  792. sz = sizeof(buffer);
  793. r = MsiRecordGetString(hrec, 3, buffer, &sz);
  794. ok(r == ERROR_SUCCESS, "MsiRecordGetString failed\n");
  795. ok(!lstrcmp(buffer, "3141592"), "Expected 3141592, got %s\n", buffer);
  796. r = MsiCloseHandle(hrec);
  797. ok(r == ERROR_SUCCESS, "failed to close record\n");
  798. /* use a record that doesn't come from a view fetch */
  799. hrec = MsiCreateRecord(3);
  800. ok(hrec != 0, "MsiCreateRecord failed\n");
  801. r = MsiRecordSetInteger(hrec, 1, 3);
  802. ok(r == ERROR_SUCCESS, "failed to set integer\n");
  803. r = MsiRecordSetString(hrec, 2, "jane");
  804. ok(r == ERROR_SUCCESS, "failed to set string\n");
  805. r = MsiRecordSetString(hrec, 3, "112358");
  806. ok(r == ERROR_SUCCESS, "failed to set string\n");
  807. r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
  808. ok(r == ERROR_FUNCTION_FAILED, "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
  809. r = MsiCloseHandle(hrec);
  810. ok(r == ERROR_SUCCESS, "failed to close record\n");
  811. /* use a record that doesn't come from a view fetch, primary key matches */
  812. hrec = MsiCreateRecord(3);
  813. ok(hrec != 0, "MsiCreateRecord failed\n");
  814. r = MsiRecordSetInteger(hrec, 1, 1);
  815. ok(r == ERROR_SUCCESS, "failed to set integer\n");
  816. r = MsiRecordSetString(hrec, 2, "jane");
  817. ok(r == ERROR_SUCCESS, "failed to set string\n");
  818. r = MsiRecordSetString(hrec, 3, "112358");
  819. ok(r == ERROR_SUCCESS, "failed to set string\n");
  820. r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
  821. ok(r == ERROR_FUNCTION_FAILED, "MsiViewModify failed\n");
  822. r = MsiCloseHandle(hrec);
  823. ok(r == ERROR_SUCCESS, "failed to close record\n");
  824. hrec = MsiCreateRecord(3);
  825. r = MsiRecordSetInteger(hrec, 1, 2);
  826. ok(r == ERROR_SUCCESS, "failed to set integer\n");
  827. r = MsiRecordSetString(hrec, 2, "nick");
  828. ok(r == ERROR_SUCCESS, "failed to set string\n");
  829. r = MsiRecordSetString(hrec, 3, "141421");
  830. ok(r == ERROR_SUCCESS, "failed to set string\n");
  831. r = MsiViewExecute(hview, 0);
  832. ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
  833. r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec );
  834. ok(r == ERROR_SUCCESS, "MsiViewModify failed\n");
  835. r = MsiCloseHandle(hrec);
  836. ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
  837. r = MsiViewClose(hview);
  838. ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
  839. r = MsiCloseHandle(hview);
  840. ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
  841. query = "SELECT * FROM `phone` WHERE `id` = 1";
  842. r = MsiDatabaseOpenView(hdb, query, &hview);
  843. ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
  844. r = MsiViewExecute(hview, 0);
  845. ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
  846. r = MsiViewFetch(hview, &hrec);
  847. ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
  848. /* change the id to match the second row */
  849. r = MsiRecordSetInteger(hrec, 1, 2);
  850. ok(r == ERROR_SUCCESS, "failed to set integer\n");
  851. r = MsiRecordSetString(hrec, 2, "jerry");
  852. ok(r == ERROR_SUCCESS, "failed to set string\n");
  853. r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
  854. ok(r == ERROR_FUNCTION_FAILED, "MsiViewModify failed\n");
  855. r = MsiCloseHandle(hrec);
  856. ok(r == ERROR_SUCCESS, "failed to close record\n");
  857. r = MsiViewClose(hview);
  858. ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
  859. r = MsiCloseHandle(hview);
  860. ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
  861. /* broader search */
  862. query = "SELECT * FROM `phone` ORDER BY `id`";
  863. r = MsiDatabaseOpenView(hdb, query, &hview);
  864. ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
  865. r = MsiViewExecute(hview, 0);
  866. ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
  867. r = MsiViewFetch(hview, &hrec);
  868. ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
  869. /* change the id to match the second row */
  870. r = MsiRecordSetInteger(hrec, 1, 2);
  871. ok(r == ERROR_SUCCESS, "failed to set integer\n");
  872. r = MsiRecordSetString(hrec, 2, "jerry");
  873. ok(r == ERROR_SUCCESS, "failed to set string\n");
  874. r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
  875. ok(r == ERROR_FUNCTION_FAILED, "MsiViewModify failed\n");
  876. r = MsiCloseHandle(hrec);
  877. ok(r == ERROR_SUCCESS, "failed to close record\n");
  878. r = MsiViewClose(hview);
  879. ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
  880. r = MsiCloseHandle(hview);
  881. ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
  882. r = MsiCloseHandle( hdb );
  883. ok(r == ERROR_SUCCESS, "MsiOpenDatabase close failed\n");
  884. }
  885. static MSIHANDLE create_db(void)
  886. {
  887. MSIHANDLE hdb = 0;
  888. UINT res;
  889. DeleteFile(msifile);
  890. /* create an empty database */
  891. res = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb );
  892. ok( res == ERROR_SUCCESS , "Failed to create database\n" );
  893. if( res != ERROR_SUCCESS )
  894. return hdb;
  895. res = MsiDatabaseCommit( hdb );
  896. ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
  897. return hdb;
  898. }
  899. static void test_getcolinfo(void)
  900. {
  901. MSIHANDLE hdb, hview = 0, rec = 0;
  902. UINT r;
  903. DWORD sz;
  904. char buffer[0x20];
  905. /* create an empty db */
  906. hdb = create_db();
  907. ok( hdb, "failed to create db\n");
  908. /* tables should be present */
  909. r = MsiDatabaseOpenView(hdb, "select * from _Tables", &hview);
  910. ok( r == ERROR_SUCCESS, "failed to open query\n");
  911. r = MsiViewExecute(hview, 0);
  912. ok( r == ERROR_SUCCESS, "failed to execute query\n");
  913. /* check that NAMES works */
  914. rec = 0;
  915. r = MsiViewGetColumnInfo( hview, MSICOLINFO_NAMES, &rec );
  916. ok( r == ERROR_SUCCESS, "failed to get names\n");
  917. sz = sizeof buffer;
  918. r = MsiRecordGetString(rec, 1, buffer, &sz );
  919. ok( r == ERROR_SUCCESS, "failed to get string\n");
  920. ok( !strcmp(buffer,"Name"), "_Tables has wrong column name\n");
  921. r = MsiCloseHandle( rec );
  922. ok( r == ERROR_SUCCESS, "failed to close record handle\n");
  923. /* check that TYPES works */
  924. rec = 0;
  925. r = MsiViewGetColumnInfo( hview, MSICOLINFO_TYPES, &rec );
  926. ok( r == ERROR_SUCCESS, "failed to get names\n");
  927. sz = sizeof buffer;
  928. r = MsiRecordGetString(rec, 1, buffer, &sz );
  929. ok( r == ERROR_SUCCESS, "failed to get string\n");
  930. ok( !strcmp(buffer,"s64"), "_Tables has wrong column type\n");
  931. r = MsiCloseHandle( rec );
  932. ok( r == ERROR_SUCCESS, "failed to close record handle\n");
  933. /* check that invalid values fail */
  934. rec = 0;
  935. r = MsiViewGetColumnInfo( hview, 100, &rec );
  936. ok( r == ERROR_INVALID_PARAMETER, "wrong error code\n");
  937. ok( rec == 0, "returned a record\n");
  938. r = MsiViewGetColumnInfo( hview, MSICOLINFO_TYPES, NULL );
  939. ok( r == ERROR_INVALID_PARAMETER, "wrong error code\n");
  940. r = MsiViewGetColumnInfo( 0, MSICOLINFO_TYPES, &rec );
  941. ok( r == ERROR_INVALID_HANDLE, "wrong error code\n");
  942. r = MsiViewClose(hview);
  943. ok( r == ERROR_SUCCESS, "failed to close view\n");
  944. r = MsiCloseHandle(hview);
  945. ok( r == ERROR_SUCCESS, "failed to close view handle\n");
  946. r = MsiCloseHandle(hdb);
  947. ok( r == ERROR_SUCCESS, "failed to close database\n");
  948. }
  949. static MSIHANDLE get_column_info(MSIHANDLE hdb, const char *query, MSICOLINFO type)
  950. {
  951. MSIHANDLE hview = 0, rec = 0;
  952. UINT r;
  953. r = MsiDatabaseOpenView(hdb, query, &hview);
  954. if( r != ERROR_SUCCESS )
  955. return r;
  956. r = MsiViewExecute(hview, 0);
  957. if( r == ERROR_SUCCESS )
  958. {
  959. MsiViewGetColumnInfo( hview, type, &rec );
  960. }
  961. MsiViewClose(hview);
  962. MsiCloseHandle(hview);
  963. return rec;
  964. }
  965. static UINT get_columns_table_type(MSIHANDLE hdb, const char *table, UINT field)
  966. {
  967. MSIHANDLE hview = 0, rec = 0;
  968. UINT r, type = 0;
  969. char query[0x100];
  970. sprintf(query, "select * from `_Columns` where `Table` = '%s'", table );
  971. r = MsiDatabaseOpenView(hdb, query, &hview);
  972. if( r != ERROR_SUCCESS )
  973. return r;
  974. r = MsiViewExecute(hview, 0);
  975. if( r == ERROR_SUCCESS )
  976. {
  977. while (1)
  978. {
  979. r = MsiViewFetch( hview, &rec );
  980. if( r != ERROR_SUCCESS)
  981. break;
  982. r = MsiRecordGetInteger( rec, 2 );
  983. if (r == field)
  984. type = MsiRecordGetInteger( rec, 4 );
  985. MsiCloseHandle( rec );
  986. }
  987. }
  988. MsiViewClose(hview);
  989. MsiCloseHandle(hview);
  990. return type;
  991. }
  992. static BOOL check_record( MSIHANDLE rec, UINT field, LPCSTR val )
  993. {
  994. CHAR buffer[0x20];
  995. UINT r;
  996. DWORD sz;
  997. sz = sizeof buffer;
  998. r = MsiRecordGetString( rec, field, buffer, &sz );
  999. return (r == ERROR_SUCCESS ) && !strcmp(val, buffer);
  1000. }
  1001. static void test_viewgetcolumninfo(void)
  1002. {
  1003. MSIHANDLE hdb = 0, rec;
  1004. UINT r;
  1005. hdb = create_db();
  1006. ok( hdb, "failed to create db\n");
  1007. r = run_query( hdb, 0,
  1008. "CREATE TABLE `Properties` "
  1009. "( `Property` CHAR(255), "
  1010. " `Value` CHAR(1), "
  1011. " `Intvalue` INT, "
  1012. " `Integervalue` INTEGER, "
  1013. " `Shortvalue` SHORT, "
  1014. " `Longvalue` LONG, "
  1015. " `Longcharvalue` LONGCHAR "
  1016. " PRIMARY KEY `Property`)" );
  1017. ok( r == ERROR_SUCCESS , "Failed to create table\n" );
  1018. /* check the column types */
  1019. rec = get_column_info( hdb, "select * from `Properties`", MSICOLINFO_TYPES );
  1020. ok( rec, "failed to get column info record\n" );
  1021. ok( check_record( rec, 1, "S255"), "wrong record type\n");
  1022. ok( check_record( rec, 2, "S1"), "wrong record type\n");
  1023. ok( check_record( rec, 3, "I2"), "wrong record type\n");
  1024. ok( check_record( rec, 4, "I2"), "wrong record type\n");
  1025. ok( check_record( rec, 5, "I2"), "wrong record type\n");
  1026. ok( check_record( rec, 6, "I4"), "wrong record type\n");
  1027. ok( check_record( rec, 7, "S0"), "wrong record type\n");
  1028. MsiCloseHandle( rec );
  1029. /* check the type in _Columns */
  1030. ok( 0x3dff == get_columns_table_type(hdb, "Properties", 1 ), "_columns table wrong\n");
  1031. ok( 0x1d01 == get_columns_table_type(hdb, "Properties", 2 ), "_columns table wrong\n");
  1032. ok( 0x1502 == get_columns_table_type(hdb, "Properties", 3 ), "_columns table wrong\n");
  1033. ok( 0x1502 == get_columns_table_type(hdb, "Properties", 4 ), "_columns table wrong\n");
  1034. ok( 0x1502 == get_columns_table_type(hdb, "Properties", 5 ), "_columns table wrong\n");
  1035. ok( 0x1104 == get_columns_table_type(hdb, "Properties", 6 ), "_columns table wrong\n");
  1036. ok( 0x1d00 == get_columns_table_type(hdb, "Properties", 7 ), "_columns table wrong\n");
  1037. /* now try the names */
  1038. rec = get_column_info( hdb, "select * from `Properties`", MSICOLINFO_NAMES );
  1039. ok( rec, "failed to get column info record\n" );
  1040. ok( check_record( rec, 1, "Property"), "wrong record type\n");
  1041. ok( check_record( rec, 2, "Value"), "wrong record type\n");
  1042. ok( check_record( rec, 3, "Intvalue"), "wrong record type\n");
  1043. ok( check_record( rec, 4, "Integervalue"), "wrong record type\n");
  1044. ok( check_record( rec, 5, "Shortvalue"), "wrong record type\n");
  1045. ok( check_record( rec, 6, "Longvalue"), "wrong record type\n");
  1046. ok( check_record( rec, 7, "Longcharvalue"), "wrong record type\n");
  1047. MsiCloseHandle( rec );
  1048. r = run_query( hdb, 0,
  1049. "CREATE TABLE `Binary` "
  1050. "( `Name` CHAR(255), `Data` OBJECT PRIMARY KEY `Name`)" );
  1051. ok( r == ERROR_SUCCESS , "Failed to create table\n" );
  1052. /* check the column types */
  1053. rec = get_column_info( hdb, "select * from `Binary`", MSICOLINFO_TYPES );
  1054. ok( rec, "failed to get column info record\n" );
  1055. ok( check_record( rec, 1, "S255"), "wrong record type\n");
  1056. ok( check_record( rec, 2, "V0"), "wrong record type\n");
  1057. MsiCloseHandle( rec );
  1058. /* check the type in _Columns */
  1059. ok( 0x3dff == get_columns_table_type(hdb, "Binary", 1 ), "_columns table wrong\n");
  1060. ok( 0x1900 == get_columns_table_type(hdb, "Binary", 2 ), "_columns table wrong\n");
  1061. /* now try the names */
  1062. rec = get_column_info( hdb, "select * from `Binary`", MSICOLINFO_NAMES );
  1063. ok( rec, "failed to get column info record\n" );
  1064. ok( check_record( rec, 1, "Name"), "wrong record type\n");
  1065. ok( check_record( rec, 2, "Data"), "wrong record type\n");
  1066. MsiCloseHandle( rec );
  1067. r = run_query( hdb, 0,
  1068. "CREATE TABLE `UIText` "
  1069. "( `Key` CHAR(72) NOT NULL, `Text` CHAR(255) LOCALIZABLE PRIMARY KEY `Key`)" );
  1070. ok( r == ERROR_SUCCESS , "Failed to create table\n" );
  1071. ok( 0x2d48 == get_columns_table_type(hdb, "UIText", 1 ), "_columns table wrong\n");
  1072. ok( 0x1fff == get_columns_table_type(hdb, "UIText", 2 ), "_columns table wrong\n");
  1073. rec = get_column_info( hdb, "select * from `UIText`", MSICOLINFO_NAMES );
  1074. ok( rec, "failed to get column info record\n" );
  1075. ok( check_record( rec, 1, "Key"), "wrong record type\n");
  1076. ok( check_record( rec, 2, "Text"), "wrong record type\n");
  1077. MsiCloseHandle( rec );
  1078. rec = get_column_info( hdb, "select * from `UIText`", MSICOLINFO_TYPES );
  1079. ok( rec, "failed to get column info record\n" );
  1080. ok( check_record( rec, 1, "s72"), "wrong record type\n");
  1081. ok( check_record( rec, 2, "L255"), "wrong record type\n");
  1082. MsiCloseHandle( rec );
  1083. MsiCloseHandle( hdb );
  1084. }
  1085. static void test_msiexport(void)
  1086. {
  1087. MSIHANDLE hdb = 0, hview = 0;
  1088. UINT r;
  1089. const char *query;
  1090. char path[MAX_PATH];
  1091. const char file[] = "phone.txt";
  1092. HANDLE handle;
  1093. char buffer[0x100];
  1094. DWORD length;
  1095. const char expected[] =
  1096. "id\tname\tnumber\r\n"
  1097. "I2\tS32\tS32\r\n"
  1098. "phone\tid\r\n"
  1099. "1\tAbe\t8675309\r\n";
  1100. DeleteFile(msifile);
  1101. /* just MsiOpenDatabase should not create a file */
  1102. r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
  1103. ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
  1104. /* create a table */
  1105. query = "CREATE TABLE `phone` ( "
  1106. "`id` INT, `name` CHAR(32), `number` CHAR(32) "
  1107. "PRIMARY KEY `id`)";
  1108. r = MsiDatabaseOpenView(hdb, query, &hview);
  1109. ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
  1110. r = MsiViewExecute(hview, 0);
  1111. ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
  1112. r = MsiViewClose

Large files files are truncated, but you can click here to view the full file