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