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