-sync msi_winetest with wine 1.1.32
[reactos.git] / rostests / winetests / msi / db.c
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
21 #define COBJMACROS
22
23 #include <stdio.h>
24
25 #include <windows.h>
26 #include <msi.h>
27 #include <msidefs.h>
28 #include <msiquery.h>
29
30 #include <objidl.h>
31
32 #include "wine/test.h"
33
34 static const char *msifile = "winetest.msi";
35 static const char *msifile2 = "winetst2.msi";
36 static const char *mstfile = "winetst.mst";
37
38 static void test_msidatabase(void)
39 {
40 MSIHANDLE hdb = 0, hdb2 = 0;
41 UINT res;
42
43 DeleteFile(msifile);
44
45 res = MsiOpenDatabase( msifile, msifile2, &hdb );
46 ok( res == ERROR_OPEN_FAILED, "expected failure\n");
47
48 res = MsiOpenDatabase( msifile, (LPSTR) 0xff, &hdb );
49 ok( res == ERROR_INVALID_PARAMETER, "expected failure\n");
50
51 res = MsiCloseHandle( hdb );
52 ok( res == ERROR_SUCCESS , "Failed to close database\n" );
53
54 /* create an empty database */
55 res = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb );
56 ok( res == ERROR_SUCCESS , "Failed to create database\n" );
57
58 res = MsiDatabaseCommit( hdb );
59 ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
60
61 ok( INVALID_FILE_ATTRIBUTES != GetFileAttributes( msifile ), "database should exist\n");
62
63 res = MsiCloseHandle( hdb );
64 ok( res == ERROR_SUCCESS , "Failed to close database\n" );
65 res = MsiOpenDatabase( msifile, msifile2, &hdb2 );
66 ok( res == ERROR_SUCCESS , "Failed to open database\n" );
67
68 ok( INVALID_FILE_ATTRIBUTES != GetFileAttributes( msifile2 ), "database should exist\n");
69
70 res = MsiDatabaseCommit( hdb2 );
71 ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
72
73 res = MsiCloseHandle( hdb2 );
74 ok( res == ERROR_SUCCESS , "Failed to close database\n" );
75
76 res = MsiOpenDatabase( msifile, msifile2, &hdb2 );
77 ok( res == ERROR_SUCCESS , "Failed to open database\n" );
78
79 res = MsiCloseHandle( hdb2 );
80 ok( res == ERROR_SUCCESS , "Failed to close database\n" );
81
82 ok( INVALID_FILE_ATTRIBUTES == GetFileAttributes( msifile2 ), "uncommitted database should not exist\n");
83
84 res = MsiOpenDatabase( msifile, msifile2, &hdb2 );
85 ok( res == ERROR_SUCCESS , "Failed to close database\n" );
86
87 res = MsiDatabaseCommit( hdb2 );
88 ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
89
90 res = MsiCloseHandle( hdb2 );
91 ok( res == ERROR_SUCCESS , "Failed to close database\n" );
92
93 ok( INVALID_FILE_ATTRIBUTES != GetFileAttributes( msifile2 ), "committed database should exist\n");
94
95 res = MsiOpenDatabase( msifile, MSIDBOPEN_READONLY, &hdb );
96 ok( res == ERROR_SUCCESS , "Failed to open database\n" );
97
98 res = MsiCloseHandle( hdb );
99 ok( res == ERROR_SUCCESS , "Failed to close database\n" );
100
101 res = MsiOpenDatabase( msifile, MSIDBOPEN_DIRECT, &hdb );
102 ok( res == ERROR_SUCCESS , "Failed to open database\n" );
103
104 res = MsiCloseHandle( hdb );
105 ok( res == ERROR_SUCCESS , "Failed to close database\n" );
106
107 res = MsiOpenDatabase( msifile, MSIDBOPEN_TRANSACT, &hdb );
108 ok( res == ERROR_SUCCESS , "Failed to open database\n" );
109
110 res = MsiCloseHandle( hdb );
111 ok( res == ERROR_SUCCESS , "Failed to close database\n" );
112 ok( INVALID_FILE_ATTRIBUTES != GetFileAttributes( msifile ), "database should exist\n");
113
114 /* MSIDBOPEN_CREATE deletes the database if MsiCommitDatabase isn't called */
115 res = MsiOpenDatabase( msifile, MSIDBOPEN_CREATE, &hdb );
116 ok( res == ERROR_SUCCESS , "Failed to open database\n" );
117
118 ok( INVALID_FILE_ATTRIBUTES != GetFileAttributes( msifile ), "database should exist\n");
119
120 res = MsiCloseHandle( hdb );
121 ok( res == ERROR_SUCCESS , "Failed to close database\n" );
122
123 ok( INVALID_FILE_ATTRIBUTES == GetFileAttributes( msifile ), "database should exist\n");
124
125 res = MsiOpenDatabase( msifile, MSIDBOPEN_CREATE, &hdb );
126 ok( res == ERROR_SUCCESS , "Failed to open database\n" );
127
128 res = MsiDatabaseCommit( hdb );
129 ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
130
131 ok( INVALID_FILE_ATTRIBUTES != GetFileAttributes( msifile ), "database should exist\n");
132
133 res = MsiCloseHandle( hdb );
134 ok( res == ERROR_SUCCESS , "Failed to close database\n" );
135
136 res = DeleteFile( msifile2 );
137 ok( res == TRUE, "Failed to delete database\n" );
138
139 res = DeleteFile( msifile );
140 ok( res == TRUE, "Failed to delete database\n" );
141 }
142
143 static UINT do_query(MSIHANDLE hdb, const char *query, MSIHANDLE *phrec)
144 {
145 MSIHANDLE hview = 0;
146 UINT r, ret;
147
148 if (phrec)
149 *phrec = 0;
150
151 /* open a select query */
152 r = MsiDatabaseOpenView(hdb, query, &hview);
153 if (r != ERROR_SUCCESS)
154 return r;
155 r = MsiViewExecute(hview, 0);
156 if (r != ERROR_SUCCESS)
157 return r;
158 ret = MsiViewFetch(hview, phrec);
159 r = MsiViewClose(hview);
160 if (r != ERROR_SUCCESS)
161 return r;
162 r = MsiCloseHandle(hview);
163 if (r != ERROR_SUCCESS)
164 return r;
165 return ret;
166 }
167
168 static UINT run_query( MSIHANDLE hdb, MSIHANDLE hrec, const char *query )
169 {
170 MSIHANDLE hview = 0;
171 UINT r;
172
173 r = MsiDatabaseOpenView(hdb, query, &hview);
174 if( r != ERROR_SUCCESS )
175 return r;
176
177 r = MsiViewExecute(hview, hrec);
178 if( r == ERROR_SUCCESS )
179 r = MsiViewClose(hview);
180 MsiCloseHandle(hview);
181 return r;
182 }
183
184 static UINT create_component_table( MSIHANDLE hdb )
185 {
186 return run_query( hdb, 0,
187 "CREATE TABLE `Component` ( "
188 "`Component` CHAR(72) NOT NULL, "
189 "`ComponentId` CHAR(38), "
190 "`Directory_` CHAR(72) NOT NULL, "
191 "`Attributes` SHORT NOT NULL, "
192 "`Condition` CHAR(255), "
193 "`KeyPath` CHAR(72) "
194 "PRIMARY KEY `Component`)" );
195 }
196
197 static UINT create_custom_action_table( MSIHANDLE hdb )
198 {
199 return run_query( hdb, 0,
200 "CREATE TABLE `CustomAction` ( "
201 "`Action` CHAR(72) NOT NULL, "
202 "`Type` SHORT NOT NULL, "
203 "`Source` CHAR(72), "
204 "`Target` CHAR(255) "
205 "PRIMARY KEY `Action`)" );
206 }
207
208 static UINT create_directory_table( MSIHANDLE hdb )
209 {
210 return run_query( hdb, 0,
211 "CREATE TABLE `Directory` ( "
212 "`Directory` CHAR(255) NOT NULL, "
213 "`Directory_Parent` CHAR(255), "
214 "`DefaultDir` CHAR(255) NOT NULL "
215 "PRIMARY KEY `Directory`)" );
216 }
217
218 static UINT create_feature_components_table( MSIHANDLE hdb )
219 {
220 return run_query( hdb, 0,
221 "CREATE TABLE `FeatureComponents` ( "
222 "`Feature_` CHAR(38) NOT NULL, "
223 "`Component_` CHAR(72) NOT NULL "
224 "PRIMARY KEY `Feature_`, `Component_` )" );
225 }
226
227 static UINT create_std_dlls_table( MSIHANDLE hdb )
228 {
229 return run_query( hdb, 0,
230 "CREATE TABLE `StdDlls` ( "
231 "`File` CHAR(255) NOT NULL, "
232 "`Binary_` CHAR(72) NOT NULL "
233 "PRIMARY KEY `File` )" );
234 }
235
236 static UINT create_binary_table( MSIHANDLE hdb )
237 {
238 return run_query( hdb, 0,
239 "CREATE TABLE `Binary` ( "
240 "`Name` CHAR(72) NOT NULL, "
241 "`Data` CHAR(72) NOT NULL "
242 "PRIMARY KEY `Name` )" );
243 }
244
245 #define make_add_entry(type, qtext) \
246 static UINT add##_##type##_##entry( MSIHANDLE hdb, const char *values ) \
247 { \
248 char insert[] = qtext; \
249 char *query; \
250 UINT sz, r; \
251 sz = strlen(values) + sizeof insert; \
252 query = HeapAlloc(GetProcessHeap(),0,sz); \
253 sprintf(query,insert,values); \
254 r = run_query( hdb, 0, query ); \
255 HeapFree(GetProcessHeap(), 0, query); \
256 return r; \
257 }
258
259 make_add_entry(component,
260 "INSERT INTO `Component` "
261 "(`Component`, `ComponentId`, `Directory_`, "
262 "`Attributes`, `Condition`, `KeyPath`) VALUES( %s )")
263
264 make_add_entry(custom_action,
265 "INSERT INTO `CustomAction` "
266 "(`Action`, `Type`, `Source`, `Target`) VALUES( %s )")
267
268 make_add_entry(feature_components,
269 "INSERT INTO `FeatureComponents` "
270 "(`Feature_`, `Component_`) VALUES( %s )")
271
272 make_add_entry(std_dlls,
273 "INSERT INTO `StdDlls` (`File`, `Binary_`) VALUES( %s )")
274
275 make_add_entry(binary,
276 "INSERT INTO `Binary` (`Name`, `Data`) VALUES( %s )")
277
278 static void test_msiinsert(void)
279 {
280 MSIHANDLE hdb = 0, hview = 0, hrec = 0;
281 UINT r;
282 const char *query;
283 char buf[80];
284 DWORD sz;
285
286 DeleteFile(msifile);
287
288 /* just MsiOpenDatabase should not create a file */
289 r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
290 ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
291
292 /* create a table */
293 query = "CREATE TABLE `phone` ( "
294 "`id` INT, `name` CHAR(32), `number` CHAR(32) "
295 "PRIMARY KEY `id`)";
296 r = MsiDatabaseOpenView(hdb, query, &hview);
297 ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
298 r = MsiViewExecute(hview, 0);
299 ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
300 r = MsiViewClose(hview);
301 ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
302 r = MsiCloseHandle(hview);
303 ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
304
305 /* insert a value into it */
306 query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
307 "VALUES('1', 'Abe', '8675309')";
308 r = MsiDatabaseOpenView(hdb, query, &hview);
309 ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
310 r = MsiViewExecute(hview, 0);
311 ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
312 r = MsiViewClose(hview);
313 ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
314 r = MsiCloseHandle(hview);
315 ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
316
317 query = "SELECT * FROM `phone` WHERE `id` = 1";
318 r = do_query(hdb, query, &hrec);
319 ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
320
321 /* check the record contains what we put in it */
322 r = MsiRecordGetFieldCount(hrec);
323 ok(r == 3, "record count wrong\n");
324
325 r = MsiRecordIsNull(hrec, 0);
326 ok(r == FALSE, "field 0 not null\n");
327
328 r = MsiRecordGetInteger(hrec, 1);
329 ok(r == 1, "field 1 contents wrong\n");
330 sz = sizeof buf;
331 r = MsiRecordGetString(hrec, 2, buf, &sz);
332 ok(r == ERROR_SUCCESS, "field 2 content fetch failed\n");
333 ok(!strcmp(buf,"Abe"), "field 2 content incorrect\n");
334 sz = sizeof buf;
335 r = MsiRecordGetString(hrec, 3, buf, &sz);
336 ok(r == ERROR_SUCCESS, "field 3 content fetch failed\n");
337 ok(!strcmp(buf,"8675309"), "field 3 content incorrect\n");
338
339 r = MsiCloseHandle(hrec);
340 ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
341
342 /* open a select query */
343 hrec = 100;
344 query = "SELECT * FROM `phone` WHERE `id` >= 10";
345 r = do_query(hdb, query, &hrec);
346 ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch failed\n");
347 ok(hrec == 0, "hrec should be null\n");
348
349 r = MsiCloseHandle(hrec);
350 ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
351
352 query = "SELECT * FROM `phone` WHERE `id` < 0";
353 r = do_query(hdb, query, &hrec);
354 ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch failed\n");
355
356 query = "SELECT * FROM `phone` WHERE `id` <= 0";
357 r = do_query(hdb, query, &hrec);
358 ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch failed\n");
359
360 query = "SELECT * FROM `phone` WHERE `id` <> 1";
361 r = do_query(hdb, query, &hrec);
362 ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch failed\n");
363
364 query = "SELECT * FROM `phone` WHERE `id` > 10";
365 r = do_query(hdb, query, &hrec);
366 ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch failed\n");
367
368 /* now try a few bad INSERT xqueries */
369 query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
370 "VALUES(?, ?)";
371 r = MsiDatabaseOpenView(hdb, query, &hview);
372 ok(r == ERROR_BAD_QUERY_SYNTAX, "MsiDatabaseOpenView failed\n");
373
374 /* construct a record to insert */
375 hrec = MsiCreateRecord(4);
376 r = MsiRecordSetInteger(hrec, 1, 2);
377 ok(r == ERROR_SUCCESS, "MsiRecordSetInteger failed\n");
378 r = MsiRecordSetString(hrec, 2, "Adam");
379 ok(r == ERROR_SUCCESS, "MsiRecordSetString failed\n");
380 r = MsiRecordSetString(hrec, 3, "96905305");
381 ok(r == ERROR_SUCCESS, "MsiRecordSetString failed\n");
382
383 /* insert another value, using a record and wildcards */
384 query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
385 "VALUES(?, ?, ?)";
386 r = MsiDatabaseOpenView(hdb, query, &hview);
387 ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
388
389 if (r == ERROR_SUCCESS)
390 {
391 r = MsiViewExecute(hview, hrec);
392 ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
393 r = MsiViewClose(hview);
394 ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
395 r = MsiCloseHandle(hview);
396 ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
397 }
398 r = MsiCloseHandle(hrec);
399 ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
400
401 r = MsiViewFetch(0, NULL);
402 ok(r == ERROR_INVALID_PARAMETER, "MsiViewFetch failed\n");
403
404 r = MsiDatabaseCommit(hdb);
405 ok(r == ERROR_SUCCESS, "MsiDatabaseCommit failed\n");
406
407 r = MsiCloseHandle(hdb);
408 ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
409
410 r = DeleteFile(msifile);
411 ok(r == TRUE, "file didn't exist after commit\n");
412 }
413
414 typedef UINT (WINAPI *fnMsiDecomposeDescriptorA)(LPCSTR, LPCSTR, LPSTR, LPSTR, DWORD *);
415 static fnMsiDecomposeDescriptorA pMsiDecomposeDescriptorA;
416
417 static void test_msidecomposedesc(void)
418 {
419 char prod[MAX_FEATURE_CHARS+1], comp[MAX_FEATURE_CHARS+1], feature[MAX_FEATURE_CHARS+1];
420 const char *desc;
421 UINT r;
422 DWORD len;
423 HMODULE hmod;
424
425 hmod = GetModuleHandle("msi.dll");
426 pMsiDecomposeDescriptorA = (fnMsiDecomposeDescriptorA)
427 GetProcAddress(hmod, "MsiDecomposeDescriptorA");
428 if (!pMsiDecomposeDescriptorA)
429 return;
430
431 /* test a valid feature descriptor */
432 desc = "']gAVn-}f(ZXfeAR6.jiFollowTheWhiteRabbit>3w2x^IGfe?CxI5heAvk.";
433 len = 0;
434 r = pMsiDecomposeDescriptorA(desc, prod, feature, comp, &len);
435 ok(r == ERROR_SUCCESS, "returned an error\n");
436 ok(len == strlen(desc), "length was wrong\n");
437 ok(strcmp(prod,"{90110409-6000-11D3-8CFE-0150048383C9}")==0, "product wrong\n");
438 ok(strcmp(feature,"FollowTheWhiteRabbit")==0, "feature wrong\n");
439 ok(strcmp(comp,"{A7CD68DB-EF74-49C8-FBB2-A7C463B2AC24}")==0,"component wrong\n");
440
441 /* test an invalid feature descriptor with too many characters */
442 desc = "']gAVn-}f(ZXfeAR6.ji"
443 "ThisWillFailIfTheresMoreThanAGuidsChars>"
444 "3w2x^IGfe?CxI5heAvk.";
445 len = 0;
446 r = pMsiDecomposeDescriptorA(desc, prod, feature, comp, &len);
447 ok(r == ERROR_INVALID_PARAMETER, "returned wrong error\n");
448
449 /*
450 * Test a valid feature descriptor with the
451 * maximum number of characters and some trailing characters.
452 */
453 desc = "']gAVn-}f(ZXfeAR6.ji"
454 "ThisWillWorkIfTheresLTEThanAGuidsChars>"
455 "3w2x^IGfe?CxI5heAvk."
456 "extra";
457 len = 0;
458 r = pMsiDecomposeDescriptorA(desc, prod, feature, comp, &len);
459 ok(r == ERROR_SUCCESS, "returned wrong error\n");
460 ok(len == (strlen(desc) - strlen("extra")), "length wrong\n");
461
462 len = 0;
463 r = pMsiDecomposeDescriptorA(desc, prod, feature, NULL, &len);
464 ok(r == ERROR_SUCCESS, "returned wrong error\n");
465 ok(len == (strlen(desc) - strlen("extra")), "length wrong\n");
466
467 len = 0;
468 r = pMsiDecomposeDescriptorA(desc, prod, NULL, NULL, &len);
469 ok(r == ERROR_SUCCESS, "returned wrong error\n");
470 ok(len == (strlen(desc) - strlen("extra")), "length wrong\n");
471
472 len = 0;
473 r = pMsiDecomposeDescriptorA(desc, NULL, NULL, NULL, &len);
474 ok(r == ERROR_SUCCESS, "returned wrong error\n");
475 ok(len == (strlen(desc) - strlen("extra")), "length wrong\n");
476
477 len = 0;
478 r = pMsiDecomposeDescriptorA(NULL, NULL, NULL, NULL, &len);
479 ok(r == ERROR_INVALID_PARAMETER, "returned wrong error\n");
480 ok(len == 0, "length wrong\n");
481 }
482
483 static UINT try_query_param( MSIHANDLE hdb, LPCSTR szQuery, MSIHANDLE hrec )
484 {
485 MSIHANDLE htab = 0;
486 UINT res;
487
488 res = MsiDatabaseOpenView( hdb, szQuery, &htab );
489 if(res == ERROR_SUCCESS )
490 {
491 UINT r;
492
493 r = MsiViewExecute( htab, hrec );
494 if(r != ERROR_SUCCESS )
495 res = r;
496
497 r = MsiViewClose( htab );
498 if(r != ERROR_SUCCESS )
499 res = r;
500
501 r = MsiCloseHandle( htab );
502 if(r != ERROR_SUCCESS )
503 res = r;
504 }
505 return res;
506 }
507
508 static UINT try_query( MSIHANDLE hdb, LPCSTR szQuery )
509 {
510 return try_query_param( hdb, szQuery, 0 );
511 }
512
513 static UINT try_insert_query( MSIHANDLE hdb, LPCSTR szQuery )
514 {
515 MSIHANDLE hrec = 0;
516 UINT r;
517
518 hrec = MsiCreateRecord( 1 );
519 MsiRecordSetString( hrec, 1, "Hello");
520
521 r = try_query_param( hdb, szQuery, hrec );
522
523 MsiCloseHandle( hrec );
524 return r;
525 }
526
527 static void test_msibadqueries(void)
528 {
529 MSIHANDLE hdb = 0;
530 UINT r;
531
532 DeleteFile(msifile);
533
534 /* just MsiOpenDatabase should not create a file */
535 r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
536 ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
537
538 r = MsiDatabaseCommit( hdb );
539 ok(r == ERROR_SUCCESS , "Failed to commit database\n");
540
541 r = MsiCloseHandle( hdb );
542 ok(r == ERROR_SUCCESS , "Failed to close database\n");
543
544 /* open it readonly */
545 r = MsiOpenDatabase(msifile, MSIDBOPEN_READONLY, &hdb );
546 ok(r == ERROR_SUCCESS , "Failed to open database r/o\n");
547
548 /* add a table to it */
549 r = try_query( hdb, "select * from _Tables");
550 ok(r == ERROR_SUCCESS , "query 1 failed\n");
551
552 r = MsiCloseHandle( hdb );
553 ok(r == ERROR_SUCCESS , "Failed to close database r/o\n");
554
555 /* open it read/write */
556 r = MsiOpenDatabase(msifile, MSIDBOPEN_TRANSACT, &hdb );
557 ok(r == ERROR_SUCCESS , "Failed to open database r/w\n");
558
559 /* a bunch of test queries that fail with the native MSI */
560
561 r = try_query( hdb, "CREATE TABLE");
562 ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2a return code\n");
563
564 r = try_query( hdb, "CREATE TABLE `a`");
565 ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2b return code\n");
566
567 r = try_query( hdb, "CREATE TABLE `a` ()");
568 ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2c return code\n");
569
570 r = try_query( hdb, "CREATE TABLE `a` (`b`)");
571 ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2d return code\n");
572
573 r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) )");
574 ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2e return code\n");
575
576 r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL)");
577 ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2f return code\n");
578
579 r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY)");
580 ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2g return code\n");
581
582 r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY)");
583 ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2h return code\n");
584
585 r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY)");
586 ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2i return code\n");
587
588 r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY 'b')");
589 ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2j return code\n");
590
591 r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY `b')");
592 ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2k return code\n");
593
594 r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY `b')");
595 ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2l return code\n");
596
597 r = try_query( hdb, "CREATE TABLE `a` (`b` CHA(72) NOT NULL PRIMARY KEY `b`)");
598 ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2m return code\n");
599
600 r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(-1) NOT NULL PRIMARY KEY `b`)");
601 ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2n return code\n");
602
603 r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(720) NOT NULL PRIMARY KEY `b`)");
604 ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2o return code\n");
605
606 r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL KEY `b`)");
607 ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2p return code\n");
608
609 r = try_query( hdb, "CREATE TABLE `a` (`` CHAR(72) NOT NULL PRIMARY KEY `b`)");
610 ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2p return code\n");
611
612 r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY `b`)");
613 ok(r == ERROR_SUCCESS , "valid query 2z failed\n");
614
615 r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY `b`)");
616 ok(r == ERROR_BAD_QUERY_SYNTAX , "created same table again\n");
617
618 r = try_query( hdb, "CREATE TABLE `aa` (`b` CHAR(72) NOT NULL, `c` "
619 "CHAR(72), `d` CHAR(255) NOT NULL LOCALIZABLE PRIMARY KEY `b`)");
620 ok(r == ERROR_SUCCESS , "query 4 failed\n");
621
622 r = MsiDatabaseCommit( hdb );
623 ok(r == ERROR_SUCCESS , "Failed to commit database after write\n");
624
625 r = try_query( hdb, "CREATE TABLE `blah` (`foo` CHAR(72) NOT NULL "
626 "PRIMARY KEY `foo`)");
627 ok(r == ERROR_SUCCESS , "query 4 failed\n");
628
629 r = try_insert_query( hdb, "insert into a ( `b` ) VALUES ( ? )");
630 ok(r == ERROR_SUCCESS , "failed to insert record in db\n");
631
632 r = MsiDatabaseCommit( hdb );
633 ok(r == ERROR_SUCCESS , "Failed to commit database after write\n");
634
635 r = try_query( hdb, "CREATE TABLE `boo` (`foo` CHAR(72) NOT NULL "
636 "PRIMARY KEY `ba`)");
637 ok(r != ERROR_SUCCESS , "query 5 succeeded\n");
638
639 r = try_query( hdb,"CREATE TABLE `bee` (`foo` CHAR(72) NOT NULL )");
640 ok(r != ERROR_SUCCESS , "query 6 succeeded\n");
641
642 r = try_query( hdb, "CREATE TABLE `temp` (`t` CHAR(72) NOT NULL "
643 "PRIMARY KEY `t`)");
644 ok(r == ERROR_SUCCESS , "query 7 failed\n");
645
646 r = try_query( hdb, "CREATE TABLE `c` (`b` CHAR NOT NULL PRIMARY KEY `b`)");
647 ok(r == ERROR_SUCCESS , "query 8 failed\n");
648
649 r = try_query( hdb, "select * from c");
650 ok(r == ERROR_SUCCESS , "query failed\n");
651
652 r = try_query( hdb, "select * from c where b = 'x");
653 ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
654
655 r = try_query( hdb, "select * from c where b = 'x'");
656 ok(r == ERROR_SUCCESS, "query failed\n");
657
658 r = try_query( hdb, "select * from 'c'");
659 ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
660
661 r = try_query( hdb, "select * from ''");
662 ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
663
664 r = try_query( hdb, "select * from c where b = x");
665 ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
666
667 r = try_query( hdb, "select * from c where b = \"x\"");
668 ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
669
670 r = try_query( hdb, "select * from c where b = 'x'");
671 ok(r == ERROR_SUCCESS, "query failed\n");
672
673 r = try_query( hdb, "select * from c where b = '\"x'");
674 ok(r == ERROR_SUCCESS, "query failed\n");
675
676 if (0) /* FIXME: this query causes trouble with other tests */
677 {
678 r = try_query( hdb, "select * from c where b = '\\\'x'");
679 ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
680 }
681
682 r = try_query( hdb, "select * from 'c'");
683 ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
684
685 r = MsiCloseHandle( hdb );
686 ok(r == ERROR_SUCCESS , "Failed to close database transact\n");
687
688 r = DeleteFile( msifile );
689 ok(r == TRUE, "file didn't exist after commit\n");
690 }
691
692 static void test_viewmodify(void)
693 {
694 MSIHANDLE hdb = 0, hview = 0, hrec = 0;
695 UINT r;
696 MSIDBERROR err;
697 const char *query;
698 char buffer[0x100];
699 DWORD sz;
700
701 DeleteFile(msifile);
702
703 /* just MsiOpenDatabase should not create a file */
704 r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
705 ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
706
707 query = "CREATE TABLE `phone` ( "
708 "`id` INT, `name` CHAR(32), `number` CHAR(32) "
709 "PRIMARY KEY `id`)";
710 r = run_query( hdb, 0, query );
711 ok(r == ERROR_SUCCESS, "query failed\n");
712
713 /* check what the error function reports without doing anything */
714 sz = 0;
715 /* passing NULL as the 3rd param make function to crash on older platforms */
716 err = MsiViewGetError( 0, NULL, &sz );
717 ok(err == MSIDBERROR_INVALIDARG, "MsiViewGetError return\n");
718
719 /* open a view */
720 query = "SELECT * FROM `phone`";
721 r = MsiDatabaseOpenView(hdb, query, &hview);
722 ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
723
724 /* see what happens with a good hview and bad args */
725 err = MsiViewGetError( hview, NULL, NULL );
726 ok(err == MSIDBERROR_INVALIDARG || err == MSIDBERROR_NOERROR,
727 "MsiViewGetError returns %u (expected -3)\n", err);
728 err = MsiViewGetError( hview, buffer, NULL );
729 ok(err == MSIDBERROR_INVALIDARG, "MsiViewGetError return\n");
730
731 /* see what happens with a zero length buffer */
732 sz = 0;
733 buffer[0] = 'x';
734 err = MsiViewGetError( hview, buffer, &sz );
735 ok(err == MSIDBERROR_MOREDATA, "MsiViewGetError return\n");
736 ok(buffer[0] == 'x', "buffer cleared\n");
737 ok(sz == 0, "size not zero\n");
738
739 /* ok this one is strange */
740 sz = 0;
741 err = MsiViewGetError( hview, NULL, &sz );
742 ok(err == MSIDBERROR_NOERROR, "MsiViewGetError return\n");
743 ok(sz == 0, "size not zero\n");
744
745 /* see if it really has an error */
746 sz = sizeof buffer;
747 buffer[0] = 'x';
748 err = MsiViewGetError( hview, buffer, &sz );
749 ok(err == MSIDBERROR_NOERROR, "MsiViewGetError return\n");
750 ok(buffer[0] == 0, "buffer not cleared\n");
751 ok(sz == 0, "size not zero\n");
752
753 r = MsiViewExecute(hview, 0);
754 ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
755
756 /* try some invalid records */
757 r = MsiViewModify(hview, MSIMODIFY_INSERT, 0 );
758 ok(r == ERROR_INVALID_HANDLE, "MsiViewModify failed\n");
759 r = MsiViewModify(hview, -1, 0 );
760 ok(r == ERROR_INVALID_HANDLE, "MsiViewModify failed\n");
761
762 /* try an small record */
763 hrec = MsiCreateRecord(1);
764 r = MsiViewModify(hview, -1, hrec );
765 ok(r == ERROR_INVALID_DATA, "MsiViewModify failed\n");
766
767 r = MsiCloseHandle(hrec);
768 ok(r == ERROR_SUCCESS, "failed to close record\n");
769
770 /* insert a valid record */
771 hrec = MsiCreateRecord(3);
772
773 r = MsiRecordSetInteger(hrec, 1, 1);
774 ok(r == ERROR_SUCCESS, "failed to set integer\n");
775 r = MsiRecordSetString(hrec, 2, "bob");
776 ok(r == ERROR_SUCCESS, "failed to set string\n");
777 r = MsiRecordSetString(hrec, 3, "7654321");
778 ok(r == ERROR_SUCCESS, "failed to set string\n");
779
780 r = MsiViewExecute(hview, 0);
781 ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
782 r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec );
783 ok(r == ERROR_SUCCESS, "MsiViewModify failed\n");
784
785 /* insert the same thing again */
786 r = MsiViewExecute(hview, 0);
787 ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
788
789 /* should fail ... */
790 r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec );
791 ok(r == ERROR_FUNCTION_FAILED, "MsiViewModify failed\n");
792
793 r = MsiCloseHandle(hrec);
794 ok(r == ERROR_SUCCESS, "failed to close record\n");
795
796 r = MsiViewClose(hview);
797 ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
798 r = MsiCloseHandle(hview);
799 ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
800
801 query = "SELECT * FROM `phone`";
802 r = MsiDatabaseOpenView(hdb, query, &hview);
803 ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
804
805 r = MsiViewExecute(hview, 0);
806 ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
807
808 r = MsiViewFetch(hview, &hrec);
809 ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
810
811 r = MsiRecordGetInteger(hrec, 1);
812 ok(r == 1, "Expected 1, got %d\n", r);
813
814 sz = sizeof(buffer);
815 r = MsiRecordGetString(hrec, 2, buffer, &sz);
816 ok(r == ERROR_SUCCESS, "MsiRecordGetString failed\n");
817 ok(!lstrcmp(buffer, "bob"), "Expected bob, got %s\n", buffer);
818
819 sz = sizeof(buffer);
820 r = MsiRecordGetString(hrec, 3, buffer, &sz);
821 ok(r == ERROR_SUCCESS, "MsiRecordGetString failed\n");
822 ok(!lstrcmp(buffer, "7654321"), "Expected 7654321, got %s\n", buffer);
823
824 /* update the view, non-primary key */
825 r = MsiRecordSetString(hrec, 3, "3141592");
826 ok(r == ERROR_SUCCESS, "MsiRecordSetString failed\n");
827
828 r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
829 ok(r == ERROR_SUCCESS, "MsiViewModify failed\n");
830
831 /* do it again */
832 r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
833 ok(r == ERROR_SUCCESS, "MsiViewModify failed: %d\n", r);
834
835 /* update the view, primary key */
836 r = MsiRecordSetInteger(hrec, 1, 5);
837 ok(r == ERROR_SUCCESS, "MsiRecordSetInteger failed\n");
838
839 r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
840 ok(r == ERROR_FUNCTION_FAILED, "MsiViewModify failed\n");
841
842 r = MsiCloseHandle(hrec);
843 ok(r == ERROR_SUCCESS, "failed to close record\n");
844
845 r = MsiViewClose(hview);
846 ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
847 r = MsiCloseHandle(hview);
848 ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
849
850 query = "SELECT * FROM `phone`";
851 r = MsiDatabaseOpenView(hdb, query, &hview);
852 ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
853
854 r = MsiViewExecute(hview, 0);
855 ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
856
857 r = MsiViewFetch(hview, &hrec);
858 ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
859
860 r = MsiRecordGetInteger(hrec, 1);
861 ok(r == 1, "Expected 1, got %d\n", r);
862
863 sz = sizeof(buffer);
864 r = MsiRecordGetString(hrec, 2, buffer, &sz);
865 ok(r == ERROR_SUCCESS, "MsiRecordGetString failed\n");
866 ok(!lstrcmp(buffer, "bob"), "Expected bob, got %s\n", buffer);
867
868 sz = sizeof(buffer);
869 r = MsiRecordGetString(hrec, 3, buffer, &sz);
870 ok(r == ERROR_SUCCESS, "MsiRecordGetString failed\n");
871 ok(!lstrcmp(buffer, "3141592"), "Expected 3141592, got %s\n", buffer);
872
873 r = MsiCloseHandle(hrec);
874 ok(r == ERROR_SUCCESS, "failed to close record\n");
875
876 /* use a record that doesn't come from a view fetch */
877 hrec = MsiCreateRecord(3);
878 ok(hrec != 0, "MsiCreateRecord failed\n");
879
880 r = MsiRecordSetInteger(hrec, 1, 3);
881 ok(r == ERROR_SUCCESS, "failed to set integer\n");
882 r = MsiRecordSetString(hrec, 2, "jane");
883 ok(r == ERROR_SUCCESS, "failed to set string\n");
884 r = MsiRecordSetString(hrec, 3, "112358");
885 ok(r == ERROR_SUCCESS, "failed to set string\n");
886
887 r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
888 ok(r == ERROR_FUNCTION_FAILED, "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
889
890 r = MsiCloseHandle(hrec);
891 ok(r == ERROR_SUCCESS, "failed to close record\n");
892
893 /* use a record that doesn't come from a view fetch, primary key matches */
894 hrec = MsiCreateRecord(3);
895 ok(hrec != 0, "MsiCreateRecord failed\n");
896
897 r = MsiRecordSetInteger(hrec, 1, 1);
898 ok(r == ERROR_SUCCESS, "failed to set integer\n");
899 r = MsiRecordSetString(hrec, 2, "jane");
900 ok(r == ERROR_SUCCESS, "failed to set string\n");
901 r = MsiRecordSetString(hrec, 3, "112358");
902 ok(r == ERROR_SUCCESS, "failed to set string\n");
903
904 r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
905 ok(r == ERROR_FUNCTION_FAILED, "MsiViewModify failed\n");
906
907 r = MsiCloseHandle(hrec);
908 ok(r == ERROR_SUCCESS, "failed to close record\n");
909
910 hrec = MsiCreateRecord(3);
911
912 r = MsiRecordSetInteger(hrec, 1, 2);
913 ok(r == ERROR_SUCCESS, "failed to set integer\n");
914 r = MsiRecordSetString(hrec, 2, "nick");
915 ok(r == ERROR_SUCCESS, "failed to set string\n");
916 r = MsiRecordSetString(hrec, 3, "141421");
917 ok(r == ERROR_SUCCESS, "failed to set string\n");
918
919 r = MsiViewExecute(hview, 0);
920 ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
921 r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec );
922 ok(r == ERROR_SUCCESS, "MsiViewModify failed\n");
923
924 r = MsiViewClose(hview);
925 ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
926 r = MsiCloseHandle(hview);
927 ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
928
929 query = "SELECT * FROM `phone` WHERE `id` = 1";
930 r = MsiDatabaseOpenView(hdb, query, &hview);
931 ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
932 r = MsiViewExecute(hview, 0);
933 ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
934 r = MsiViewFetch(hview, &hrec);
935 ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
936
937 /* change the id to match the second row */
938 r = MsiRecordSetInteger(hrec, 1, 2);
939 ok(r == ERROR_SUCCESS, "failed to set integer\n");
940 r = MsiRecordSetString(hrec, 2, "jerry");
941 ok(r == ERROR_SUCCESS, "failed to set string\n");
942
943 r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
944 ok(r == ERROR_FUNCTION_FAILED, "MsiViewModify failed\n");
945
946 r = MsiCloseHandle(hrec);
947 ok(r == ERROR_SUCCESS, "failed to close record\n");
948 r = MsiViewClose(hview);
949 ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
950 r = MsiCloseHandle(hview);
951 ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
952
953 /* broader search */
954 query = "SELECT * FROM `phone` ORDER BY `id`";
955 r = MsiDatabaseOpenView(hdb, query, &hview);
956 ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
957 r = MsiViewExecute(hview, 0);
958 ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
959 r = MsiViewFetch(hview, &hrec);
960 ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
961
962 /* change the id to match the second row */
963 r = MsiRecordSetInteger(hrec, 1, 2);
964 ok(r == ERROR_SUCCESS, "failed to set integer\n");
965 r = MsiRecordSetString(hrec, 2, "jerry");
966 ok(r == ERROR_SUCCESS, "failed to set string\n");
967
968 r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
969 ok(r == ERROR_FUNCTION_FAILED, "MsiViewModify failed\n");
970
971 r = MsiCloseHandle(hrec);
972 ok(r == ERROR_SUCCESS, "failed to close record\n");
973 r = MsiViewClose(hview);
974 ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
975 r = MsiCloseHandle(hview);
976 ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
977
978 r = MsiCloseHandle( hdb );
979 ok(r == ERROR_SUCCESS, "MsiOpenDatabase close failed\n");
980 }
981
982 static MSIHANDLE create_db(void)
983 {
984 MSIHANDLE hdb = 0;
985 UINT res;
986
987 DeleteFile(msifile);
988
989 /* create an empty database */
990 res = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb );
991 ok( res == ERROR_SUCCESS , "Failed to create database\n" );
992 if( res != ERROR_SUCCESS )
993 return hdb;
994
995 res = MsiDatabaseCommit( hdb );
996 ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
997
998 return hdb;
999 }
1000
1001 static void test_getcolinfo(void)
1002 {
1003 MSIHANDLE hdb, hview = 0, rec = 0;
1004 UINT r;
1005 DWORD sz;
1006 char buffer[0x20];
1007
1008 /* create an empty db */
1009 hdb = create_db();
1010 ok( hdb, "failed to create db\n");
1011
1012 /* tables should be present */
1013 r = MsiDatabaseOpenView(hdb, "select * from _Tables", &hview);
1014 ok( r == ERROR_SUCCESS, "failed to open query\n");
1015
1016 r = MsiViewExecute(hview, 0);
1017 ok( r == ERROR_SUCCESS, "failed to execute query\n");
1018
1019 /* check that NAMES works */
1020 rec = 0;
1021 r = MsiViewGetColumnInfo( hview, MSICOLINFO_NAMES, &rec );
1022 ok( r == ERROR_SUCCESS, "failed to get names\n");
1023 sz = sizeof buffer;
1024 r = MsiRecordGetString(rec, 1, buffer, &sz );
1025 ok( r == ERROR_SUCCESS, "failed to get string\n");
1026 ok( !strcmp(buffer,"Name"), "_Tables has wrong column name\n");
1027 r = MsiCloseHandle( rec );
1028 ok( r == ERROR_SUCCESS, "failed to close record handle\n");
1029
1030 /* check that TYPES works */
1031 rec = 0;
1032 r = MsiViewGetColumnInfo( hview, MSICOLINFO_TYPES, &rec );
1033 ok( r == ERROR_SUCCESS, "failed to get names\n");
1034 sz = sizeof buffer;
1035 r = MsiRecordGetString(rec, 1, buffer, &sz );
1036 ok( r == ERROR_SUCCESS, "failed to get string\n");
1037 ok( !strcmp(buffer,"s64"), "_Tables has wrong column type\n");
1038 r = MsiCloseHandle( rec );
1039 ok( r == ERROR_SUCCESS, "failed to close record handle\n");
1040
1041 /* check that invalid values fail */
1042 rec = 0;
1043 r = MsiViewGetColumnInfo( hview, 100, &rec );
1044 ok( r == ERROR_INVALID_PARAMETER, "wrong error code\n");
1045 ok( rec == 0, "returned a record\n");
1046
1047 r = MsiViewGetColumnInfo( hview, MSICOLINFO_TYPES, NULL );
1048 ok( r == ERROR_INVALID_PARAMETER, "wrong error code\n");
1049
1050 r = MsiViewGetColumnInfo( 0, MSICOLINFO_TYPES, &rec );
1051 ok( r == ERROR_INVALID_HANDLE, "wrong error code\n");
1052
1053 r = MsiViewClose(hview);
1054 ok( r == ERROR_SUCCESS, "failed to close view\n");
1055 r = MsiCloseHandle(hview);
1056 ok( r == ERROR_SUCCESS, "failed to close view handle\n");
1057 r = MsiCloseHandle(hdb);
1058 ok( r == ERROR_SUCCESS, "failed to close database\n");
1059 }
1060
1061 static MSIHANDLE get_column_info(MSIHANDLE hdb, const char *query, MSICOLINFO type)
1062 {
1063 MSIHANDLE hview = 0, rec = 0;
1064 UINT r;
1065
1066 r = MsiDatabaseOpenView(hdb, query, &hview);
1067 if( r != ERROR_SUCCESS )
1068 return r;
1069
1070 r = MsiViewExecute(hview, 0);
1071 if( r == ERROR_SUCCESS )
1072 {
1073 MsiViewGetColumnInfo( hview, type, &rec );
1074 }
1075 MsiViewClose(hview);
1076 MsiCloseHandle(hview);
1077 return rec;
1078 }
1079
1080 static UINT get_columns_table_type(MSIHANDLE hdb, const char *table, UINT field)
1081 {
1082 MSIHANDLE hview = 0, rec = 0;
1083 UINT r, type = 0;
1084 char query[0x100];
1085
1086 sprintf(query, "select * from `_Columns` where `Table` = '%s'", table );
1087
1088 r = MsiDatabaseOpenView(hdb, query, &hview);
1089 if( r != ERROR_SUCCESS )
1090 return r;
1091
1092 r = MsiViewExecute(hview, 0);
1093 if( r == ERROR_SUCCESS )
1094 {
1095 while (1)
1096 {
1097 r = MsiViewFetch( hview, &rec );
1098 if( r != ERROR_SUCCESS)
1099 break;
1100 r = MsiRecordGetInteger( rec, 2 );
1101 if (r == field)
1102 type = MsiRecordGetInteger( rec, 4 );
1103 MsiCloseHandle( rec );
1104 }
1105 }
1106 MsiViewClose(hview);
1107 MsiCloseHandle(hview);
1108 return type;
1109 }
1110
1111 static BOOL check_record( MSIHANDLE rec, UINT field, LPCSTR val )
1112 {
1113 CHAR buffer[0x20];
1114 UINT r;
1115 DWORD sz;
1116
1117 sz = sizeof buffer;
1118 r = MsiRecordGetString( rec, field, buffer, &sz );
1119 return (r == ERROR_SUCCESS ) && !strcmp(val, buffer);
1120 }
1121
1122 static void test_viewgetcolumninfo(void)
1123 {
1124 MSIHANDLE hdb = 0, rec;
1125 UINT r;
1126
1127 hdb = create_db();
1128 ok( hdb, "failed to create db\n");
1129
1130 r = run_query( hdb, 0,
1131 "CREATE TABLE `Properties` "
1132 "( `Property` CHAR(255), "
1133 " `Value` CHAR(1), "
1134 " `Intvalue` INT, "
1135 " `Integervalue` INTEGER, "
1136 " `Shortvalue` SHORT, "
1137 " `Longvalue` LONG, "
1138 " `Longcharvalue` LONGCHAR "
1139 " PRIMARY KEY `Property`)" );
1140 ok( r == ERROR_SUCCESS , "Failed to create table\n" );
1141
1142 /* check the column types */
1143 rec = get_column_info( hdb, "select * from `Properties`", MSICOLINFO_TYPES );
1144 ok( rec, "failed to get column info record\n" );
1145
1146 ok( check_record( rec, 1, "S255"), "wrong record type\n");
1147 ok( check_record( rec, 2, "S1"), "wrong record type\n");
1148 ok( check_record( rec, 3, "I2"), "wrong record type\n");
1149 ok( check_record( rec, 4, "I2"), "wrong record type\n");
1150 ok( check_record( rec, 5, "I2"), "wrong record type\n");
1151 ok( check_record( rec, 6, "I4"), "wrong record type\n");
1152 ok( check_record( rec, 7, "S0"), "wrong record type\n");
1153
1154 MsiCloseHandle( rec );
1155
1156 /* check the type in _Columns */
1157 ok( 0x3dff == get_columns_table_type(hdb, "Properties", 1 ), "_columns table wrong\n");
1158 ok( 0x1d01 == get_columns_table_type(hdb, "Properties", 2 ), "_columns table wrong\n");
1159 ok( 0x1502 == get_columns_table_type(hdb, "Properties", 3 ), "_columns table wrong\n");
1160 ok( 0x1502 == get_columns_table_type(hdb, "Properties", 4 ), "_columns table wrong\n");
1161 ok( 0x1502 == get_columns_table_type(hdb, "Properties", 5 ), "_columns table wrong\n");
1162 ok( 0x1104 == get_columns_table_type(hdb, "Properties", 6 ), "_columns table wrong\n");
1163 ok( 0x1d00 == get_columns_table_type(hdb, "Properties", 7 ), "_columns table wrong\n");
1164
1165 /* now try the names */
1166 rec = get_column_info( hdb, "select * from `Properties`", MSICOLINFO_NAMES );
1167 ok( rec, "failed to get column info record\n" );
1168
1169 ok( check_record( rec, 1, "Property"), "wrong record type\n");
1170 ok( check_record( rec, 2, "Value"), "wrong record type\n");
1171 ok( check_record( rec, 3, "Intvalue"), "wrong record type\n");
1172 ok( check_record( rec, 4, "Integervalue"), "wrong record type\n");
1173 ok( check_record( rec, 5, "Shortvalue"), "wrong record type\n");
1174 ok( check_record( rec, 6, "Longvalue"), "wrong record type\n");
1175 ok( check_record( rec, 7, "Longcharvalue"), "wrong record type\n");
1176
1177 MsiCloseHandle( rec );
1178
1179 r = run_query( hdb, 0,
1180 "CREATE TABLE `Binary` "
1181 "( `Name` CHAR(255), `Data` OBJECT PRIMARY KEY `Name`)" );
1182 ok( r == ERROR_SUCCESS , "Failed to create table\n" );
1183
1184 /* check the column types */
1185 rec = get_column_info( hdb, "select * from `Binary`", MSICOLINFO_TYPES );
1186 ok( rec, "failed to get column info record\n" );
1187
1188 ok( check_record( rec, 1, "S255"), "wrong record type\n");
1189 ok( check_record( rec, 2, "V0"), "wrong record type\n");
1190
1191 MsiCloseHandle( rec );
1192
1193 /* check the type in _Columns */
1194 ok( 0x3dff == get_columns_table_type(hdb, "Binary", 1 ), "_columns table wrong\n");
1195 ok( 0x1900 == get_columns_table_type(hdb, "Binary", 2 ), "_columns table wrong\n");
1196
1197 /* now try the names */
1198 rec = get_column_info( hdb, "select * from `Binary`", MSICOLINFO_NAMES );
1199 ok( rec, "failed to get column info record\n" );
1200
1201 ok( check_record( rec, 1, "Name"), "wrong record type\n");
1202 ok( check_record( rec, 2, "Data"), "wrong record type\n");
1203 MsiCloseHandle( rec );
1204
1205 r = run_query( hdb, 0,
1206 "CREATE TABLE `UIText` "
1207 "( `Key` CHAR(72) NOT NULL, `Text` CHAR(255) LOCALIZABLE PRIMARY KEY `Key`)" );
1208 ok( r == ERROR_SUCCESS , "Failed to create table\n" );
1209
1210 ok( 0x2d48 == get_columns_table_type(hdb, "UIText", 1 ), "_columns table wrong\n");
1211 ok( 0x1fff == get_columns_table_type(hdb, "UIText", 2 ), "_columns table wrong\n");
1212
1213 rec = get_column_info( hdb, "select * from `UIText`", MSICOLINFO_NAMES );
1214 ok( rec, "failed to get column info record\n" );
1215 ok( check_record( rec, 1, "Key"), "wrong record type\n");
1216 ok( check_record( rec, 2, "Text"), "wrong record type\n");
1217 MsiCloseHandle( rec );
1218
1219 rec = get_column_info( hdb, "select * from `UIText`", MSICOLINFO_TYPES );
1220 ok( rec, "failed to get column info record\n" );
1221 ok( check_record( rec, 1, "s72"), "wrong record type\n");
1222 ok( check_record( rec, 2, "L255"), "wrong record type\n");
1223 MsiCloseHandle( rec );
1224
1225 MsiCloseHandle( hdb );
1226 }
1227
1228 static void test_msiexport(void)
1229 {
1230 MSIHANDLE hdb = 0, hview = 0;
1231 UINT r;
1232 const char *query;
1233 char path[MAX_PATH];
1234 const char file[] = "phone.txt";
1235 HANDLE handle;
1236 char buffer[0x100];
1237 DWORD length;
1238 const char expected[] =
1239 "id\tname\tnumber\r\n"
1240 "I2\tS32\tS32\r\n"
1241 "phone\tid\r\n"
1242 "1\tAbe\t8675309\r\n";
1243
1244 DeleteFile(msifile);
1245
1246 /* just MsiOpenDatabase should not create a file */
1247 r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
1248 ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
1249
1250 /* create a table */
1251 query = "CREATE TABLE `phone` ( "
1252 "`id` INT, `name` CHAR(32), `number` CHAR(32) "
1253 "PRIMARY KEY `id`)";
1254 r = MsiDatabaseOpenView(hdb, query, &hview);
1255 ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
1256 r = MsiViewExecute(hview, 0);
1257 ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
1258 r = MsiViewClose(hview);
1259 ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
1260 r = MsiCloseHandle(hview);
1261 ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
1262
1263 /* insert a value into it */
1264 query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
1265 "VALUES('1', 'Abe', '8675309')";
1266 r = MsiDatabaseOpenView(hdb, query, &hview);
1267 ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
1268 r = MsiViewExecute(hview, 0);
1269 ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
1270 r = MsiViewClose(hview);
1271 ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
1272 r = MsiCloseHandle(hview);
1273 ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
1274
1275 GetCurrentDirectory(MAX_PATH, path);
1276
1277 r = MsiDatabaseExport(hdb, "phone", path, file);
1278 ok(r == ERROR_SUCCESS, "MsiDatabaseExport failed\n");
1279
1280 MsiCloseHandle(hdb);
1281
1282 lstrcat(path, "\\");
1283 lstrcat(path, file);
1284
1285 /* check the data that was written */
1286 length = 0;
1287 memset(buffer, 0, sizeof buffer);
1288 handle = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
1289 if (handle != INVALID_HANDLE_VALUE)
1290 {
1291 ReadFile(handle, buffer, sizeof buffer, &length, NULL);
1292 CloseHandle(handle);
1293 DeleteFile(path);
1294 }
1295 else
1296 ok(0, "failed to open file %s\n", path);
1297
1298 ok( length == strlen(expected), "length of data wrong\n");
1299 ok( !lstrcmp(buffer, expected), "data doesn't match\n");
1300 DeleteFile(msifile);
1301 }
1302
1303 static void test_longstrings(void)
1304 {
1305 const char insert_query[] =
1306 "INSERT INTO `strings` ( `id`, `val` ) VALUES('1', 'Z')";
1307 char *str;
1308 MSIHANDLE hdb = 0, hview = 0, hrec = 0;
1309 DWORD len;
1310 UINT r;
1311 const DWORD STRING_LENGTH = 0x10005;
1312
1313 DeleteFile(msifile);
1314 /* just MsiOpenDatabase should not create a file */
1315 r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
1316 ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
1317
1318 /* create a table */
1319 r = try_query( hdb,
1320 "CREATE TABLE `strings` ( `id` INT, `val` CHAR(0) PRIMARY KEY `id`)");
1321 ok(r == ERROR_SUCCESS, "query failed\n");
1322
1323 /* try a insert a very long string */
1324 str = HeapAlloc(GetProcessHeap(), 0, STRING_LENGTH+sizeof insert_query);
1325 len = strchr(insert_query, 'Z') - insert_query;
1326 strcpy(str, insert_query);
1327 memset(str+len, 'Z', STRING_LENGTH);
1328 strcpy(str+len+STRING_LENGTH, insert_query+len+1);
1329 r = try_query( hdb, str );
1330 ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
1331
1332 HeapFree(GetProcessHeap(), 0, str);
1333
1334 MsiDatabaseCommit(hdb);
1335 ok(r == ERROR_SUCCESS, "MsiDatabaseCommit failed\n");
1336 MsiCloseHandle(hdb);
1337
1338 r = MsiOpenDatabase(msifile, MSIDBOPEN_READONLY, &hdb);
1339 ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
1340
1341 r = MsiDatabaseOpenView(hdb, "select * from `strings` where `id` = 1", &hview);
1342 ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
1343
1344 r = MsiViewExecute(hview, 0);
1345 ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
1346
1347 r = MsiViewFetch(hview, &hrec);
1348 ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
1349
1350 MsiViewClose(hview);
1351 MsiCloseHandle(hview);
1352
1353 r = MsiRecordGetString(hrec, 2, NULL, &len);
1354 ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
1355 ok(len == STRING_LENGTH, "string length wrong\n");
1356
1357 MsiCloseHandle(hrec);
1358 MsiCloseHandle(hdb);
1359 DeleteFile(msifile);
1360 }
1361
1362 static void create_file_data(LPCSTR name, LPCSTR data, DWORD size)
1363 {
1364 HANDLE file;
1365 DWORD written;
1366
1367 file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
1368 if (file == INVALID_HANDLE_VALUE)
1369 return;
1370
1371 WriteFile(file, data, strlen(data), &written, NULL);
1372 WriteFile(file, "\n", strlen("\n"), &written, NULL);
1373
1374 if (size)
1375 {
1376 SetFilePointer(file, size, NULL, FILE_BEGIN);
1377 SetEndOfFile(file);
1378 }
1379
1380 CloseHandle(file);
1381 }
1382
1383 #define create_file(name) create_file_data(name, name, 0)
1384
1385 static void test_streamtable(void)
1386 {
1387 MSIHANDLE hdb = 0, rec, view;
1388 char file[MAX_PATH];
1389 char buf[MAX_PATH];
1390 DWORD size;
1391 UINT r;
1392
1393 hdb = create_db();
1394 ok( hdb, "failed to create db\n");
1395
1396 r = run_query( hdb, 0,
1397 "CREATE TABLE `Properties` "
1398 "( `Property` CHAR(255), `Value` CHAR(1) PRIMARY KEY `Property`)" );
1399 ok( r == ERROR_SUCCESS , "Failed to create table\n" );
1400
1401 r = run_query( hdb, 0,
1402 "INSERT INTO `Properties` "
1403 "( `Value`, `Property` ) VALUES ( 'Prop', 'value' )" );
1404 ok( r == ERROR_SUCCESS, "Failed to add to table\n" );
1405
1406 r = MsiDatabaseCommit( hdb );
1407 ok( r == ERROR_SUCCESS , "Failed to commit database\n" );
1408
1409 MsiCloseHandle( hdb );
1410
1411 r = MsiOpenDatabase(msifile, MSIDBOPEN_TRANSACT, &hdb );
1412 ok( r == ERROR_SUCCESS , "Failed to open database\n" );
1413
1414 /* check the column types */
1415 rec = get_column_info( hdb, "select * from `_Streams`", MSICOLINFO_TYPES );
1416 ok( rec, "failed to get column info record\n" );
1417
1418 ok( check_record( rec, 1, "s62"), "wrong record type\n");
1419 ok( check_record( rec, 2, "V0"), "wrong record type\n");
1420
1421 MsiCloseHandle( rec );
1422
1423 /* now try the names */
1424 rec = get_column_info( hdb, "select * from `_Streams`", MSICOLINFO_NAMES );
1425 ok( rec, "failed to get column info record\n" );
1426
1427 ok( check_record( rec, 1, "Name"), "wrong record type\n");
1428 ok( check_record( rec, 2, "Data"), "wrong record type\n");
1429
1430 MsiCloseHandle( rec );
1431
1432 /* insert a file into the _Streams table */
1433 create_file( "test.txt" );
1434
1435 rec = MsiCreateRecord( 2 );
1436 MsiRecordSetString( rec, 1, "data" );
1437
1438 r = MsiRecordSetStream( rec, 2, "test.txt" );
1439 ok( r == ERROR_SUCCESS, "Failed to add stream data to the record: %d\n", r);
1440
1441 DeleteFile("test.txt");
1442
1443 r = MsiDatabaseOpenView( hdb,
1444 "INSERT INTO `_Streams` ( `Name`, `Data` ) VALUES ( ?, ? )", &view );
1445 ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r);
1446
1447 r = MsiViewExecute( view, rec );
1448 ok( r == ERROR_SUCCESS, "Failed to execute view: %d\n", r);
1449
1450 MsiCloseHandle( rec );
1451 MsiViewClose( view );
1452 MsiCloseHandle( view );
1453
1454 r = MsiDatabaseOpenView( hdb,
1455 "SELECT `Name`, `Data` FROM `_Streams`", &view );
1456 ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r);
1457
1458 r = MsiViewExecute( view, 0 );
1459 ok( r == ERROR_SUCCESS, "Failed to execute view: %d\n", r);
1460
1461 r = MsiViewFetch( view, &rec );
1462 ok( r == ERROR_SUCCESS, "Failed to fetch record: %d\n", r);
1463
1464 size = MAX_PATH;
1465 r = MsiRecordGetString( rec, 1, file, &size );
1466 ok( r == ERROR_SUCCESS, "Failed to get string: %d\n", r);
1467 ok( !lstrcmp(file, "data"), "Expected 'data', got %s\n", file);
1468
1469 size = MAX_PATH;
1470 memset(buf, 0, MAX_PATH);
1471 r = MsiRecordReadStream( rec, 2, buf, &size );
1472 ok( r == ERROR_SUCCESS, "Failed to get stream: %d\n", r);
1473 ok( !lstrcmp(buf, "test.txt\n"), "Expected 'test.txt\\n', got %s\n", buf);
1474
1475 MsiCloseHandle( rec );
1476
1477 r = MsiViewFetch( view, &rec );
1478 ok( r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
1479
1480 MsiViewClose( view );
1481 MsiCloseHandle( view );
1482 MsiCloseHandle( hdb );
1483 DeleteFile(msifile);
1484 }
1485
1486 static void test_binary(void)
1487 {
1488 MSIHANDLE hdb = 0, rec;
1489 char file[MAX_PATH];
1490 char buf[MAX_PATH];
1491 DWORD size;
1492 LPCSTR query;
1493 UINT r;
1494
1495 /* insert a file into the Binary table */
1496 r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb );
1497 ok( r == ERROR_SUCCESS , "Failed to open database\n" );
1498
1499 query = "CREATE TABLE `Binary` ( `Name` CHAR(72) NOT NULL, `ID` INT NOT NULL, `Data` OBJECT PRIMARY KEY `Name`, `ID`)";
1500 r = run_query( hdb, 0, query );
1501 ok( r == ERROR_SUCCESS, "Cannot create Binary table: %d\n", r );
1502
1503 create_file( "test.txt" );
1504 rec = MsiCreateRecord( 1 );
1505 r = MsiRecordSetStream( rec, 1, "test.txt" );
1506 ok( r == ERROR_SUCCESS, "Failed to add stream data to the record: %d\n", r);
1507 DeleteFile( "test.txt" );
1508
1509 query = "INSERT INTO `Binary` ( `Name`, `ID`, `Data` ) VALUES ( 'filename1', 1, ? )";
1510 r = run_query( hdb, rec, query );
1511 ok( r == ERROR_SUCCESS, "Insert into Binary table failed: %d\n", r );
1512
1513 r = MsiCloseHandle( rec );
1514 ok( r == ERROR_SUCCESS , "Failed to close record handle\n" );
1515
1516 r = MsiDatabaseCommit( hdb );
1517 ok( r == ERROR_SUCCESS , "Failed to commit database\n" );
1518
1519 r = MsiCloseHandle( hdb );
1520 ok( r == ERROR_SUCCESS , "Failed to close database\n" );
1521
1522 /* read file from the Stream table */
1523 r = MsiOpenDatabase( msifile, MSIDBOPEN_READONLY, &hdb );
1524 ok( r == ERROR_SUCCESS , "Failed to open database\n" );
1525
1526 query = "SELECT * FROM `_Streams`";
1527 r = do_query( hdb, query, &rec );
1528 ok( r == ERROR_SUCCESS, "SELECT query failed: %d\n", r );
1529
1530 size = MAX_PATH;
1531 r = MsiRecordGetString( rec, 1, file, &size );
1532 ok( r == ERROR_SUCCESS, "Failed to get string: %d\n", r );
1533 ok( !lstrcmp(file, "Binary.filename1.1"), "Expected 'Binary.filename1.1', got %s\n", file );
1534
1535 size = MAX_PATH;
1536 memset( buf, 0, MAX_PATH );
1537 r = MsiRecordReadStream( rec, 2, buf, &size );
1538 ok( r == ERROR_SUCCESS, "Failed to get stream: %d\n", r );
1539 ok( !lstrcmp(buf, "test.txt\n"), "Expected 'test.txt\\n', got %s\n", buf );
1540
1541 r = MsiCloseHandle( rec );
1542 ok( r == ERROR_SUCCESS , "Failed to close record handle\n" );
1543
1544 /* read file from the Binary table */
1545 query = "SELECT * FROM `Binary`";
1546 r = do_query( hdb, query, &rec );
1547 ok( r == ERROR_SUCCESS, "SELECT query failed: %d\n", r );
1548
1549 size = MAX_PATH;
1550 r = MsiRecordGetString( rec, 1, file, &size );
1551 ok( r == ERROR_SUCCESS, "Failed to get string: %d\n", r );
1552 ok( !lstrcmp(file, "filename1"), "Expected 'filename1', got %s\n", file );
1553
1554 size = MAX_PATH;
1555 memset( buf, 0, MAX_PATH );
1556 r = MsiRecordReadStream( rec, 3, buf, &size );
1557 ok( r == ERROR_SUCCESS, "Failed to get stream: %d\n", r );
1558 ok( !lstrcmp(buf, "test.txt\n"), "Expected 'test.txt\\n', got %s\n", buf );
1559
1560 r = MsiCloseHandle( rec );
1561 ok( r == ERROR_SUCCESS , "Failed to close record handle\n" );
1562
1563 r = MsiCloseHandle( hdb );
1564 ok( r == ERROR_SUCCESS , "Failed to close database\n" );
1565
1566 DeleteFile( msifile );
1567 }
1568
1569 static void test_where(void)
1570 {
1571 MSIHANDLE hdb = 0, rec, view;
1572 LPCSTR query;
1573 UINT r;
1574 DWORD size;
1575 CHAR buf[MAX_PATH];
1576 UINT count;
1577
1578 hdb = create_db();
1579 ok( hdb, "failed to create db\n");
1580
1581 r = run_query( hdb, 0,
1582 "CREATE TABLE `Media` ("
1583 "`DiskId` SHORT NOT NULL, "
1584 "`LastSequence` LONG, "
1585 "`DiskPrompt` CHAR(64) LOCALIZABLE, "
1586 "`Cabinet` CHAR(255), "
1587 "`VolumeLabel` CHAR(32), "
1588 "`Source` CHAR(72) "
1589 "PRIMARY KEY `DiskId`)" );
1590 ok( r == S_OK, "cannot create Media table: %d\n", r );
1591
1592 r = run_query( hdb, 0, "INSERT INTO `Media` "
1593 "( `DiskId`, `LastSequence`, `DiskPrompt`, `Cabinet`, `VolumeLabel`, `Source` ) "
1594 "VALUES ( 1, 0, '', 'zero.cab', '', '' )" );
1595 ok( r == S_OK, "cannot add file to the Media table: %d\n", r );
1596
1597 r = run_query( hdb, 0, "INSERT INTO `Media` "
1598 "( `DiskId`, `LastSequence`, `DiskPrompt`, `Cabinet`, `VolumeLabel`, `Source` ) "
1599 "VALUES ( 2, 1, '', 'one.cab', '', '' )" );
1600 ok( r == S_OK, "cannot add file to the Media table: %d\n", r );
1601
1602 r = run_query( hdb, 0, "INSERT INTO `Media` "
1603 "( `DiskId`, `LastSequence`, `DiskPrompt`, `Cabinet`, `VolumeLabel`, `Source` ) "
1604 "VALUES ( 3, 2, '', 'two.cab', '', '' )" );
1605 ok( r == S_OK, "cannot add file to the Media table: %d\n", r );
1606
1607 query = "SELECT * FROM `Media`";
1608 r = do_query(hdb, query, &rec);
1609 ok(r == ERROR_SUCCESS, "MsiViewFetch failed: %d\n", r);
1610 ok( check_record( rec, 4, "zero.cab"), "wrong cabinet\n");
1611 MsiCloseHandle( rec );
1612
1613 query = "SELECT * FROM `Media` WHERE `LastSequence` >= 1";
1614 r = do_query(hdb, query, &rec);
1615 ok(r == ERROR_SUCCESS, "MsiViewFetch failed: %d\n", r);
1616 ok( check_record( rec, 4, "one.cab"), "wrong cabinet\n");
1617
1618 r = MsiRecordGetInteger(rec, 1);
1619 ok( 2 == r, "field wrong\n");
1620 r = MsiRecordGetInteger(rec, 2);
1621 ok( 1 == r, "field wrong\n");
1622 MsiCloseHandle( rec );
1623
1624 query = "SELECT `DiskId` FROM `Media` WHERE `LastSequence` >= 1 AND DiskId >= 0";
1625 r = MsiDatabaseOpenView(hdb, query, &view);
1626 ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
1627
1628 r = MsiViewExecute(view, 0);
1629 ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
1630
1631 r = MsiViewFetch(view, &rec);
1632 ok( r == ERROR_SUCCESS, "failed to fetch view: %d\n", r );
1633
1634 count = MsiRecordGetFieldCount( rec );
1635 ok( count == 1, "Expected 1 record fields, got %d\n", count );
1636
1637 size = MAX_PATH;
1638 r = MsiRecordGetString( rec, 1, buf, &size );
1639 ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
1640 ok( !lstrcmp( buf, "2" ),
1641 "For (row %d, column 1) expected '%d', got %s\n", 0, 2, buf );
1642 MsiCloseHandle( rec );
1643
1644 r = MsiViewFetch(view, &rec);
1645 ok( r == ERROR_SUCCESS, "failed to fetch view: %d\n", r );
1646
1647 size = MAX_PATH;
1648 r = MsiRecordGetString( rec, 1, buf, &size );
1649 ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
1650 ok( !lstrcmp( buf, "3" ),
1651 "For (row %d, column 1) expected '%d', got %s\n", 1, 3, buf );
1652 MsiCloseHandle( rec );
1653
1654 r = MsiViewFetch(view, &rec);
1655 ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
1656
1657 MsiViewClose(view);
1658 MsiCloseHandle(view);
1659
1660 MsiCloseHandle( rec );
1661
1662 rec = 0;
1663 query = "SELECT * FROM `Media` WHERE `DiskPrompt` IS NULL";
1664 r = do_query(hdb, query, &rec);
1665 ok( r == ERROR_SUCCESS, "query failed: %d\n", r );
1666 MsiCloseHandle( rec );
1667
1668 rec = MsiCreateRecord(1);
1669 MsiRecordSetString(rec, 1, "");
1670
1671 query = "SELECT * FROM `Media` WHERE `DiskPrompt` = ?";
1672 r = MsiDatabaseOpenView(hdb, query, &view);
1673 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1674 r = MsiViewExecute(view, rec);
1675 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1676
1677 MsiCloseHandle(rec);
1678
1679 r = MsiViewFetch(view, &rec);
1680 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1681
1682 MsiCloseHandle(rec);
1683 MsiViewClose(view);
1684 MsiCloseHandle(view);
1685
1686 MsiCloseHandle( hdb );
1687 DeleteFile(msifile);
1688 }
1689
1690 static CHAR CURR_DIR[MAX_PATH];
1691
1692 static const CHAR test_data[] = "FirstPrimaryColumn\tSecondPrimaryColumn\tShortInt\tShortIntNullable\tLongInt\tLongIntNullable\tString\tLocalizableString\tLocalizableStringNullable\n"
1693 "s255\ti2\ti2\tI2\ti4\tI4\tS255\tS0\ts0\n"
1694 "TestTable\tFirstPrimaryColumn\n"
1695 "stringage\t5\t2\t\t2147483640\t-2147483640\tanother string\tlocalizable\tduh\n";
1696
1697 static const CHAR two_primary[] = "PrimaryOne\tPrimaryTwo\n"
1698 "s255\ts255\n"
1699 "TwoPrimary\tPrimaryOne\tPrimaryTwo\n"
1700 "papaya\tleaf\n"
1701 "papaya\tflower\n";
1702
1703 static const CHAR endlines1[] = "A\tB\tC\tD\tE\tF\r\n"
1704 "s72\ts72\ts72\ts72\ts72\ts72\n"
1705 "Table\tA\r\n"
1706 "a\tb\tc\td\te\tf\n"
1707 "g\th\ti\t\rj\tk\tl\r\n";
1708
1709 static const CHAR endlines2[] = "A\tB\tC\tD\tE\tF\r"
1710 "s72\ts72\ts72\ts72\ts72\ts72\n"
1711 "Table2\tA\r\n"
1712 "a\tb\tc\td\te\tf\n"
1713 "g\th\ti\tj\tk\tl\r\n";
1714
1715 static const CHAR suminfo[] = "PropertyId\tValue\n"
1716 "i2\tl255\n"
1717 "_SummaryInformation\tPropertyId\n"
1718 "1\t1252\n"
1719 "2\tInstaller Database\n"
1720 "3\tInstaller description\n"
1721 "4\tWineHQ\n"
1722 "5\tInstaller\n"
1723 "6\tInstaller comments\n"
1724 "7\tIntel;1033\n"
1725 "9\t{12345678-1234-1234-1234-123456789012}\n"
1726 "12\t2009/04/12 15:46:11\n"
1727 "13\t2009/04/12 15:46:11\n"
1728 "14\t200\n"
1729 "15\t2\n"
1730 "18\tVim\n"
1731 "19\t2\n";
1732
1733 static void write_file(const CHAR *filename, const char *data, int data_size)
1734 {
1735 DWORD size;
1736
1737 HANDLE hf = CreateFile(filename, GENERIC_WRITE, 0, NULL,
1738 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1739
1740 WriteFile(hf, data, data_size, &size, NULL);
1741 CloseHandle(hf);
1742 }
1743
1744 static UINT add_table_to_db(MSIHANDLE hdb, LPCSTR table_data)
1745 {
1746 UINT r;
1747
1748 write_file("temp_file", table_data, (lstrlen(table_data) - 1) * sizeof(char));
1749 r = MsiDatabaseImportA(hdb, CURR_DIR, "temp_file");
1750 DeleteFileA("temp_file");
1751
1752 return r;
1753 }
1754
1755 static void test_suminfo_import(void)
1756 {
1757 MSIHANDLE hdb, hsi, view = 0;
1758 LPCSTR query;
1759 UINT r, count, size, type;
1760 char str_value[50];
1761 INT int_value;
1762 FILETIME ft_value;
1763
1764 GetCurrentDirectoryA(MAX_PATH, CURR_DIR);
1765
1766 r = MsiOpenDatabaseA(msifile, MSIDBOPEN_CREATE, &hdb);
1767 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
1768
1769 r = add_table_to_db(hdb, suminfo);
1770 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
1771
1772 /* _SummaryInformation is not imported as a regular table... */
1773
1774 query = "SELECT * FROM `_SummaryInformation`";
1775 r = MsiDatabaseOpenViewA(hdb, query, &view);
1776 ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %u\n", r);
1777 MsiCloseHandle(view);
1778
1779 /* ...its data is added to the special summary information stream */
1780
1781 r = MsiGetSummaryInformationA(hdb, NULL, 0, &hsi);
1782 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
1783
1784 r = MsiSummaryInfoGetPropertyCount(hsi, &count);
1785 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
1786 ok(count == 14, "Expected 14, got %u\n", count);
1787
1788 r = MsiSummaryInfoGetPropertyA(hsi, PID_CODEPAGE, &type, &int_value, NULL, NULL, NULL);
1789 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
1790 ok(type == VT_I2, "Expected VT_I2, got %u\n", type);
1791 ok(int_value == 1252, "Expected 1252, got %d\n", int_value);
1792
1793 size = sizeof(str_value);
1794 r = MsiSummaryInfoGetPropertyA(hsi, PID_TITLE, &type, NULL, NULL, str_value, &size);
1795 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
1796 ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
1797 ok(size == 18, "Expected 18, got %u\n", size);
1798 ok(!strcmp(str_value, "Installer Database"),
1799 "Expected \"Installer Database\", got %s\n", str_value);
1800
1801 size = sizeof(str_value);
1802 r = MsiSummaryInfoGetPropertyA(hsi, PID_SUBJECT, &type, NULL, NULL, str_value, &size);
1803 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
1804 ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
1805 ok(!strcmp(str_value, "Installer description"),
1806 "Expected \"Installer description\", got %s\n", str_value);
1807
1808 size = sizeof(str_value);
1809 r = MsiSummaryInfoGetPropertyA(hsi, PID_AUTHOR, &type, NULL, NULL, str_value, &size);
1810 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
1811 ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
1812 ok(!strcmp(str_value, "WineHQ"),
1813 "Expected \"WineHQ\", got %s\n", str_value);
1814
1815 size = sizeof(str_value);
1816 r = MsiSummaryInfoGetPropertyA(hsi, PID_KEYWORDS, &type, NULL, NULL, str_value, &size);
1817 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
1818 ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
1819 ok(!strcmp(str_value, "Installer"),
1820 "Expected \"Installer\", got %s\n", str_value);
1821
1822 size = sizeof(str_value);
1823 r = MsiSummaryInfoGetPropertyA(hsi, PID_COMMENTS, &type, NULL, NULL, str_value, &size);
1824 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
1825 ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
1826 ok(!strcmp(str_value, "Installer comments"),
1827 "Expected \"Installer comments\", got %s\n", str_value);
1828
1829 size = sizeof(str_value);
1830 r = MsiSummaryInfoGetPropertyA(hsi, PID_TEMPLATE, &type, NULL, NULL, str_value, &size);
1831 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
1832 ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
1833 ok(!strcmp(str_value, "Intel;1033"),
1834 "Expected \"Intel;1033\", got %s\n", str_value);
1835
1836 size = sizeof(str_value);
1837 r = MsiSummaryInfoGetPropertyA(hsi, PID_REVNUMBER, &type, NULL, NULL, str_value, &size);
1838 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
1839 ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
1840 ok(!strcmp(str_value, "{12345678-1234-1234-1234-123456789012}"),
1841 "Expected \"{12345678-1234-1234-1234-123456789012}\", got %s\n", str_value);
1842
1843 r = MsiSummaryInfoGetPropertyA(hsi, PID_CREATE_DTM, &type, NULL, &ft_value, NULL, NULL);
1844 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
1845 ok(type == VT_FILETIME, "Expected VT_FILETIME, got %u\n", type);
1846
1847 r = MsiSummaryInfoGetPropertyA(hsi, PID_LASTSAVE_DTM, &type, NULL, &ft_value, NULL, NULL);
1848 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
1849 ok(type == VT_FILETIME, "Expected VT_FILETIME, got %u\n", type);
1850
1851 r = MsiSummaryInfoGetPropertyA(hsi, PID_PAGECOUNT, &type, &int_value, NULL, NULL, NULL);
1852 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
1853 ok(type == VT_I4, "Expected VT_I4, got %u\n", type);
1854 ok(int_value == 200, "Expected 200, got %d\n", int_value);
1855
1856 r = MsiSummaryInfoGetPropertyA(hsi, PID_WORDCOUNT, &type, &int_value, NULL, NULL, NULL);
1857 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
1858 ok(type == VT_I4, "Expected VT_I4, got %u\n", type);
1859 ok(int_value == 2, "Expected 2, got %d\n", int_value);
1860
1861 r = MsiSummaryInfoGetPropertyA(hsi, PID_SECURITY, &type, &int_value, NULL, NULL, NULL);
1862 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
1863 ok(type == VT_I4, "Expected VT_I4, got %u\n", type);
1864 ok(int_value == 2, "Expected 2, got %d\n", int_value);
1865
1866 size = sizeof(str_value);
1867 r = MsiSummaryInfoGetPropertyA(hsi, PID_APPNAME, &type, NULL, NULL, str_value, &size);
1868 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
1869 ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
1870 ok(!strcmp(str_value, "Vim"), "Expected \"Vim\", got %s\n", str_value);
1871
1872 MsiCloseHandle(hsi);
1873 MsiCloseHandle(hdb);
1874 DeleteFileA(msifile);
1875 }
1876
1877 static void test_msiimport(void)
1878 {
1879 MSIHANDLE hdb, view, rec;
1880 LPCSTR query;
1881 UINT r, count;
1882 signed int i;
1883
1884 GetCurrentDirectoryA(MAX_PATH, CURR_DIR);
1885
1886 r = MsiOpenDatabaseA(msifile, MSIDBOPEN_CREATE, &hdb);
1887 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1888
1889 r = add_table_to_db(hdb, test_data);
1890 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1891
1892 r = add_table_to_db(hdb, two_primary);
1893 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1894
1895 r = add_table_to_db(hdb, endlines1);
1896 if (r == ERROR_FUNCTION_FAILED)
1897 {
1898 /* win9x doesn't handle this case */
1899 skip("endlines not handled correctly.\n");
1900 MsiCloseHandle(hdb);
1901 DeleteFileA(msifile);
1902 return;
1903 }
1904
1905 r = add_table_to_db(hdb, endlines2);
1906 ok(r == ERROR_FUNCTION_FAILED,
1907 "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
1908
1909 query = "SELECT * FROM `TestTable`";
1910 r = MsiDatabaseOpenView(hdb, query, &view);
1911 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1912
1913 r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec);
1914 count = MsiRecordGetFieldCount(rec);
1915 ok(count == 9, "Expected 9, got %d\n", count);
1916 ok(check_record(rec, 1, "FirstPrimaryColumn"), "Expected FirstPrimaryColumn\n");
1917 ok(check_record(rec, 2, "SecondPrimaryColumn"), "Expected SecondPrimaryColumn\n");
1918 ok(check_record(rec, 3, "ShortInt"), "Expected ShortInt\n");
1919 ok(check_record(rec, 4, "ShortIntNullable"), "Expected ShortIntNullalble\n");
1920 ok(check_record(rec, 5, "LongInt"), "Expected LongInt\n");
1921 ok(check_record(rec, 6, "LongIntNullable"), "Expected LongIntNullalble\n");
1922 ok(check_record(rec, 7, "String"), "Expected String\n");
1923 ok(check_record(rec, 8, "LocalizableString"), "Expected LocalizableString\n");
1924 ok(check_record(rec, 9, "LocalizableStringNullable"), "Expected LocalizableStringNullable\n");
1925 MsiCloseHandle(rec);
1926
1927 r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
1928 count = MsiRecordGetFieldCount(rec);
1929 ok(count == 9, "Expected 9, got %d\n", count);
1930 ok(check_record(rec, 1, "s255"), "Expected s255\n");
1931 ok(check_record(rec, 2, "i2"), "Expected i2\n");
1932 ok(check_record(rec, 3, "i2"), "Expected i2\n");
1933 ok(check_record(rec, 4, "I2"), "Expected I2\n");
1934 ok(check_record(rec, 5, "i4"), "Expected i4\n");
1935 ok(check_record(rec, 6, "I4"), "Expected I4\n");
1936 ok(check_record(rec, 7, "S255"), "Expected S255\n");
1937 ok(check_record(rec, 8, "S0"), "Expected S0\n");
1938 ok(check_record(rec, 9, "s0"), "Expected s0\n");
1939 MsiCloseHandle(rec);
1940
1941 query = "SELECT * FROM `TestTable`";
1942 r = do_query(hdb, query, &rec);
1943 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1944 ok(check_record(rec, 1, "stringage"), "Expected 'stringage'\n");
1945 ok(check_record(rec, 7, "another string"), "Expected 'another string'\n");
1946 ok(check_record(rec, 8, "localizable"), "Expected 'localizable'\n");
1947 ok(check_record(rec, 9, "duh"), "Expected 'duh'\n");
1948
1949 i = MsiRecordGetInteger(rec, 2);
1950 ok(i == 5, "Expected 5, got %d\n", i);
1951
1952 i = MsiRecordGetInteger(rec, 3);
1953 ok(i == 2, "Expected 2, got %d\n", i);
1954
1955 i = MsiRecordGetInteger(rec, 4);
1956 ok(i == MSI_NULL_INTEGER, "Expected MSI_NULL_INTEGER, got %d\n", i);
1957
1958 i = MsiRecordGetInteger(rec, 5);
1959 ok(i == 2147483640, "Expected 2147483640, got %d\n", i);
1960
1961 i = MsiRecordGetInteger(rec, 6);
1962 ok(i == -2147483640, "Expected -2147483640, got %d\n", i);
1963
1964 MsiCloseHandle(rec);
1965 MsiViewClose(view);
1966 MsiCloseHandle(view);
1967
1968 query = "SELECT * FROM `TwoPrimary`";
1969 r = MsiDatabaseOpenView(hdb, query, &view);
1970 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1971
1972 r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec);
1973 count = MsiRecordGetFieldCount(rec);
1974 ok(count == 2, "Expected 2, got %d\n", count);
1975 ok(check_record(rec, 1, "PrimaryOne"), "Expected PrimaryOne\n");
1976 ok(check_record(rec, 2, "PrimaryTwo"), "Expected PrimaryTwo\n");
1977
1978 MsiCloseHandle(rec);
1979
1980 r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
1981 count = MsiRecordGetFieldCount(rec);
1982 ok(count == 2, "Expected 2, got %d\n", count);
1983 ok(check_record(rec, 1, "s255"), "Expected s255\n");
1984 ok(check_record(rec, 2, "s255"), "Expected s255\n");
1985 MsiCloseHandle(rec);
1986
1987 r = MsiViewExecute(view, 0);
1988 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1989
1990 r = MsiViewFetch(view, &rec);
1991 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1992
1993 ok(check_record(rec, 1, "papaya"), "Expected 'papaya'\n");
1994 ok(check_record(rec, 2, "leaf"), "Expected 'leaf'\n");
1995
1996 MsiCloseHandle(rec);
1997
1998 r = MsiViewFetch(view, &rec);
1999 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2000
2001 ok(check_record(rec, 1, "papaya"), "Expected 'papaya'\n");
2002 ok(check_record(rec, 2, "flower"), "Expected 'flower'\n");
2003
2004 MsiCloseHandle(rec);
2005
2006 r = MsiViewFetch(view, &rec);
2007 ok(r == ERROR_NO_MORE_ITEMS,
2008 "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
2009
2010 r = MsiViewClose(view);
2011 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2012
2013 MsiCloseHandle(view);
2014
2015 query = "SELECT * FROM `Table`";
2016 r = MsiDatabaseOpenView(hdb, query, &view);
2017 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2018
2019 r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec);
2020 count = MsiRecordGetFieldCount(rec);
2021 ok(count == 6, "Expected 6, got %d\n", count);
2022 ok(check_record(rec, 1, "A"), "Expected A\n");
2023 ok(check_record(rec, 2, "B"), "Expected B\n");
2024 ok(check_record(rec, 3, "C"), "Expected C\n");
2025 ok(check_record(rec, 4, "D"), "Expected D\n");
2026 ok(check_record(rec, 5, "E"), "Expected E\n");
2027 ok(check_record(rec, 6, "F"), "Expected F\n");
2028 MsiCloseHandle(rec);
2029
2030 r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
2031 count = MsiRecordGetFieldCount(rec);
2032 ok(count == 6, "Expected 6, got %d\n", count);
2033 ok(check_record(rec, 1, "s72"), "Expected s72\n");
2034 ok(check_record(rec, 2, "s72"), "Expected s72\n");
2035 ok(check_record(rec, 3, "s72"), "Expected s72\n");
2036 ok(check_record(rec, 4, "s72"), "Expected s72\n");
2037 ok(check_record(rec, 5, "s72"), "Expected s72\n");
2038 ok(check_record(rec, 6, "s72"), "Expected s72\n");
2039 MsiCloseHandle(rec);
2040
2041 MsiViewClose(view);
2042 MsiCloseHandle(view);
2043
2044 query = "SELECT * FROM `Table`";
2045 r = MsiDatabaseOpenView(hdb, query, &view);
2046 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2047
2048 r = MsiViewExecute(view, 0);
2049 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2050
2051 r = MsiViewFetch(view, &rec);
2052 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2053 ok(check_record(rec, 1, "a"), "Expected 'a'\n");
2054 ok(check_record(rec, 2, "b"), "Expected 'b'\n");
2055 ok(check_record(rec, 3, "c"), "Expected 'c'\n");
2056 ok(check_record(rec, 4, "d"), "Expected 'd'\n");
2057 ok(check_record(rec, 5, "e"), "Expected 'e'\n");
2058 ok(check_record(rec, 6, "f"), "Expected 'f'\n");
2059
2060 MsiCloseHandle(rec);
2061
2062 r = MsiViewFetch(view, &rec);
2063 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2064 ok(check_record(rec, 1, "g"), "Expected 'g'\n");
2065 ok(check_record(rec, 2, "h"), "Expected 'h'\n");
2066 ok(check_record(rec, 3, "i"), "Expected 'i'\n");
2067 ok(check_record(rec, 4, "j"), "Expected 'j'\n");
2068 ok(check_record(rec, 5, "k"), "Expected 'k'\n");
2069 ok(check_record(rec, 6, "l"), "Expected 'l'\n");
2070
2071 MsiCloseHandle(rec);
2072
2073 r = MsiViewFetch(view, &rec);
2074 ok(r == ERROR_NO_MORE_ITEMS,
2075 "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
2076
2077 MsiViewClose(view);
2078 MsiCloseHandle(view);
2079 MsiCloseHandle(hdb);
2080 DeleteFileA(msifile);
2081 }
2082
2083 static const CHAR bin_import_dat[] = "Name\tData\r\n"
2084 "s72\tV0\r\n"
2085 "Binary\tName\r\n"
2086 "filename1\tfilename1.ibd\r\n";
2087
2088 static void test_binary_import(void)
2089 {
2090 MSIHANDLE hdb = 0, rec;
2091 char file[MAX_PATH];
2092 char buf[MAX_PATH];
2093 char path[MAX_PATH];
2094 DWORD size;
2095 LPCSTR query;
2096 UINT r;
2097
2098 /* create files to import */
2099 write_file("bin_import.idt", bin_import_dat,
2100 (sizeof(bin_import_dat) - 1) * sizeof(char));
2101 CreateDirectory("bin_import", NULL);
2102 create_file_data("bin_import/filename1.ibd", "just some words", 15);
2103
2104 /* import files into database */
2105 r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
2106 ok( r == ERROR_SUCCESS , "Failed to open database\n");
2107
2108 GetCurrentDirectory(MAX_PATH, path);
2109 r = MsiDatabaseImport(hdb, path, "bin_import.idt");
2110 ok(r == ERROR_SUCCESS , "Failed to import Binary table\n");
2111
2112 /* read file from the Binary table */
2113 query = "SELECT * FROM `Binary`";
2114 r = do_query(hdb, query, &rec);
2115 ok(r == ERROR_SUCCESS, "SELECT query failed: %d\n", r);
2116
2117 size = MAX_PATH;
2118 r = MsiRecordGetString(rec, 1, file, &size);
2119 ok(r == ERROR_SUCCESS, "Failed to get string: %d\n", r);
2120 ok(!lstrcmp(file, "filename1"), "Expected 'filename1', got %s\n", file);
2121
2122 size = MAX_PATH;
2123 memset(buf, 0, MAX_PATH);
2124 r = MsiRecordReadStream(rec, 2, buf, &size);
2125 ok(r == ERROR_SUCCESS, "Failed to get stream: %d\n", r);
2126 ok(!lstrcmp(buf, "just some words"),
2127 "Expected 'just some words', got %s\n", buf);
2128
2129 r = MsiCloseHandle(rec);
2130 ok(r == ERROR_SUCCESS , "Failed to close record handle\n");
2131
2132 r = MsiCloseHandle(hdb);
2133 ok(r == ERROR_SUCCESS , "Failed to close database\n");
2134
2135 DeleteFile("bin_import/filename1.ibd");
2136 RemoveDirectory("bin_import");
2137 DeleteFile("bin_import.idt");
2138 }
2139
2140 static void test_markers(void)
2141 {
2142 MSIHANDLE hdb, rec;
2143 LPCSTR query;
2144 UINT r;
2145
2146 hdb = create_db();
2147 ok( hdb, "failed to create db\n");
2148
2149 rec = MsiCreateRecord(3);
2150 MsiRecordSetString(rec, 1, "Table");
2151 MsiRecordSetString(rec, 2, "Apples");
2152 MsiRecordSetString(rec, 3, "Oranges");
2153
2154 /* try a legit create */
2155 query = "CREATE TABLE `Table` ( `One` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`)";
2156 r = run_query(hdb, 0, query);
2157 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2158 MsiCloseHandle(rec);
2159
2160 /* try table name as marker */
2161 rec = MsiCreateRecord(1);
2162 MsiRecordSetString(rec, 1, "Fable");
2163 query = "CREATE TABLE `?` ( `One` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`)";
2164 r = run_query(hdb, rec, query);
2165 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2166
2167 /* verify that we just created a table called '?', not 'Fable' */
2168 r = try_query(hdb, "SELECT * from `Fable`");
2169 ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2170
2171 r = try_query(hdb, "SELECT * from `?`");
2172 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2173
2174 /* try table name as marker without backticks */
2175 MsiRecordSetString(rec, 1, "Mable");
2176 query = "CREATE TABLE ? ( `One` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`)";
2177 r = run_query(hdb, rec, query);
2178 ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2179
2180 /* try one column name as marker */
2181 MsiRecordSetString(rec, 1, "One");
2182 query = "CREATE TABLE `Mable` ( `?` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`)";
2183 r = run_query(hdb, rec, query);
2184 ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2185 MsiCloseHandle(rec);
2186
2187 /* try column names as markers */
2188 rec = MsiCreateRecord(2);
2189 MsiRecordSetString(rec, 1, "One");
2190 MsiRecordSetString(rec, 2, "Two");
2191 query = "CREATE TABLE `Mable` ( `?` SHORT NOT NULL, `?` CHAR(255) PRIMARY KEY `One`)";
2192 r = run_query(hdb, rec, query);
2193 ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2194 MsiCloseHandle(rec);
2195
2196 /* try names with backticks */
2197 rec = MsiCreateRecord(3);
2198 MsiRecordSetString(rec, 1, "One");
2199 MsiRecordSetString(rec, 2, "Two");
2200 MsiRecordSetString(rec, 3, "One");
2201 query = "CREATE TABLE `Mable` ( `?` SHORT NOT NULL, `?` CHAR(255) PRIMARY KEY `?`)";
2202 r = run_query(hdb, rec, query);
2203 ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2204
2205 /* try names with backticks, minus definitions */
2206 query = "CREATE TABLE `Mable` ( `?`, `?` PRIMARY KEY `?`)";
2207 r = run_query(hdb, rec, query);
2208 ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2209
2210 /* try names without backticks */
2211 query = "CREATE TABLE `Mable` ( ? SHORT NOT NULL, ? CHAR(255) PRIMARY KEY ?)";
2212 r = run_query(hdb, rec, query);
2213 ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2214 MsiCloseHandle(rec);
2215
2216 /* try one long marker */
2217 rec = MsiCreateRecord(1);
2218 MsiRecordSetString(rec, 1, "`One` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`");
2219 query = "CREATE TABLE `Mable` ( ? )";
2220 r = run_query(hdb, rec, query);
2221 ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2222 MsiCloseHandle(rec);
2223
2224 /* try all names as markers */
2225 rec = MsiCreateRecord(4);
2226 MsiRecordSetString(rec, 1, "Mable");
2227 MsiRecordSetString(rec, 2, "One");
2228 MsiRecordSetString(rec, 3, "Two");
2229 MsiRecordSetString(rec, 4, "One");
2230 query = "CREATE TABLE `?` ( `?` SHORT NOT NULL, `?` CHAR(255) PRIMARY KEY `?`)";
2231 r = run_query(hdb, rec, query);
2232 ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2233 MsiCloseHandle(rec);
2234
2235 /* try a legit insert */
2236 query = "INSERT INTO `Table` ( `One`, `Two` ) VALUES ( 5, 'hello' )";
2237 r = run_query(hdb, 0, query);
2238 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2239
2240 r = try_query(hdb, "SELECT * from `Table`");
2241 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2242
2243 /* try values as markers */
2244 rec = MsiCreateRecord(2);
2245 MsiRecordSetInteger(rec, 1, 4);
2246 MsiRecordSetString(rec, 2, "hi");
2247 query = "INSERT INTO `Table` ( `One`, `Two` ) VALUES ( ?, '?' )";
2248 r = run_query(hdb, rec, query);
2249 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2250 MsiCloseHandle(rec);
2251
2252 /* try column names and values as markers */
2253 rec = MsiCreateRecord(4);
2254 MsiRecordSetString(rec, 1, "One");
2255 MsiRecordSetString(rec, 2, "Two");
2256 MsiRecordSetInteger(rec, 3, 5);
2257 MsiRecordSetString(rec, 4, "hi");
2258 query = "INSERT INTO `Table` ( `?`, `?` ) VALUES ( ?, '?' )";
2259 r = run_query(hdb, rec, query);
2260 ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2261 MsiCloseHandle(rec);
2262
2263 /* try column names as markers */
2264 rec = MsiCreateRecord(2);
2265 MsiRecordSetString(rec, 1, "One");
2266 MsiRecordSetString(rec, 2, "Two");
2267 query = "INSERT INTO `Table` ( `?`, `?` ) VALUES ( 3, 'yellow' )";
2268 r = run_query(hdb, rec, query);
2269 ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2270 MsiCloseHandle(rec);
2271
2272 /* try table name as a marker */
2273 rec = MsiCreateRecord(1);
2274 MsiRecordSetString(rec, 1, "Table");
2275 query = "INSERT INTO `?` ( `One`, `Two` ) VALUES ( 2, 'green' )";
2276 r = run_query(hdb, rec, query);
2277 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2278 MsiCloseHandle(rec);
2279
2280 /* try table name and values as markers */
2281 rec = MsiCreateRecord(3);
2282 MsiRecordSetString(rec, 1, "Table");
2283 MsiRecordSetInteger(rec, 2, 10);
2284 MsiRecordSetString(rec, 3, "haha");
2285 query = "INSERT INTO `?` ( `One`, `Two` ) VALUES ( ?, '?' )";
2286 r = run_query(hdb, rec, query);
2287 ok(r == ERROR_FUNCTION_FAILED, "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
2288 MsiCloseHandle(rec);
2289
2290 /* try all markers */
2291 rec = MsiCreateRecord(5);
2292 MsiRecordSetString(rec, 1, "Table");
2293 MsiRecordSetString(rec, 1, "One");
2294 MsiRecordSetString(rec, 1, "Two");
2295 MsiRecordSetInteger(rec, 2, 10);
2296 MsiRecordSetString(rec, 3, "haha");
2297 query = "INSERT INTO `?` ( `?`, `?` ) VALUES ( ?, '?' )";
2298 r = run_query(hdb, rec, query);
2299 ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2300 MsiCloseHandle(rec);
2301
2302 /* insert an integer as a string */
2303 rec = MsiCreateRecord(2);
2304 MsiRecordSetString(rec, 1, "11");
2305 MsiRecordSetString(rec, 2, "hi");
2306 query = "INSERT INTO `Table` ( `One`, `Two` ) VALUES ( ?, '?' )";
2307 r = run_query(hdb, rec, query);
2308 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2309 MsiCloseHandle(rec);
2310
2311 /* leave off the '' for the string */
2312 rec = MsiCreateRecord(2);
2313 MsiRecordSetInteger(rec, 1, 12);
2314 MsiRecordSetString(rec, 2, "hi");
2315 query = "INSERT INTO `Table` ( `One`, `Two` ) VALUES ( ?, ? )";
2316 r = run_query(hdb, rec, query);
2317 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2318 MsiCloseHandle(rec);
2319
2320 MsiCloseHandle(hdb);
2321 DeleteFileA(msifile);
2322 }
2323
2324 #define MY_NVIEWS 4000 /* Largest installer I've seen uses < 2k */
2325 static void test_handle_limit(void)
2326 {
2327 int i;
2328 MSIHANDLE hdb;
2329 MSIHANDLE hviews[MY_NVIEWS];
2330 UINT r;
2331
2332 /* create an empty db */
2333 hdb = create_db();
2334 ok( hdb, "failed to create db\n");
2335
2336 memset(hviews, 0, sizeof(hviews));
2337
2338 for (i=0; i<MY_NVIEWS; i++) {
2339 static char szQueryBuf[256] = "SELECT * from `_Tables`";
2340 hviews[i] = 0xdeadbeeb;
2341 r = MsiDatabaseOpenView(hdb, szQueryBuf, &hviews[i]);
2342 if( r != ERROR_SUCCESS || hviews[i] == 0xdeadbeeb ||
2343 hviews[i] == 0 || (i && (hviews[i] == hviews[i-1])))
2344 break;
2345 }
2346
2347 ok( i == MY_NVIEWS, "problem opening views\n");
2348
2349 for (i=0; i<MY_NVIEWS; i++) {
2350 if (hviews[i] != 0 && hviews[i] != 0xdeadbeeb) {
2351 MsiViewClose(hviews[i]);
2352 r = MsiCloseHandle(hviews[i]);
2353 if (r != ERROR_SUCCESS)
2354 break;
2355 }
2356 }
2357
2358 ok( i == MY_NVIEWS, "problem closing views\n");
2359
2360 r = MsiCloseHandle(hdb);
2361 ok( r == ERROR_SUCCESS, "failed to close database\n");
2362 }
2363
2364 static void generate_transform(void)
2365 {
2366 MSIHANDLE hdb1, hdb2, hrec;
2367 LPCSTR query;
2368 UINT r;
2369
2370 /* start with two identical databases */
2371 CopyFile(msifile2, msifile, FALSE);
2372
2373 r = MsiOpenDatabase(msifile, MSIDBOPEN_TRANSACT, &hdb1 );
2374 ok( r == ERROR_SUCCESS , "Failed to create database\n" );
2375
2376 r = MsiDatabaseCommit( hdb1 );
2377 ok( r == ERROR_SUCCESS , "Failed to commit database\n" );
2378
2379 r = MsiOpenDatabase(msifile2, MSIDBOPEN_READONLY, &hdb2 );
2380 ok( r == ERROR_SUCCESS , "Failed to create database\n" );
2381
2382 /* the transform between two identical database should be empty */
2383 r = MsiDatabaseGenerateTransform(hdb1, hdb2, NULL, 0, 0);
2384 todo_wine {
2385 ok( r == ERROR_NO_DATA, "return code %d, should be ERROR_NO_DATA\n", r );
2386 }
2387
2388 query = "CREATE TABLE `AAR` ( `BAR` SHORT NOT NULL, `CAR` CHAR(255) PRIMARY KEY `CAR`)";
2389 r = run_query(hdb1, 0, query);
2390 ok(r == ERROR_SUCCESS, "failed to add table\n");
2391
2392 query = "INSERT INTO `AAR` ( `BAR`, `CAR` ) VALUES ( 1, 'vw' )";
2393 r = run_query(hdb1, 0, query);
2394 ok(r == ERROR_SUCCESS, "failed to add row 1\n");
2395
2396 query = "INSERT INTO `AAR` ( `BAR`, `CAR` ) VALUES ( 2, 'bmw' )";
2397 r = run_query(hdb1, 0, query);
2398 ok(r == ERROR_SUCCESS, "failed to add row 2\n");
2399
2400 query = "UPDATE `MOO` SET `OOO` = 'c' WHERE `NOO` = 1";
2401 r = run_query(hdb1, 0, query);
2402 ok(r == ERROR_SUCCESS, "failed to modify row\n");
2403
2404 query = "DELETE FROM `MOO` WHERE `NOO` = 3";
2405 r = run_query(hdb1, 0, query);
2406 ok(r == ERROR_SUCCESS, "failed to delete row\n");
2407
2408 hrec = MsiCreateRecord(2);
2409 r = MsiRecordSetInteger(hrec, 1, 1);
2410 ok(r == ERROR_SUCCESS, "failed to set integer\n");
2411
2412 write_file("testdata.bin", "naengmyon", 9);
2413 r = MsiRecordSetStream(hrec, 2, "testdata.bin");
2414 ok(r == ERROR_SUCCESS, "failed to set stream\n");
2415
2416 query = "INSERT INTO `BINARY` ( `ID`, `BLOB` ) VALUES ( ?, ? )";
2417 r = run_query(hdb1, hrec, query);
2418 ok(r == ERROR_SUCCESS, "failed to add row with blob\n");
2419
2420 MsiCloseHandle(hrec);
2421
2422 query = "ALTER TABLE `MOO` ADD `COW` INTEGER";
2423 r = run_query(hdb1, 0, query);
2424 ok(r == ERROR_SUCCESS, "failed to add column\n");
2425
2426 query = "ALTER TABLE `MOO` ADD `PIG` INTEGER";
2427 r = run_query(hdb1, 0, query);
2428 ok(r == ERROR_SUCCESS, "failed to add column\n");
2429
2430 query = "UPDATE `MOO` SET `PIG` = 5 WHERE `NOO` = 1";
2431 r = run_query(hdb1, 0, query);
2432 ok(r == ERROR_SUCCESS, "failed to modify row\n");
2433
2434 query = "CREATE TABLE `Property` ( `Property` CHAR(72) NOT NULL, "
2435 "`Value` CHAR(0) PRIMARY KEY `Property`)";
2436 r = run_query(hdb1, 0, query);
2437 ok(r == ERROR_SUCCESS, "failed to add property table\n");
2438
2439 query = "INSERT INTO `Property` ( `Property`, `Value` ) VALUES ( 'prop', 'val' )";
2440 r = run_query(hdb1, 0, query);
2441 ok(r == ERROR_SUCCESS, "failed to add property\n");
2442
2443 /* database needs to be committed */
2444 MsiDatabaseCommit(hdb1);
2445
2446 r = MsiDatabaseGenerateTransform(hdb1, hdb2, mstfile, 0, 0);
2447 ok( r == ERROR_SUCCESS, "return code %d, should be ERROR_SUCCESS\n", r );
2448
2449 MsiCloseHandle( hdb1 );
2450 MsiCloseHandle( hdb2 );
2451
2452 DeleteFile("testdata.bin");
2453 }
2454
2455 /* data for generating a transform */
2456
2457 /* tables transform names - encoded as they would be in an msi database file */
2458 static const WCHAR name1[] = { 0x4840, 0x3a8a, 0x481b, 0 }; /* AAR */
2459 static const WCHAR name2[] = { 0x4840, 0x3b3f, 0x43f2, 0x4438, 0x45b1, 0 }; /* _Columns */
2460 static const WCHAR name3[] = { 0x4840, 0x3f7f, 0x4164, 0x422f, 0x4836, 0 }; /* _Tables */
2461 static const WCHAR name4[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0 }; /* _StringData */
2462 static const WCHAR name5[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0 }; /* _StringPool */
2463 static const WCHAR name6[] = { 0x4840, 0x3e16, 0x4818, 0}; /* MOO */
2464 static const WCHAR name7[] = { 0x4840, 0x3c8b, 0x3a97, 0x409b, 0 }; /* BINARY */
2465 static const WCHAR name8[] = { 0x3c8b, 0x3a97, 0x409b, 0x387e, 0 }; /* BINARY.1 */
2466 static const WCHAR name9[] = { 0x4840, 0x4559, 0x44f2, 0x4568, 0x4737, 0 }; /* Property */
2467
2468 /* data in each table */
2469 static const WCHAR data1[] = { /* AAR */
2470 0x0201, 0x0008, 0x8001, /* 0x0201 = add row (1), two shorts */
2471 0x0201, 0x0009, 0x8002,
2472 };
2473 static const WCHAR data2[] = { /* _Columns */
2474 0x0401, 0x0001, 0x8003, 0x0002, 0x9502,
2475 0x0401, 0x0001, 0x8004, 0x0003, 0x9502,
2476 0x0401, 0x0005, 0x0000, 0x0006, 0xbdff, /* 0x0401 = add row (1), 4 shorts */
2477 0x0401, 0x0005, 0x0000, 0x0007, 0x8502,
2478 0x0401, 0x000a, 0x0000, 0x000a, 0xad48,
2479 0x0401, 0x000a, 0x0000, 0x000b, 0x9d00,
2480 };
2481 static const WCHAR data3[] = { /* _Tables */
2482 0x0101, 0x0005, /* 0x0101 = add row (1), 1 short */
2483 0x0101, 0x000a,
2484 };
2485 static const char data4[] = /* _StringData */
2486 "MOOCOWPIGcAARCARBARvwbmwPropertyValuepropval"; /* all the strings squashed together */
2487 static const WCHAR data5[] = { /* _StringPool */
2488 /* len, refs */
2489 0, 0, /* string 0 '' */
2490 3, 2, /* string 1 'MOO' */
2491 3, 1, /* string 2 'COW' */
2492 3, 1, /* string 3 'PIG' */
2493 1, 1, /* string 4 'c' */
2494 3, 3, /* string 5 'AAR' */
2495 3, 1, /* string 6 'CAR' */
2496 3, 1, /* string 7 'BAR' */
2497 2, 1, /* string 8 'vw' */
2498 3, 1, /* string 9 'bmw' */
2499 8, 4, /* string 10 'Property' */
2500 5, 1, /* string 11 'Value' */
2501 4, 1, /* string 12 'prop' */
2502 3, 1, /* string 13 'val' */
2503 };
2504 /* update row, 0x0002 is a bitmask of present column data, keys are excluded */
2505 static const WCHAR data6[] = { /* MOO */
2506 0x000a, 0x8001, 0x0004, 0x8005, /* update row */
2507 0x0000, 0x8003, /* delete row */
2508 };
2509
2510 static const WCHAR data7[] = { /* BINARY */
2511 0x0201, 0x8001, 0x0001,
2512 };
2513
2514 static const char data8[] = /* stream data for the BINARY table */
2515 "naengmyon";
2516
2517 static const WCHAR data9[] = { /* Property */
2518 0x0201, 0x000c, 0x000d,
2519 };
2520
2521 static const struct {
2522 LPCWSTR name;
2523 const void *data;
2524 DWORD size;
2525 } table_transform_data[] =
2526 {
2527 { name1, data1, sizeof data1 },
2528 { name2, data2, sizeof data2 },
2529 { name3, data3, sizeof data3 },
2530 { name4, data4, sizeof data4 - 1 },
2531 { name5, data5, sizeof data5 },
2532 { name6, data6, sizeof data6 },
2533 { name7, data7, sizeof data7 },
2534 { name8, data8, sizeof data8 - 1 },
2535 { name9, data9, sizeof data9 },
2536 };
2537
2538 #define NUM_TRANSFORM_TABLES (sizeof table_transform_data/sizeof table_transform_data[0])
2539
2540 static void generate_transform_manual(void)
2541 {
2542 IStorage *stg = NULL;
2543 IStream *stm;
2544 WCHAR name[0x20];
2545 HRESULT r;
2546 DWORD i, count;
2547 const DWORD mode = STGM_CREATE|STGM_READWRITE|STGM_DIRECT|STGM_SHARE_EXCLUSIVE;
2548
2549 const CLSID CLSID_MsiTransform = { 0xc1082,0,0,{0xc0,0,0,0,0,0,0,0x46}};
2550
2551 MultiByteToWideChar(CP_ACP, 0, mstfile, -1, name, 0x20);
2552
2553 r = StgCreateDocfile(name, mode, 0, &stg);
2554 ok(r == S_OK, "failed to create storage\n");
2555 if (!stg)
2556 return;
2557
2558 r = IStorage_SetClass( stg, &CLSID_MsiTransform );
2559 ok(r == S_OK, "failed to set storage type\n");
2560
2561 for (i=0; i<NUM_TRANSFORM_TABLES; i++)
2562 {
2563 r = IStorage_CreateStream( stg, table_transform_data[i].name,
2564 STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stm );
2565 if (FAILED(r))
2566 {
2567 ok(0, "failed to create stream %08x\n", r);
2568 continue;
2569 }
2570
2571 r = IStream_Write( stm, table_transform_data[i].data,
2572 table_transform_data[i].size, &count );
2573 if (FAILED(r) || count != table_transform_data[i].size)
2574 ok(0, "failed to write stream\n");
2575 IStream_Release(stm);
2576 }
2577
2578 IStorage_Release(stg);
2579 }
2580
2581 static UINT set_summary_info(MSIHANDLE hdb)
2582 {
2583 UINT res;
2584 MSIHANDLE suminfo;
2585
2586 /* build summary info */
2587 res = MsiGetSummaryInformation(hdb, NULL, 7, &suminfo);
2588 ok( res == ERROR_SUCCESS , "Failed to open summaryinfo\n" );
2589
2590 res = MsiSummaryInfoSetProperty(suminfo,2, VT_LPSTR, 0,NULL,
2591 "Installation Database");
2592 ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
2593
2594 res = MsiSummaryInfoSetProperty(suminfo,3, VT_LPSTR, 0,NULL,
2595 "Installation Database");
2596 ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
2597
2598 res = MsiSummaryInfoSetProperty(suminfo,4, VT_LPSTR, 0,NULL,
2599 "Wine Hackers");
2600 ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
2601
2602 res = MsiSummaryInfoSetProperty(suminfo,7, VT_LPSTR, 0,NULL,
2603 ";1033");
2604 ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
2605
2606 res = MsiSummaryInfoSetProperty(suminfo,9, VT_LPSTR, 0,NULL,
2607 "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}");
2608 ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
2609
2610 res = MsiSummaryInfoSetProperty(suminfo, 14, VT_I4, 100, NULL, NULL);
2611 ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
2612
2613 res = MsiSummaryInfoSetProperty(suminfo, 15, VT_I4, 0, NULL, NULL);
2614 ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
2615
2616 res = MsiSummaryInfoPersist(suminfo);
2617 ok( res == ERROR_SUCCESS , "Failed to make summary info persist\n" );
2618
2619 res = MsiCloseHandle( suminfo);
2620 ok( res == ERROR_SUCCESS , "Failed to close suminfo\n" );
2621
2622 return res;
2623 }
2624
2625 static MSIHANDLE create_package_db(LPCSTR filename)
2626 {
2627 MSIHANDLE hdb = 0;
2628 UINT res;
2629
2630 DeleteFile(msifile);
2631
2632 /* create an empty database */
2633 res = MsiOpenDatabase(filename, MSIDBOPEN_CREATE, &hdb );
2634 ok( res == ERROR_SUCCESS , "Failed to create database\n" );
2635 if( res != ERROR_SUCCESS )
2636 return hdb;
2637
2638 res = MsiDatabaseCommit( hdb );
2639 ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
2640
2641 res = set_summary_info(hdb);
2642
2643 res = create_directory_table(hdb);
2644 ok( res == ERROR_SUCCESS , "Failed to create directory table\n" );
2645
2646 return hdb;
2647 }
2648
2649 static MSIHANDLE package_from_db(MSIHANDLE hdb)
2650 {
2651 UINT res;
2652 CHAR szPackage[10];
2653 MSIHANDLE hPackage;
2654
2655 sprintf(szPackage,"#%i",hdb);
2656 res = MsiOpenPackage(szPackage,&hPackage);
2657 if (res != ERROR_SUCCESS)
2658 return 0;
2659
2660 res = MsiCloseHandle(hdb);
2661 if (res != ERROR_SUCCESS)
2662 return 0;
2663
2664 return hPackage;
2665 }
2666
2667 static void test_try_transform(void)
2668 {
2669 MSIHANDLE hdb, hview, hrec, hpkg;
2670 LPCSTR query;
2671 UINT r;
2672 DWORD sz;
2673 char buffer[MAX_PATH];
2674
2675 DeleteFile(msifile);
2676 DeleteFile(mstfile);
2677
2678 /* create the database */
2679 hdb = create_package_db(msifile);
2680 ok(hdb, "Failed to create package db\n");
2681
2682 query = "CREATE TABLE `MOO` ( `NOO` SHORT NOT NULL, `OOO` CHAR(255) PRIMARY KEY `NOO`)";
2683 r = run_query(hdb, 0, query);
2684 ok(r == ERROR_SUCCESS, "failed to add table\n");
2685
2686 query = "INSERT INTO `MOO` ( `NOO`, `OOO` ) VALUES ( 1, 'a' )";
2687 r = run_query(hdb, 0, query);
2688 ok(r == ERROR_SUCCESS, "failed to add row\n");
2689
2690 query = "INSERT INTO `MOO` ( `NOO`, `OOO` ) VALUES ( 2, 'b' )";
2691 r = run_query(hdb, 0, query);
2692 ok(r == ERROR_SUCCESS, "failed to add row\n");
2693
2694 query = "INSERT INTO `MOO` ( `NOO`, `OOO` ) VALUES ( 3, 'c' )";
2695 r = run_query(hdb, 0, query);
2696 ok(r == ERROR_SUCCESS, "failed to add row\n");
2697
2698 query = "CREATE TABLE `BINARY` ( `ID` SHORT NOT NULL, `BLOB` OBJECT PRIMARY KEY `ID`)";
2699 r = run_query(hdb, 0, query);
2700 ok(r == ERROR_SUCCESS, "failed to add table\n");
2701
2702 hrec = MsiCreateRecord(2);
2703 r = MsiRecordSetInteger(hrec, 1, 2);
2704 ok(r == ERROR_SUCCESS, "failed to set integer\n");
2705
2706 write_file("testdata.bin", "lamyon", 6);
2707 r = MsiRecordSetStream(hrec, 2, "testdata.bin");
2708 ok(r == ERROR_SUCCESS, "failed to set stream\n");
2709
2710 query = "INSERT INTO `BINARY` ( `ID`, `BLOB` ) VALUES ( ?, ? )";
2711 r = run_query(hdb, hrec, query);
2712 ok(r == ERROR_SUCCESS, "failed to add row with blob\n");
2713
2714 MsiCloseHandle(hrec);
2715
2716 r = MsiDatabaseCommit( hdb );
2717 ok( r == ERROR_SUCCESS , "Failed to commit database\n" );
2718
2719 MsiCloseHandle( hdb );
2720 DeleteFileA("testdata.bin");
2721
2722 /*
2723 * Both these generate an equivalent transform,
2724 * but the first doesn't work in Wine yet
2725 * because MsiDatabaseGenerateTransform is unimplemented.
2726 */
2727 if (0)
2728 generate_transform();
2729 else
2730 generate_transform_manual();
2731
2732 r = MsiOpenDatabase(msifile, MSIDBOPEN_DIRECT, &hdb );
2733 ok( r == ERROR_SUCCESS , "Failed to create database\n" );
2734
2735 r = MsiDatabaseApplyTransform( hdb, mstfile, 0 );
2736 ok( r == ERROR_SUCCESS, "return code %d, should be ERROR_SUCCESS\n", r );
2737
2738 MsiDatabaseCommit( hdb );
2739
2740 /* check new values */
2741 hrec = 0;
2742 query = "select `BAR`,`CAR` from `AAR` where `BAR` = 1 AND `CAR` = 'vw'";
2743 r = do_query(hdb, query, &hrec);
2744 ok(r == ERROR_SUCCESS, "select query failed\n");
2745 MsiCloseHandle(hrec);
2746
2747 query = "select `BAR`,`CAR` from `AAR` where `BAR` = 2 AND `CAR` = 'bmw'";
2748 hrec = 0;
2749 r = do_query(hdb, query, &hrec);
2750 ok(r == ERROR_SUCCESS, "select query failed\n");
2751 MsiCloseHandle(hrec);
2752
2753 /* check updated values */
2754 hrec = 0;
2755 query = "select `NOO`,`OOO` from `MOO` where `NOO` = 1 AND `OOO` = 'c'";
2756 r = do_query(hdb, query, &hrec);
2757 ok(r == ERROR_SUCCESS, "select query failed\n");
2758 MsiCloseHandle(hrec);
2759
2760 /* check unchanged value */
2761 hrec = 0;
2762 query = "select `NOO`,`OOO` from `MOO` where `NOO` = 2 AND `OOO` = 'b'";
2763 r = do_query(hdb, query, &hrec);
2764 ok(r == ERROR_SUCCESS, "select query failed\n");
2765 MsiCloseHandle(hrec);
2766
2767 /* check deleted value */
2768 hrec = 0;
2769 query = "select * from `MOO` where `NOO` = 3";
2770 r = do_query(hdb, query, &hrec);
2771 ok(r == ERROR_NO_MORE_ITEMS, "select query failed\n");
2772 if (hrec) MsiCloseHandle(hrec);
2773
2774 /* check added stream */
2775 hrec = 0;
2776 query = "select `BLOB` from `BINARY` where `ID` = 1";
2777 r = do_query(hdb, query, &hrec);
2778 ok(r == ERROR_SUCCESS, "select query failed\n");
2779
2780 /* check the contents of the stream */
2781 sz = sizeof buffer;
2782 r = MsiRecordReadStream( hrec, 1, buffer, &sz );