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