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