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