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