ReactOS 0.4.16-dev-340-g0540c21
db.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2005 Mike McCormack for CodeWeavers
3 *
4 * A test program for MSI database files.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21#define COBJMACROS
22
23#include <stdio.h>
24
25#include <windows.h>
26#include <objidl.h>
27#include <msi.h>
28#include <msidefs.h>
29#include <msiquery.h>
30
31#include "wine/test.h"
32#include "utils.h"
33
34static const char *msifile = "winetest-db.msi";
35static const char *msifile2 = "winetst2-db.msi";
36static const char *mstfile = "winetst-db.mst";
37static const WCHAR msifileW[] = L"winetest-db.msi";
38static const WCHAR msifile2W[] = L"winetst2-db.msi";
39
40static void WINAPIV check_record_(int line, MSIHANDLE rec, UINT count, ...)
41{
43 UINT i;
44
45 ok_(__FILE__, line)(count == MsiRecordGetFieldCount(rec),
46 "expected %u fields, got %u\n", count, MsiRecordGetFieldCount(rec));
47
49
50 for (i = 1; i <= count; ++i)
51 {
52 const char *expect = va_arg(args, const char *);
53 char buffer[200] = "x";
54 DWORD sz = sizeof(buffer);
55 UINT r = MsiRecordGetStringA(rec, i, buffer, &sz);
56 ok_(__FILE__, line)(r == ERROR_SUCCESS, "field %u: got unexpected error %u\n", i, r);
57 ok_(__FILE__, line)(!strcmp(buffer, expect),
58 "field %u: expected \"%s\", got \"%s\"\n", i, expect, buffer);
59 }
60
61 va_end(args);
62}
63#define check_record(rec, ...) check_record_(__LINE__, rec, __VA_ARGS__)
64
65static void test_msidatabase(void)
66{
67 MSIHANDLE hdb = 0, hdb2 = 0;
69 DWORD len;
70 UINT res;
71
73
75 ok( res == ERROR_OPEN_FAILED, "expected failure\n");
76
77 res = MsiOpenDatabaseW( msifileW, (LPWSTR)0xff, &hdb );
78 ok( res == ERROR_INVALID_PARAMETER, "expected failure\n");
79
80 res = MsiCloseHandle( hdb );
81 ok( res == ERROR_SUCCESS , "Failed to close database\n" );
82
83 /* create an empty database */
85 ok( res == ERROR_SUCCESS , "Failed to create database\n" );
86
87 res = MsiDatabaseCommit( hdb );
88 ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
89
90 ok( GetFileAttributesA( msifile ) != INVALID_FILE_ATTRIBUTES, "database should exist\n");
91
92 res = MsiCloseHandle( hdb );
93 ok( res == ERROR_SUCCESS , "Failed to close database\n" );
95 ok( res == ERROR_SUCCESS , "Failed to open database\n" );
96
97 ok( GetFileAttributesA( msifile2 ) != INVALID_FILE_ATTRIBUTES, "database should exist\n");
98
99 res = MsiDatabaseCommit( hdb2 );
100 ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
101
102 res = MsiCloseHandle( hdb2 );
103 ok( res == ERROR_SUCCESS , "Failed to close database\n" );
104
106 ok( res == ERROR_SUCCESS , "Failed to open database\n" );
107
108 res = MsiCloseHandle( hdb2 );
109 ok( res == ERROR_SUCCESS , "Failed to close database\n" );
110
111 ok( GetFileAttributesA( msifile2 ) == INVALID_FILE_ATTRIBUTES, "uncommitted database should not exist\n");
112
114 ok( res == ERROR_SUCCESS , "Failed to close database\n" );
115
116 res = MsiDatabaseCommit( hdb2 );
117 ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
118
119 res = MsiCloseHandle( hdb2 );
120 ok( res == ERROR_SUCCESS , "Failed to close database\n" );
121
122 ok( GetFileAttributesA( msifile2 ) != INVALID_FILE_ATTRIBUTES, "committed database should exist\n");
123
125 ok( res == ERROR_SUCCESS , "Failed to open database\n" );
126
127 res = MsiDatabaseCommit( hdb );
128 ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
129
130 res = MsiCloseHandle( hdb );
131 ok( res == ERROR_SUCCESS , "Failed to close database\n" );
132
134 ok( res == ERROR_SUCCESS , "Failed to open database\n" );
135
136 res = MsiCloseHandle( hdb );
137 ok( res == ERROR_SUCCESS , "Failed to close database\n" );
138
140 ok( res == ERROR_SUCCESS , "Failed to open database\n" );
141
142 res = MsiCloseHandle( hdb );
143 ok( res == ERROR_SUCCESS , "Failed to close database\n" );
144 ok( GetFileAttributesA( msifile ) != INVALID_FILE_ATTRIBUTES, "database should exist\n");
145
146 /* MSIDBOPEN_CREATE deletes the database if MsiCommitDatabase isn't called */
148 ok( res == ERROR_SUCCESS , "Failed to open database\n" );
149
150 ok( GetFileAttributesA( msifile ) != INVALID_FILE_ATTRIBUTES, "database should exist\n");
151
152 res = MsiCloseHandle( hdb );
153 ok( res == ERROR_SUCCESS , "Failed to close database\n" );
154
155 ok( GetFileAttributesA( msifile ) == INVALID_FILE_ATTRIBUTES, "database should exist\n");
156
158 ok( res == ERROR_SUCCESS , "Failed to open database\n" );
159
160 res = MsiDatabaseCommit( hdb );
161 ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
162
163 ok( GetFileAttributesA( msifile ) != INVALID_FILE_ATTRIBUTES, "database should exist\n");
164
165 res = MsiCloseHandle( hdb );
166 ok( res == ERROR_SUCCESS , "Failed to close database\n" );
167
169 ok ( res, "Got zero res.\n" );
170 lstrcatW( path, L"\\");
172 len = lstrlenW(path);
173 path[len - 4] = 0;
174
176 ok( res != ERROR_SUCCESS , "Got unexpected res %u.\n", res );
177
179 path[lstrlenW(path) - 4] = 0;
180
182 ok( res != ERROR_SUCCESS , "Got unexpected res %u.\n", res );
183
185 ok( res == TRUE, "Failed to delete database\n" );
186
188 ok( res == TRUE, "Failed to delete database\n" );
189}
190
191static UINT do_query(MSIHANDLE hdb, const char *query, MSIHANDLE *phrec)
192{
193 MSIHANDLE hview = 0;
194 UINT r, ret;
195
196 if (phrec)
197 *phrec = 0;
198
199 /* open a select query */
200 r = MsiDatabaseOpenViewA(hdb, query, &hview);
201 if (r != ERROR_SUCCESS)
202 return r;
203 r = MsiViewExecute(hview, 0);
204 if (r != ERROR_SUCCESS)
205 return r;
206 ret = MsiViewFetch(hview, phrec);
207 r = MsiViewClose(hview);
208 if (r != ERROR_SUCCESS)
209 return r;
210 r = MsiCloseHandle(hview);
211 if (r != ERROR_SUCCESS)
212 return r;
213 return ret;
214}
215
216static UINT run_queryW( MSIHANDLE hdb, MSIHANDLE hrec, const WCHAR *query )
217{
218 MSIHANDLE hview = 0;
219 UINT r;
220
221 r = MsiDatabaseOpenViewW(hdb, query, &hview);
222 if( r != ERROR_SUCCESS )
223 return r;
224
225 r = MsiViewExecute(hview, hrec);
226 if( r == ERROR_SUCCESS )
227 r = MsiViewClose(hview);
228 MsiCloseHandle(hview);
229 return r;
230}
231
233{
234 UINT r = run_query( hdb, 0,
235 "CREATE TABLE `Component` ( "
236 "`Component` CHAR(72) NOT NULL, "
237 "`ComponentId` CHAR(38), "
238 "`Directory_` CHAR(72) NOT NULL, "
239 "`Attributes` SHORT NOT NULL, "
240 "`Condition` CHAR(255), "
241 "`KeyPath` CHAR(72) "
242 "PRIMARY KEY `Component`)" );
243 ok(r == ERROR_SUCCESS, "Failed to create Component table: %u\n", r);
244 return r;
245}
246
248{
249 UINT r = run_query( hdb, 0,
250 "CREATE TABLE `CustomAction` ( "
251 "`Action` CHAR(72) NOT NULL, "
252 "`Type` SHORT NOT NULL, "
253 "`Source` CHAR(72), "
254 "`Target` CHAR(255) "
255 "PRIMARY KEY `Action`)" );
256 ok(r == ERROR_SUCCESS, "Failed to create CustomAction table: %u\n", r);
257 return r;
258}
259
261{
262 UINT r = run_query( hdb, 0,
263 "CREATE TABLE `Directory` ( "
264 "`Directory` CHAR(255) NOT NULL, "
265 "`Directory_Parent` CHAR(255), "
266 "`DefaultDir` CHAR(255) NOT NULL "
267 "PRIMARY KEY `Directory`)" );
268 ok(r == ERROR_SUCCESS, "Failed to create Directory table: %u\n", r);
269 return r;
270}
271
273{
274 UINT r = run_query( hdb, 0,
275 "CREATE TABLE `FeatureComponents` ( "
276 "`Feature_` CHAR(38) NOT NULL, "
277 "`Component_` CHAR(72) NOT NULL "
278 "PRIMARY KEY `Feature_`, `Component_` )" );
279 ok(r == ERROR_SUCCESS, "Failed to create FeatureComponents table: %u\n", r);
280 return r;
281}
282
284{
285 UINT r = run_query( hdb, 0,
286 "CREATE TABLE `StdDlls` ( "
287 "`File` CHAR(255) NOT NULL, "
288 "`Binary_` CHAR(72) NOT NULL "
289 "PRIMARY KEY `File` )" );
290 ok(r == ERROR_SUCCESS, "Failed to create StdDlls table: %u\n", r);
291 return r;
292}
293
295{
296 UINT r = run_query( hdb, 0,
297 "CREATE TABLE `Binary` ( "
298 "`Name` CHAR(72) NOT NULL, "
299 "`Data` CHAR(72) NOT NULL "
300 "PRIMARY KEY `Name` )" );
301 ok(r == ERROR_SUCCESS, "Failed to create Binary table: %u\n", r);
302 return r;
303}
304
305static inline UINT add_entry(const char *file, int line, const char *type, MSIHANDLE hdb, const char *values, const char *insert)
306{
307 char *query;
308 UINT sz, r;
309
310 sz = strlen(values) + strlen(insert) + 1;
311 query = malloc(sz);
313 r = run_query(hdb, 0, query);
314 free(query);
315 ok_(file, line)(r == ERROR_SUCCESS, "failed to insert into %s table: %u\n", type, r);
316 return r;
317}
318
319#define add_component_entry(hdb, values) add_entry(__FILE__, __LINE__, "Component", hdb, values, \
320 "INSERT INTO `Component` " \
321 "(`Component`, `ComponentId`, `Directory_`, " \
322 "`Attributes`, `Condition`, `KeyPath`) VALUES( %s )")
323
324#define add_custom_action_entry(hdb, values) add_entry(__FILE__, __LINE__, "CustomAction", hdb, values, \
325 "INSERT INTO `CustomAction` " \
326 "(`Action`, `Type`, `Source`, `Target`) VALUES( %s )")
327
328#define add_feature_components_entry(hdb, values) add_entry(__FILE__, __LINE__, "FeatureComponents", hdb, values, \
329 "INSERT INTO `FeatureComponents` " \
330 "(`Feature_`, `Component_`) VALUES( %s )")
331
332#define add_std_dlls_entry(hdb, values) add_entry(__FILE__, __LINE__, "StdDlls", hdb, values, \
333 "INSERT INTO `StdDlls` (`File`, `Binary_`) VALUES( %s )")
334
335#define add_binary_entry(hdb, values) add_entry(__FILE__, __LINE__, "Binary", hdb, values, \
336 "INSERT INTO `Binary` (`Name`, `Data`) VALUES( %s )")
337
338static void test_msiinsert(void)
339{
340 MSIHANDLE hdb = 0, hview = 0, hview2 = 0, hrec = 0;
341 UINT r;
342 const char *query;
343 char buf[80];
344 DWORD sz;
345
347
348 /* just MsiOpenDatabase should not create a file */
350 ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
351
352 /* create a table */
353 query = "CREATE TABLE `phone` ( "
354 "`id` INT, `name` CHAR(32), `number` CHAR(32) "
355 "PRIMARY KEY `id`)";
356 r = MsiDatabaseOpenViewA(hdb, query, &hview);
357 ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
358 r = MsiViewExecute(hview, 0);
359 ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
360 r = MsiViewClose(hview);
361 ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
362 r = MsiCloseHandle(hview);
363 ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
364
365 query = "SELECT * FROM phone WHERE number = '8675309'";
366 r = MsiDatabaseOpenViewA(hdb, query, &hview2);
367 ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
368 r = MsiViewExecute(hview2, 0);
369 ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
370 r = MsiViewFetch(hview2, &hrec);
371 ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch produced items\n");
372
373 /* insert a value into it */
374 query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
375 "VALUES('1', 'Abe', '8675309')";
376 r = MsiDatabaseOpenViewA(hdb, query, &hview);
377 ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
378 r = MsiViewExecute(hview, 0);
379 ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
380 r = MsiViewClose(hview);
381 ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
382 r = MsiCloseHandle(hview);
383 ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
384
385 r = MsiViewFetch(hview2, &hrec);
386 ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch produced items\n");
387 r = MsiViewExecute(hview2, 0);
388 ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
389 r = MsiViewFetch(hview2, &hrec);
390 ok(r == ERROR_SUCCESS, "MsiViewFetch failed: %u\n", r);
391
392 r = MsiCloseHandle(hrec);
393 ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
394 r = MsiViewClose(hview2);
395 ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
396 r = MsiCloseHandle(hview2);
397 ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
398
399 query = "SELECT * FROM `phone` WHERE `id` = 1";
400 r = do_query(hdb, query, &hrec);
401 ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
402
403 /* check the record contains what we put in it */
405 ok(r == 3, "record count wrong\n");
406
407 r = MsiRecordIsNull(hrec, 0);
408 ok(r == FALSE, "field 0 not null\n");
409
410 r = MsiRecordGetInteger(hrec, 1);
411 ok(r == 1, "field 1 contents wrong\n");
412 sz = sizeof buf;
413 r = MsiRecordGetStringA(hrec, 2, buf, &sz);
414 ok(r == ERROR_SUCCESS, "field 2 content fetch failed\n");
415 ok(!strcmp(buf,"Abe"), "field 2 content incorrect\n");
416 sz = sizeof buf;
417 r = MsiRecordGetStringA(hrec, 3, buf, &sz);
418 ok(r == ERROR_SUCCESS, "field 3 content fetch failed\n");
419 ok(!strcmp(buf,"8675309"), "field 3 content incorrect\n");
420
421 r = MsiCloseHandle(hrec);
422 ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
423
424 /* open a select query */
425 hrec = 100;
426 query = "SELECT * FROM `phone` WHERE `id` >= 10";
427 r = do_query(hdb, query, &hrec);
428 ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch failed\n");
429 ok(hrec == 0, "hrec should be null\n");
430
431 r = MsiCloseHandle(hrec);
432 ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
433
434 query = "SELECT * FROM `phone` WHERE `id` < 0";
435 r = do_query(hdb, query, &hrec);
436 ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch failed\n");
437
438 query = "SELECT * FROM `phone` WHERE `id` <= 0";
439 r = do_query(hdb, query, &hrec);
440 ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch failed\n");
441
442 query = "SELECT * FROM `phone` WHERE `id` <> 1";
443 r = do_query(hdb, query, &hrec);
444 ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch failed\n");
445
446 query = "SELECT * FROM `phone` WHERE `id` > 10";
447 r = do_query(hdb, query, &hrec);
448 ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch failed\n");
449
450 /* now try a few bad INSERT xqueries */
451 query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
452 "VALUES(?, ?)";
453 r = MsiDatabaseOpenViewA(hdb, query, &hview);
454 ok(r == ERROR_BAD_QUERY_SYNTAX, "MsiDatabaseOpenView failed\n");
455
456 /* construct a record to insert */
457 hrec = MsiCreateRecord(4);
458 r = MsiRecordSetInteger(hrec, 1, 2);
459 ok(r == ERROR_SUCCESS, "MsiRecordSetInteger failed\n");
460 r = MsiRecordSetStringA(hrec, 2, "Adam");
461 ok(r == ERROR_SUCCESS, "MsiRecordSetString failed\n");
462 r = MsiRecordSetStringA(hrec, 3, "96905305");
463 ok(r == ERROR_SUCCESS, "MsiRecordSetString failed\n");
464
465 /* insert another value, using a record and wildcards */
466 query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
467 "VALUES(?, ?, ?)";
468 r = MsiDatabaseOpenViewA(hdb, query, &hview);
469 ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
470
471 if (r == ERROR_SUCCESS)
472 {
473 r = MsiViewExecute(hview, hrec);
474 ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
475 r = MsiViewClose(hview);
476 ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
477 r = MsiCloseHandle(hview);
478 ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
479 }
480 r = MsiCloseHandle(hrec);
481 ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
482
483 r = MsiViewFetch(0, NULL);
484 ok(r == ERROR_INVALID_PARAMETER, "MsiViewFetch failed\n");
485
486 r = MsiDatabaseCommit(hdb);
487 ok(r == ERROR_SUCCESS, "MsiDatabaseCommit failed\n");
488
489 r = MsiCloseHandle(hdb);
490 ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
491
493 ok(r == TRUE, "file didn't exist after commit\n");
494}
495
496static void test_msidecomposedesc(void)
497{
498 UINT (WINAPI *pMsiDecomposeDescriptorA)(LPCSTR, LPCSTR, LPSTR, LPSTR, DWORD *);
500 const char *desc;
501 UINT r;
502 DWORD len;
504
505 hmod = GetModuleHandleA("msi.dll");
506 pMsiDecomposeDescriptorA = (void*)GetProcAddress(hmod, "MsiDecomposeDescriptorA");
507 if (!pMsiDecomposeDescriptorA)
508 return;
509
510 /* test a valid feature descriptor */
511 desc = "']gAVn-}f(ZXfeAR6.jiFollowTheWhiteRabbit>3w2x^IGfe?CxI5heAvk.";
512 len = 0;
513 prod[0] = feature[0] = comp[0] = 0;
514 r = pMsiDecomposeDescriptorA(desc, prod, feature, comp, &len);
515 ok(r == ERROR_SUCCESS, "returned an error\n");
516 ok(len == strlen(desc), "length was wrong\n");
517 ok(strcmp(prod,"{90110409-6000-11D3-8CFE-0150048383C9}")==0, "product wrong\n");
518 ok(strcmp(feature,"FollowTheWhiteRabbit")==0, "feature wrong\n");
519 ok(strcmp(comp,"{A7CD68DB-EF74-49C8-FBB2-A7C463B2AC24}")==0,"component wrong\n");
520
521 /* test an invalid feature descriptor with too many characters */
522 desc = "']gAVn-}f(ZXfeAR6.ji"
523 "ThisWillFailIfTheresMoreThanAGuidsChars>"
524 "3w2x^IGfe?CxI5heAvk.";
525 len = 0;
526 r = pMsiDecomposeDescriptorA(desc, prod, feature, comp, &len);
527 ok(r == ERROR_INVALID_PARAMETER, "returned wrong error\n");
528
529 /* test a feature descriptor with < instead of > */
530 desc = "']gAVn-}f(ZXfeAR6.jiFollowTheWhiteRabbit<3w2x^IGfe?CxI5heAvk.";
531 len = 0;
532 prod[0] = feature[0] = 0;
533 comp[0] = 0x55;
534 r = pMsiDecomposeDescriptorA(desc, prod, feature, comp, &len);
535 ok(r == ERROR_SUCCESS, "returned an error\n");
536 ok(len == 41, "got %lu\n", len);
537 ok(!strcmp(prod,"{90110409-6000-11D3-8CFE-0150048383C9}"), "got '%s'\n", prod);
538 ok(!strcmp(feature,"FollowTheWhiteRabbit"), "got '%s'\n", feature);
539 ok(!comp[0], "got '%s'\n", comp);
540
541 len = 0;
542 prod[0] = feature[0] = 0;
543 comp[0] = 0x55;
544 r = pMsiDecomposeDescriptorA("yh1BVN)8A$!!!!!MKKSkAlwaysInstalledIntl_1033<", prod, feature, comp, &len);
545 ok(r == ERROR_SUCCESS, "got %u\n", r);
546 ok(len == 45, "got %lu\n", len);
547 ok(!strcmp(prod, "{90150000-006E-0409-0000-0000000FF1CE}"), "got '%s'\n", prod);
548 ok(!strcmp(feature, "AlwaysInstalledIntl_1033"), "got '%s'\n", feature);
549 ok(!comp[0], "got '%s'\n", comp);
550
551 /*
552 * Test a valid feature descriptor with the
553 * maximum number of characters and some trailing characters.
554 */
555 desc = "']gAVn-}f(ZXfeAR6.ji"
556 "ThisWillWorkIfTheresLTEThanAGuidsChars>"
557 "3w2x^IGfe?CxI5heAvk."
558 "extra";
559 len = 0;
560 r = pMsiDecomposeDescriptorA(desc, prod, feature, comp, &len);
561 ok(r == ERROR_SUCCESS, "returned wrong error\n");
562 ok(len == (strlen(desc) - strlen("extra")), "length wrong\n");
563
564 len = 0;
565 r = pMsiDecomposeDescriptorA(desc, prod, feature, NULL, &len);
566 ok(r == ERROR_SUCCESS, "returned wrong error\n");
567 ok(len == (strlen(desc) - strlen("extra")), "length wrong\n");
568
569 len = 0;
570 r = pMsiDecomposeDescriptorA(desc, prod, NULL, NULL, &len);
571 ok(r == ERROR_SUCCESS, "returned wrong error\n");
572 ok(len == (strlen(desc) - strlen("extra")), "length wrong\n");
573
574 len = 0;
575 r = pMsiDecomposeDescriptorA(desc, NULL, NULL, NULL, &len);
576 ok(r == ERROR_SUCCESS, "returned wrong error\n");
577 ok(len == (strlen(desc) - strlen("extra")), "length wrong\n");
578
579 len = 0;
580 r = pMsiDecomposeDescriptorA(NULL, NULL, NULL, NULL, &len);
581 ok(r == ERROR_INVALID_PARAMETER, "returned wrong error\n");
582 ok(len == 0, "length wrong\n");
583
584 r = pMsiDecomposeDescriptorA(desc, NULL, NULL, NULL, NULL);
585 ok(r == ERROR_SUCCESS, "returned wrong error\n");
586}
587
588static UINT try_query_param( MSIHANDLE hdb, LPCSTR szQuery, MSIHANDLE hrec )
589{
590 MSIHANDLE htab = 0;
591 UINT res;
592
593 res = MsiDatabaseOpenViewA( hdb, szQuery, &htab );
594 if(res == ERROR_SUCCESS )
595 {
596 UINT r;
597
598 r = MsiViewExecute( htab, hrec );
599 if(r != ERROR_SUCCESS )
600 res = r;
601
602 r = MsiViewClose( htab );
603 if(r != ERROR_SUCCESS )
604 res = r;
605
606 r = MsiCloseHandle( htab );
607 if(r != ERROR_SUCCESS )
608 res = r;
609 }
610 return res;
611}
612
613static UINT try_query( MSIHANDLE hdb, LPCSTR szQuery )
614{
615 return try_query_param( hdb, szQuery, 0 );
616}
617
618static UINT try_insert_query( MSIHANDLE hdb, LPCSTR szQuery )
619{
620 MSIHANDLE hrec = 0;
621 UINT r;
622
623 hrec = MsiCreateRecord( 1 );
624 MsiRecordSetStringA( hrec, 1, "Hello");
625
626 r = try_query_param( hdb, szQuery, hrec );
627
628 MsiCloseHandle( hrec );
629 return r;
630}
631
632static void test_msibadqueries(void)
633{
634 MSIHANDLE hdb = 0;
635 UINT r;
636
638
639 /* just MsiOpenDatabase should not create a file */
641 ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
642
643 r = MsiDatabaseCommit( hdb );
644 ok(r == ERROR_SUCCESS , "Failed to commit database\n");
645
646 r = MsiCloseHandle( hdb );
647 ok(r == ERROR_SUCCESS , "Failed to close database\n");
648
649 /* open it readonly */
651 ok(r == ERROR_SUCCESS , "Failed to open database r/o\n");
652
653 /* add a table to it */
654 r = try_query( hdb, "select * from _Tables");
655 ok(r == ERROR_SUCCESS , "query 1 failed\n");
656
657 r = MsiCloseHandle( hdb );
658 ok(r == ERROR_SUCCESS , "Failed to close database r/o\n");
659
660 /* open it read/write */
662 ok(r == ERROR_SUCCESS , "Failed to open database r/w\n");
663
664 /* a bunch of test queries that fail with the native MSI */
665
666 r = try_query( hdb, "CREATE TABLE");
667 ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2a return code\n");
668
669 r = try_query( hdb, "CREATE TABLE `a`");
670 ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2b return code\n");
671
672 r = try_query( hdb, "CREATE TABLE `a` ()");
673 ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2c return code\n");
674
675 r = try_query( hdb, "CREATE TABLE `a` (`b`)");
676 ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2d return code\n");
677
678 r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) )");
679 ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2e return code\n");
680
681 r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL)");
682 ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2f return code\n");
683
684 r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY)");
685 ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2g return code\n");
686
687 r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY)");
688 ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2h return code\n");
689
690 r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY)");
691 ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2i return code\n");
692
693 r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY 'b')");
694 ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2j return code\n");
695
696 r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY `b')");
697 ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2k return code\n");
698
699 r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY `b')");
700 ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2l return code\n");
701
702 r = try_query( hdb, "CREATE TABLE `a` (`b` CHA(72) NOT NULL PRIMARY KEY `b`)");
703 ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2m return code\n");
704
705 r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(-1) NOT NULL PRIMARY KEY `b`)");
706 ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2n return code\n");
707
708 r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(720) NOT NULL PRIMARY KEY `b`)");
709 ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2o return code\n");
710
711 r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL KEY `b`)");
712 ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2p return code\n");
713
714 r = try_query( hdb, "CREATE TABLE `a` (`` CHAR(72) NOT NULL PRIMARY KEY `b`)");
715 ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2p return code\n");
716
717 r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY `b`)");
718 ok(r == ERROR_SUCCESS , "valid query 2z failed\n");
719
720 r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY `b`)");
721 ok(r == ERROR_BAD_QUERY_SYNTAX , "created same table again\n");
722
723 r = try_query( hdb, "CREATE TABLE `aa` (`b` CHAR(72) NOT NULL, `c` "
724 "CHAR(72), `d` CHAR(255) NOT NULL LOCALIZABLE PRIMARY KEY `b`)");
725 ok(r == ERROR_SUCCESS , "query 4 failed\n");
726
727 r = MsiDatabaseCommit( hdb );
728 ok(r == ERROR_SUCCESS , "Failed to commit database after write\n");
729
730 r = try_query( hdb, "CREATE TABLE `blah` (`foo` CHAR(72) NOT NULL "
731 "PRIMARY KEY `foo`)");
732 ok(r == ERROR_SUCCESS , "query 4 failed\n");
733
734 r = try_insert_query( hdb, "insert into a ( `b` ) VALUES ( ? )");
735 ok(r == ERROR_SUCCESS , "failed to insert record in db\n");
736
737 r = MsiDatabaseCommit( hdb );
738 ok(r == ERROR_SUCCESS , "Failed to commit database after write\n");
739
740 r = try_query( hdb, "CREATE TABLE `boo` (`foo` CHAR(72) NOT NULL "
741 "PRIMARY KEY `ba`)");
742 ok(r != ERROR_SUCCESS , "query 5 succeeded\n");
743
744 r = try_query( hdb,"CREATE TABLE `bee` (`foo` CHAR(72) NOT NULL )");
745 ok(r != ERROR_SUCCESS , "query 6 succeeded\n");
746
747 r = try_query( hdb, "CREATE TABLE `temp` (`t` CHAR(72) NOT NULL "
748 "PRIMARY KEY `t`)");
749 ok(r == ERROR_SUCCESS , "query 7 failed\n");
750
751 r = try_query( hdb, "CREATE TABLE `c` (`b` CHAR NOT NULL PRIMARY KEY `b`)");
752 ok(r == ERROR_SUCCESS , "query 8 failed\n");
753
754 r = try_query( hdb, "select * from c");
755 ok(r == ERROR_SUCCESS , "query failed\n");
756
757 r = try_query( hdb, "select * from c where b = 'x");
758 ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
759
760 r = try_query( hdb, "select * from c where b = 'x'");
761 ok(r == ERROR_SUCCESS, "query failed\n");
762
763 r = try_query( hdb, "select * from 'c'");
764 ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
765
766 r = try_query( hdb, "select * from ''");
767 ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
768
769 r = try_query( hdb, "select * from c where b = x");
770 ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
771
772 r = try_query( hdb, "select * from c where b = \"x\"");
773 ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
774
775 r = try_query( hdb, "select * from c where b = 'x'");
776 ok(r == ERROR_SUCCESS, "query failed\n");
777
778 r = try_query( hdb, "select * from c where b = '\"x'");
779 ok(r == ERROR_SUCCESS, "query failed\n");
780
781 if (0) /* FIXME: this query causes trouble with other tests */
782 {
783 r = try_query( hdb, "select * from c where b = '\\\'x'");
784 ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
785 }
786
787 r = try_query( hdb, "select * from 'c'");
788 ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
789
790 r = try_query( hdb, "select `c`.`b` from `c` order by `c`.`order`");
791 ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %u\n", r );
792
793 r = try_query( hdb, "select `c`.b` from `c`");
794 ok( r == ERROR_SUCCESS, "query failed: %u\n", r );
795
796 r = try_query( hdb, "select `c`.`b from `c`");
797 ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %u\n", r );
798
799 r = try_query( hdb, "select `c`.b from `c`");
800 ok( r == ERROR_SUCCESS, "query failed: %u\n", r );
801
802 r = try_query( hdb, "select `c.`b` from `c`");
803 ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %u\n", r );
804
805 r = try_query( hdb, "select c`.`b` from `c`");
806 ok( r == ERROR_SUCCESS, "query failed: %u\n", r );
807
808 r = try_query( hdb, "select c.`b` from `c`");
809 ok( r == ERROR_SUCCESS, "query failed: %u\n", r );
810
811 r = try_query( hdb, "select `c`.`b` from c`");
812 ok( r == ERROR_SUCCESS, "query failed: %u\n", r );
813
814 r = try_query( hdb, "select `c`.`b` from `c");
815 ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %u\n", r );
816
817 r = try_query( hdb, "select `c`.`b` from c");
818 ok( r == ERROR_SUCCESS, "query failed: %u\n", r );
819
820 r = try_query( hdb, "CREATE TABLE `\5a` (`b` CHAR NOT NULL PRIMARY KEY `b`)" );
821 ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
822
823 r = try_query( hdb, "SELECT * FROM \5a" );
824 ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
825
826 r = try_query( hdb, "CREATE TABLE `a\5` (`b` CHAR NOT NULL PRIMARY KEY `b`)" );
827 ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
828
829 r = try_query( hdb, "SELECT * FROM a\5" );
830 ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
831
832 r = try_query( hdb, "CREATE TABLE `-a` (`b` CHAR NOT NULL PRIMARY KEY `b`)" );
833 ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
834
835 r = try_query( hdb, "SELECT * FROM -a" );
836 todo_wine ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
837
838 r = try_query( hdb, "CREATE TABLE `a-` (`b` CHAR NOT NULL PRIMARY KEY `b`)" );
839 ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
840
841 r = try_query( hdb, "SELECT * FROM a-" );
842 ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
843
844 r = MsiCloseHandle( hdb );
845 ok(r == ERROR_SUCCESS , "Failed to close database transact\n");
846
847 r = DeleteFileA( msifile );
848 ok(r == TRUE, "file didn't exist after commit\n");
849}
850
851static void test_viewmodify(void)
852{
853 MSIHANDLE hdb = 0, hview = 0, hrec = 0;
854 UINT r;
856 const char *query;
857 char buffer[0x100];
858 DWORD sz;
859
861
862 /* just MsiOpenDatabase should not create a file */
864 ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
865
866 query = "CREATE TABLE `phone` ( "
867 "`id` INT, `name` CHAR(32), `number` CHAR(32) "
868 "PRIMARY KEY `id`)";
869 r = run_query( hdb, 0, query );
870 ok(r == ERROR_SUCCESS, "query failed\n");
871
872 query = "CREATE TABLE `_Validation` ( "
873 "`Table` CHAR(32) NOT NULL, `Column` CHAR(32) NOT NULL, "
874 "`Nullable` CHAR(4) NOT NULL, `MinValue` INT, `MaxValue` INT, "
875 "`KeyTable` CHAR(255), `KeyColumn` SHORT, `Category` CHAR(32), "
876 "`Set` CHAR(255), `Description` CHAR(255) PRIMARY KEY `Table`, `Column`)";
877 r = run_query( hdb, 0, query );
878 ok(r == ERROR_SUCCESS, "query failed\n");
879
880 query = "INSERT INTO `_Validation` ( `Table`, `Column`, `Nullable` ) "
881 "VALUES('phone', 'id', 'N')";
882 r = run_query( hdb, 0, query );
883 ok(r == ERROR_SUCCESS, "query failed\n");
884
885 query = "SELECT * FROM `phone`";
886 r = MsiDatabaseOpenViewA(hdb, query, &hview);
887 ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
888
889 /* check what the error function reports without doing anything */
890 sz = sizeof(buffer);
891 strcpy(buffer, "x");
892 err = MsiViewGetErrorA( hview, buffer, &sz );
893 ok(err == MSIDBERROR_NOERROR, "got %d\n", err);
894 ok(!buffer[0], "got \"%s\"\n", buffer);
895 ok(sz == 0, "got size %lu\n", sz);
896
897 r = MsiViewExecute(hview, 0);
898 ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
899
900 /* try some invalid records */
901 r = MsiViewModify(hview, MSIMODIFY_INSERT, 0 );
902 ok(r == ERROR_INVALID_HANDLE, "MsiViewModify failed\n");
903 r = MsiViewModify(hview, -1, 0 );
904 ok(r == ERROR_INVALID_HANDLE, "MsiViewModify failed\n");
905
906 /* try an small record */
907 hrec = MsiCreateRecord(1);
908 r = MsiViewModify(hview, -1, hrec );
909 ok(r == ERROR_INVALID_DATA, "MsiViewModify failed\n");
910
911 sz = sizeof(buffer);
912 strcpy(buffer, "x");
913 err = MsiViewGetErrorA( hview, buffer, &sz );
914 ok(err == MSIDBERROR_NOERROR, "got %d\n", err);
915 ok(!buffer[0], "got \"%s\"\n", buffer);
916 ok(sz == 0, "got size %lu\n", sz);
917
918 r = MsiCloseHandle(hrec);
919 ok(r == ERROR_SUCCESS, "failed to close record\n");
920
921 /* insert a valid record */
922 hrec = MsiCreateRecord(3);
923
924 r = MsiRecordSetInteger(hrec, 1, 1);
925 ok(r == ERROR_SUCCESS, "failed to set integer\n");
926 r = MsiRecordSetStringA(hrec, 2, "bob");
927 ok(r == ERROR_SUCCESS, "failed to set string\n");
928 r = MsiRecordSetStringA(hrec, 3, "7654321");
929 ok(r == ERROR_SUCCESS, "failed to set string\n");
930
931 r = MsiViewExecute(hview, 0);
932 ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
934 ok(r == ERROR_SUCCESS, "MsiViewModify failed\n");
935
936 /* validate it */
937 r = MsiViewExecute(hview, 0);
938 ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
939
940 r = MsiViewModify(hview, MSIMODIFY_VALIDATE_NEW, hrec );
941 ok(r == ERROR_INVALID_DATA, "MsiViewModify failed %u\n", r);
942
943 sz = sizeof(buffer);
944 strcpy(buffer, "x");
945 err = MsiViewGetErrorA( hview, buffer, &sz );
946 ok(err == MSIDBERROR_DUPLICATEKEY, "got %d\n", err);
947 ok(!strcmp(buffer, "id"), "got \"%s\"\n", buffer);
948 ok(sz == 2, "got size %lu\n", sz);
949
950 /* insert the same thing again */
951 r = MsiViewExecute(hview, 0);
952 ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
953
954 /* should fail ... */
956 ok(r == ERROR_FUNCTION_FAILED, "MsiViewModify failed\n");
957
958 /* try to merge the same record */
959 r = MsiViewExecute(hview, 0);
960 ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
961 r = MsiViewModify(hview, MSIMODIFY_MERGE, hrec );
962 ok(r == ERROR_SUCCESS, "MsiViewModify failed\n");
963
964 r = MsiCloseHandle(hrec);
965 ok(r == ERROR_SUCCESS, "failed to close record\n");
966
967 /* try merging a new record */
968 hrec = MsiCreateRecord(3);
969
970 r = MsiRecordSetInteger(hrec, 1, 10);
971 ok(r == ERROR_SUCCESS, "failed to set integer\n");
972 r = MsiRecordSetStringA(hrec, 2, "pepe");
973 ok(r == ERROR_SUCCESS, "failed to set string\n");
974 r = MsiRecordSetStringA(hrec, 3, "7654321");
975 ok(r == ERROR_SUCCESS, "failed to set string\n");
976
977 r = MsiViewModify(hview, MSIMODIFY_MERGE, hrec );
978 ok(r == ERROR_SUCCESS, "MsiViewModify failed\n");
979 r = MsiViewExecute(hview, 0);
980 ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
981
982 r = MsiCloseHandle(hrec);
983 ok(r == ERROR_SUCCESS, "failed to close record\n");
984
985 r = MsiViewClose(hview);
986 ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
987 r = MsiCloseHandle(hview);
988 ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
989
990 query = "SELECT * FROM `phone`";
991 r = MsiDatabaseOpenViewA(hdb, query, &hview);
992 ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
993
994 r = MsiViewExecute(hview, 0);
995 ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
996
997 r = MsiViewFetch(hview, &hrec);
998 ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
999 check_record(hrec, 3, "1", "bob", "7654321");
1000
1001 /* update the view, non-primary key */
1002 r = MsiRecordSetStringA(hrec, 3, "3141592");
1003 ok(r == ERROR_SUCCESS, "MsiRecordSetString failed\n");
1004
1005 r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
1006 ok(r == ERROR_SUCCESS, "MsiViewModify failed\n");
1007
1008 /* do it again */
1009 r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
1010 ok(r == ERROR_SUCCESS, "MsiViewModify failed: %d\n", r);
1011
1012 /* update the view, primary key */
1013 r = MsiRecordSetInteger(hrec, 1, 5);
1014 ok(r == ERROR_SUCCESS, "MsiRecordSetInteger failed\n");
1015
1016 r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
1017 ok(r == ERROR_FUNCTION_FAILED, "MsiViewModify failed\n");
1018
1019 r = MsiCloseHandle(hrec);
1020 ok(r == ERROR_SUCCESS, "failed to close record\n");
1021
1022 r = MsiViewClose(hview);
1023 ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
1024 r = MsiCloseHandle(hview);
1025 ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
1026
1027 query = "SELECT * FROM `phone`";
1028 r = MsiDatabaseOpenViewA(hdb, query, &hview);
1029 ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
1030
1031 r = MsiViewExecute(hview, 0);
1032 ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
1033
1034 r = MsiViewFetch(hview, &hrec);
1035 ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
1036 check_record(hrec, 3, "1", "bob", "3141592");
1037 r = MsiCloseHandle(hrec);
1038 ok(r == ERROR_SUCCESS, "failed to close record\n");
1039
1040 /* use a record that doesn't come from a view fetch */
1041 hrec = MsiCreateRecord(3);
1042 ok(hrec != 0, "MsiCreateRecord failed\n");
1043
1044 r = MsiRecordSetInteger(hrec, 1, 3);
1045 ok(r == ERROR_SUCCESS, "failed to set integer\n");
1046 r = MsiRecordSetStringA(hrec, 2, "jane");
1047 ok(r == ERROR_SUCCESS, "failed to set string\n");
1048 r = MsiRecordSetStringA(hrec, 3, "112358");
1049 ok(r == ERROR_SUCCESS, "failed to set string\n");
1050
1051 r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
1052 ok(r == ERROR_FUNCTION_FAILED, "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
1053
1054 r = MsiCloseHandle(hrec);
1055 ok(r == ERROR_SUCCESS, "failed to close record\n");
1056
1057 /* use a record that doesn't come from a view fetch, primary key matches */
1058 hrec = MsiCreateRecord(3);
1059 ok(hrec != 0, "MsiCreateRecord failed\n");
1060
1061 r = MsiRecordSetInteger(hrec, 1, 1);
1062 ok(r == ERROR_SUCCESS, "failed to set integer\n");
1063 r = MsiRecordSetStringA(hrec, 2, "jane");
1064 ok(r == ERROR_SUCCESS, "failed to set string\n");
1065 r = MsiRecordSetStringA(hrec, 3, "112358");
1066 ok(r == ERROR_SUCCESS, "failed to set string\n");
1067
1068 r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
1069 ok(r == ERROR_FUNCTION_FAILED, "MsiViewModify failed\n");
1070
1071 r = MsiCloseHandle(hrec);
1072 ok(r == ERROR_SUCCESS, "failed to close record\n");
1073
1074 hrec = MsiCreateRecord(3);
1075
1076 r = MsiRecordSetInteger(hrec, 1, 2);
1077 ok(r == ERROR_SUCCESS, "failed to set integer\n");
1078 r = MsiRecordSetStringA(hrec, 2, "nick");
1079 ok(r == ERROR_SUCCESS, "failed to set string\n");
1080 r = MsiRecordSetStringA(hrec, 3, "141421");
1081 ok(r == ERROR_SUCCESS, "failed to set string\n");
1082
1083 r = MsiViewExecute(hview, 0);
1084 ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
1086 ok(r == ERROR_SUCCESS, "MsiViewModify failed\n");
1087
1088 r = MsiCloseHandle(hrec);
1089 ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
1090 r = MsiViewClose(hview);
1091 ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
1092 r = MsiCloseHandle(hview);
1093 ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
1094
1095 query = "SELECT * FROM `phone` WHERE `id` = 1";
1096 r = MsiDatabaseOpenViewA(hdb, query, &hview);
1097 ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
1098 r = MsiViewExecute(hview, 0);
1099 ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
1100 r = MsiViewFetch(hview, &hrec);
1101 ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
1102
1103 /* change the id to match the second row */
1104 r = MsiRecordSetInteger(hrec, 1, 2);
1105 ok(r == ERROR_SUCCESS, "failed to set integer\n");
1106 r = MsiRecordSetStringA(hrec, 2, "jerry");
1107 ok(r == ERROR_SUCCESS, "failed to set string\n");
1108
1109 r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
1110 ok(r == ERROR_FUNCTION_FAILED, "MsiViewModify failed\n");
1111
1112 r = MsiCloseHandle(hrec);
1113 ok(r == ERROR_SUCCESS, "failed to close record\n");
1114 r = MsiViewClose(hview);
1115 ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
1116 r = MsiCloseHandle(hview);
1117 ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
1118
1119 /* broader search */
1120 query = "SELECT * FROM `phone` ORDER BY `id`";
1121 r = MsiDatabaseOpenViewA(hdb, query, &hview);
1122 ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
1123 r = MsiViewExecute(hview, 0);
1124 ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
1125 r = MsiViewFetch(hview, &hrec);
1126 ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
1127
1128 /* change the id to match the second row */
1129 r = MsiRecordSetInteger(hrec, 1, 2);
1130 ok(r == ERROR_SUCCESS, "failed to set integer\n");
1131 r = MsiRecordSetStringA(hrec, 2, "jerry");
1132 ok(r == ERROR_SUCCESS, "failed to set string\n");
1133
1134 r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
1135 ok(r == ERROR_FUNCTION_FAILED, "MsiViewModify failed\n");
1136
1137 r = MsiCloseHandle(hrec);
1138 ok(r == ERROR_SUCCESS, "failed to close record\n");
1139 r = MsiViewClose(hview);
1140 ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
1141 r = MsiCloseHandle(hview);
1142 ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
1143
1144 r = MsiCloseHandle( hdb );
1145 ok(r == ERROR_SUCCESS, "MsiOpenDatabase close failed\n");
1146}
1147
1149{
1150 MSIHANDLE hdb = 0;
1151 UINT res;
1152
1154
1155 /* create an empty database */
1157 ok( res == ERROR_SUCCESS , "Failed to create database\n" );
1158 if( res != ERROR_SUCCESS )
1159 return hdb;
1160
1161 res = MsiDatabaseCommit( hdb );
1162 ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
1163
1164 return hdb;
1165}
1166
1167static void test_getcolinfo(void)
1168{
1169 MSIHANDLE hdb, hview = 0, rec = 0;
1170 UINT r;
1171
1172 /* create an empty db */
1173 hdb = create_db();
1174 ok( hdb, "failed to create db\n");
1175
1176 /* tables should be present */
1177 r = MsiDatabaseOpenViewA(hdb, "select Name from _Tables", &hview);
1178 ok( r == ERROR_SUCCESS, "failed to open query\n");
1179
1180 r = MsiViewExecute(hview, 0);
1181 ok( r == ERROR_SUCCESS, "failed to execute query\n");
1182
1183 /* check that NAMES works */
1184 rec = 0;
1185 r = MsiViewGetColumnInfo( hview, MSICOLINFO_NAMES, &rec );
1186 ok( r == ERROR_SUCCESS, "failed to get names\n");
1187 check_record(rec, 1, "Name");
1188 r = MsiCloseHandle( rec );
1189 ok( r == ERROR_SUCCESS, "failed to close record handle\n");
1190
1191 /* check that TYPES works */
1192 rec = 0;
1193 r = MsiViewGetColumnInfo( hview, MSICOLINFO_TYPES, &rec );
1194 ok( r == ERROR_SUCCESS, "failed to get names\n");
1195 check_record(rec, 1, "s64");
1196 r = MsiCloseHandle( rec );
1197 ok( r == ERROR_SUCCESS, "failed to close record handle\n");
1198
1199 /* check that invalid values fail */
1200 rec = 0;
1201 r = MsiViewGetColumnInfo( hview, 100, &rec );
1202 ok( r == ERROR_INVALID_PARAMETER, "wrong error code\n");
1203 ok( rec == 0, "returned a record\n");
1204
1206 ok( r == ERROR_INVALID_PARAMETER, "wrong error code\n");
1207
1209 ok( r == ERROR_INVALID_HANDLE, "wrong error code\n");
1210
1211 r = MsiViewClose(hview);
1212 ok( r == ERROR_SUCCESS, "failed to close view\n");
1213 r = MsiCloseHandle(hview);
1214 ok( r == ERROR_SUCCESS, "failed to close view handle\n");
1215 r = MsiCloseHandle(hdb);
1216 ok( r == ERROR_SUCCESS, "failed to close database\n");
1217}
1218
1220{
1221 MSIHANDLE hview = 0, rec = 0;
1222 UINT r;
1223
1224 r = MsiDatabaseOpenViewA(hdb, query, &hview);
1225 if( r != ERROR_SUCCESS )
1226 return r;
1227
1228 r = MsiViewExecute(hview, 0);
1229 if( r == ERROR_SUCCESS )
1230 {
1231 MsiViewGetColumnInfo( hview, type, &rec );
1232 }
1233 MsiViewClose(hview);
1234 MsiCloseHandle(hview);
1235 return rec;
1236}
1237
1239{
1240 MSIHANDLE hview = 0, rec = 0;
1241 UINT r, type = 0;
1242 char query[0x100];
1243
1244 sprintf(query, "select * from `_Columns` where `Table` = '%s'", table );
1245
1246 r = MsiDatabaseOpenViewA(hdb, query, &hview);
1247 if( r != ERROR_SUCCESS )
1248 return r;
1249
1250 r = MsiViewExecute(hview, 0);
1251 if( r == ERROR_SUCCESS )
1252 {
1253 while (1)
1254 {
1255 r = MsiViewFetch( hview, &rec );
1256 if( r != ERROR_SUCCESS)
1257 break;
1258 r = MsiRecordGetInteger( rec, 2 );
1259 if (r == field)
1260 type = MsiRecordGetInteger( rec, 4 );
1261 MsiCloseHandle( rec );
1262 }
1263 }
1264 MsiViewClose(hview);
1265 MsiCloseHandle(hview);
1266 return type;
1267}
1268
1269static void test_viewgetcolumninfo(void)
1270{
1271 MSIHANDLE hdb = 0, rec;
1272 UINT r;
1273
1274 hdb = create_db();
1275 ok( hdb, "failed to create db\n");
1276
1277 r = run_query( hdb, 0,
1278 "CREATE TABLE `Properties` "
1279 "( `Property` CHAR(255), "
1280 " `Value` CHAR(1), "
1281 " `Intvalue` INT, "
1282 " `Integervalue` INTEGER, "
1283 " `Shortvalue` SHORT, "
1284 " `Longvalue` LONG, "
1285 " `Longcharvalue` LONGCHAR, "
1286 " `Charvalue` CHAR, "
1287 " `Localizablevalue` CHAR LOCALIZABLE "
1288 " PRIMARY KEY `Property`)" );
1289 ok( r == ERROR_SUCCESS , "Failed to create table\n" );
1290
1291 /* check the column types */
1292 rec = get_column_info( hdb, "select * from `Properties`", MSICOLINFO_TYPES );
1293 ok( rec, "failed to get column info record\n" );
1294 check_record(rec, 9, "S255", "S1", "I2", "I2", "I2", "I4", "S0", "S0", "L0");
1295 MsiCloseHandle( rec );
1296
1297 /* check the type in _Columns */
1298 ok( 0x3dff == get_columns_table_type(hdb, "Properties", 1 ), "_columns table wrong\n");
1299 ok( 0x1d01 == get_columns_table_type(hdb, "Properties", 2 ), "_columns table wrong\n");
1300 ok( 0x1502 == get_columns_table_type(hdb, "Properties", 3 ), "_columns table wrong\n");
1301 ok( 0x1502 == get_columns_table_type(hdb, "Properties", 4 ), "_columns table wrong\n");
1302 ok( 0x1502 == get_columns_table_type(hdb, "Properties", 5 ), "_columns table wrong\n");
1303 ok( 0x1104 == get_columns_table_type(hdb, "Properties", 6 ), "_columns table wrong\n");
1304 ok( 0x1d00 == get_columns_table_type(hdb, "Properties", 7 ), "_columns table wrong\n");
1305 ok( 0x1d00 == get_columns_table_type(hdb, "Properties", 8 ), "_columns table wrong\n");
1306 ok( 0x1f00 == get_columns_table_type(hdb, "Properties", 9 ), "_columns table wrong\n");
1307
1308 /* now try the names */
1309 rec = get_column_info( hdb, "select * from `Properties`", MSICOLINFO_NAMES );
1310 ok( rec, "failed to get column info record\n" );
1311 check_record(rec, 9, "Property", "Value", "Intvalue", "Integervalue", "Shortvalue",
1312 "Longvalue", "Longcharvalue", "Charvalue", "Localizablevalue");
1313 MsiCloseHandle( rec );
1314
1315 r = run_query( hdb, 0,
1316 "CREATE TABLE `Binary` "
1317 "( `Name` CHAR(255), `Data` OBJECT PRIMARY KEY `Name`)" );
1318 ok( r == ERROR_SUCCESS , "Failed to create table\n" );
1319
1320 /* check the column types */
1321 rec = get_column_info( hdb, "select * from `Binary`", MSICOLINFO_TYPES );
1322 ok( rec, "failed to get column info record\n" );
1323 check_record(rec, 2, "S255", "V0");
1324 MsiCloseHandle( rec );
1325
1326 /* check the type in _Columns */
1327 ok( 0x3dff == get_columns_table_type(hdb, "Binary", 1 ), "_columns table wrong\n");
1328 ok( 0x1900 == get_columns_table_type(hdb, "Binary", 2 ), "_columns table wrong\n");
1329
1330 /* now try the names */
1331 rec = get_column_info( hdb, "select * from `Binary`", MSICOLINFO_NAMES );
1332 ok( rec, "failed to get column info record\n" );
1333 check_record(rec, 2, "Name", "Data");
1334 MsiCloseHandle( rec );
1335
1336 r = run_query( hdb, 0,
1337 "CREATE TABLE `UIText` "
1338 "( `Key` CHAR(72) NOT NULL, `Text` CHAR(255) LOCALIZABLE PRIMARY KEY `Key`)" );
1339 ok( r == ERROR_SUCCESS , "Failed to create table\n" );
1340
1341 ok( 0x2d48 == get_columns_table_type(hdb, "UIText", 1 ), "_columns table wrong\n");
1342 ok( 0x1fff == get_columns_table_type(hdb, "UIText", 2 ), "_columns table wrong\n");
1343
1344 rec = get_column_info( hdb, "select * from `UIText`", MSICOLINFO_NAMES );
1345 ok( rec, "failed to get column info record\n" );
1346 check_record(rec, 2, "Key", "Text");
1347 MsiCloseHandle( rec );
1348
1349 rec = get_column_info( hdb, "select * from `UIText`", MSICOLINFO_TYPES );
1350 ok( rec, "failed to get column info record\n" );
1351 check_record(rec, 2, "s72", "L255");
1352 MsiCloseHandle( rec );
1353
1354 MsiCloseHandle( hdb );
1355}
1356
1357static void test_msiexport(void)
1358{
1359 MSIHANDLE hdb = 0, hview = 0;
1360 UINT r;
1361 const char *query;
1362 char path[MAX_PATH];
1363 const char file[] = "phone.txt";
1364 HANDLE handle;
1365 char buffer[0x100];
1366 DWORD length;
1367 const char expected[] =
1368 "id\tname\tnumber\r\n"
1369 "I2\tS32\tS32\r\n"
1370 "phone\tid\r\n"
1371 "1\tAbe\t8675309\r\n";
1372
1374
1375 /* just MsiOpenDatabase should not create a file */
1377 ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
1378
1379 /* create a table */
1380 query = "CREATE TABLE `phone` ( "
1381 "`id` INT, `name` CHAR(32), `number` CHAR(32) "
1382 "PRIMARY KEY `id`)";
1383 r = MsiDatabaseOpenViewA(hdb, query, &hview);
1384 ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
1385 r = MsiViewExecute(hview, 0);
1386 ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
1387 r = MsiViewClose(hview);
1388 ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
1389 r = MsiCloseHandle(hview);
1390 ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
1391
1392 /* insert a value into it */
1393 query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
1394 "VALUES('1', 'Abe', '8675309')";
1395 r = MsiDatabaseOpenViewA(hdb, query, &hview);
1396 ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
1397 r = MsiViewExecute(hview, 0);
1398 ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
1399 r = MsiViewClose(hview);
1400 ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
1401 r = MsiCloseHandle(hview);
1402 ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
1403
1405
1406 r = MsiDatabaseExportA(hdb, "phone", path, file);
1407 ok(r == ERROR_SUCCESS, "MsiDatabaseExport failed\n");
1408
1409 MsiCloseHandle(hdb);
1410
1411 lstrcatA(path, "\\");
1412 lstrcatA(path, file);
1413
1414 /* check the data that was written */
1415 length = 0;
1416 memset(buffer, 0, sizeof buffer);
1419 {
1420 ReadFile(handle, buffer, sizeof buffer, &length, NULL);
1423 }
1424 else
1425 ok(0, "failed to open file %s\n", path);
1426
1427 ok( length == strlen(expected), "length of data wrong\n");
1428 ok( !lstrcmpA(buffer, expected), "data doesn't match\n");
1430}
1431
1432static void test_longstrings(void)
1433{
1434 const char insert_query[] =
1435 "INSERT INTO `strings` ( `id`, `val` ) VALUES('1', 'Z')";
1436 char *str;
1437 MSIHANDLE hdb = 0, hview = 0, hrec = 0;
1438 DWORD len;
1439 UINT r;
1440 const DWORD STRING_LENGTH = 0x10005;
1441
1443 /* just MsiOpenDatabase should not create a file */
1445 ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
1446
1447 /* create a table */
1448 r = try_query( hdb,
1449 "CREATE TABLE `strings` ( `id` INT, `val` CHAR(0) PRIMARY KEY `id`)");
1450 ok(r == ERROR_SUCCESS, "query failed\n");
1451
1452 /* try to insert a very long string */
1453 str = malloc(STRING_LENGTH + sizeof insert_query);
1454 len = strchr(insert_query, 'Z') - insert_query;
1455 strcpy(str, insert_query);
1456 memset(str+len, 'Z', STRING_LENGTH);
1457 strcpy(str+len+STRING_LENGTH, insert_query+len+1);
1458 r = try_query( hdb, str );
1459 ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
1460 free(str);
1461
1462 r = MsiDatabaseCommit(hdb);
1463 ok(r == ERROR_SUCCESS, "MsiDatabaseCommit failed\n");
1464 MsiCloseHandle(hdb);
1465
1467 ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
1468
1469 r = MsiDatabaseOpenViewA(hdb, "select * from `strings` where `id` = 1", &hview);
1470 ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
1471
1472 r = MsiViewExecute(hview, 0);
1473 ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
1474
1475 r = MsiViewFetch(hview, &hrec);
1476 ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
1477
1478 MsiViewClose(hview);
1479 MsiCloseHandle(hview);
1480
1481 r = MsiRecordGetStringA(hrec, 2, NULL, &len);
1482 ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
1483 ok(len == STRING_LENGTH, "string length wrong\n");
1484
1485 MsiCloseHandle(hrec);
1486 MsiCloseHandle(hdb);
1488}
1489
1490static void test_streamtable(void)
1491{
1492 MSIHANDLE hdb = 0, rec, view, hsi;
1493 char file[MAX_PATH];
1494 char buf[MAX_PATH];
1495 DWORD size;
1496 UINT r;
1497
1498 hdb = create_db();
1499 ok( hdb, "failed to create db\n");
1500
1501 r = run_query( hdb, 0,
1502 "CREATE TABLE `Properties` "
1503 "( `Property` CHAR(255), `Value` CHAR(1) PRIMARY KEY `Property`)" );
1504 ok( r == ERROR_SUCCESS , "Failed to create table\n" );
1505
1506 r = run_query( hdb, 0,
1507 "INSERT INTO `Properties` "
1508 "( `Value`, `Property` ) VALUES ( 'Prop', 'value' )" );
1509 ok( r == ERROR_SUCCESS, "Failed to add to table\n" );
1510
1511 r = MsiDatabaseCommit( hdb );
1512 ok( r == ERROR_SUCCESS , "Failed to commit database\n" );
1513
1514 MsiCloseHandle( hdb );
1515
1517 ok( r == ERROR_SUCCESS , "Failed to open database\n" );
1518
1519 /* check the column types */
1520 rec = get_column_info( hdb, "select * from `_Streams`", MSICOLINFO_TYPES );
1521 ok( rec, "failed to get column info record\n" );
1522 check_record(rec, 2, "s62", "V0");
1523 MsiCloseHandle( rec );
1524
1525 /* now try the names */
1526 rec = get_column_info( hdb, "select * from `_Streams`", MSICOLINFO_NAMES );
1527 ok( rec, "failed to get column info record\n" );
1528 check_record(rec, 2, "Name", "Data");
1529 MsiCloseHandle( rec );
1530
1531 r = MsiDatabaseOpenViewA( hdb,
1532 "SELECT * FROM `_Streams` WHERE `Name` = '\5SummaryInformation'", &view );
1533 ok( r == ERROR_SUCCESS, "Failed to open database view: %u\n", r );
1534
1535 r = MsiViewExecute( view, 0 );
1536 ok( r == ERROR_SUCCESS, "Failed to execute view: %u\n", r );
1537
1538 r = MsiViewFetch( view, &rec );
1539 ok( r == ERROR_NO_MORE_ITEMS, "Unexpected result: %u\n", r );
1540
1541 MsiCloseHandle( rec );
1542 MsiViewClose( view );
1544
1545 /* create a summary information stream */
1546 r = MsiGetSummaryInformationA( hdb, NULL, 1, &hsi );
1547 ok( r == ERROR_SUCCESS, "Failed to get summary information handle: %u\n", r );
1548
1550 ok( r == ERROR_SUCCESS, "Failed to set property: %u\n", r );
1551
1552 r = MsiSummaryInfoPersist( hsi );
1553 ok( r == ERROR_SUCCESS, "Failed to save summary information: %u\n", r );
1554
1555 MsiCloseHandle( hsi );
1556
1557 r = MsiDatabaseOpenViewA( hdb,
1558 "SELECT * FROM `_Streams` WHERE `Name` = '\5SummaryInformation'", &view );
1559 ok( r == ERROR_SUCCESS, "Failed to open database view: %u\n", r );
1560
1561 r = MsiViewExecute( view, 0 );
1562 ok( r == ERROR_SUCCESS, "Failed to execute view: %u\n", r );
1563
1564 r = MsiViewFetch( view, &rec );
1565 ok( r == ERROR_SUCCESS, "Unexpected result: %u\n", r );
1566
1567 MsiCloseHandle( rec );
1568 MsiViewClose( view );
1570
1571 /* insert a file into the _Streams table */
1572 create_file( "test.txt", 0 );
1573
1574 rec = MsiCreateRecord( 2 );
1575 MsiRecordSetStringA( rec, 1, "data" );
1576
1577 r = MsiRecordSetStreamA( rec, 2, "test.txt" );
1578 ok( r == ERROR_SUCCESS, "Failed to add stream data to the record: %d\n", r);
1579
1580 DeleteFileA("test.txt");
1581
1582 r = MsiDatabaseOpenViewA( hdb,
1583 "INSERT INTO `_Streams` ( `Name`, `Data` ) VALUES ( ?, ? )", &view );
1584 ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r);
1585
1586 r = MsiViewExecute( view, rec );
1587 ok( r == ERROR_SUCCESS, "Failed to execute view: %d\n", r);
1588
1589 MsiCloseHandle( rec );
1590 MsiViewClose( view );
1592
1593 /* insert another one */
1594 create_file( "test1.txt", 0 );
1595
1596 rec = MsiCreateRecord( 2 );
1597 MsiRecordSetStringA( rec, 1, "data1" );
1598
1599 r = MsiRecordSetStreamA( rec, 2, "test1.txt" );
1600 ok( r == ERROR_SUCCESS, "Failed to add stream data to the record: %d\n", r);
1601
1602 DeleteFileA("test1.txt");
1603
1604 r = MsiDatabaseOpenViewA( hdb,
1605 "INSERT INTO `_Streams` ( `Name`, `Data` ) VALUES ( ?, ? )", &view );
1606 ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r);
1607
1608 r = MsiViewExecute( view, rec );
1609 ok( r == ERROR_SUCCESS, "Failed to execute view: %d\n", r);
1610
1611 MsiCloseHandle( rec );
1612 MsiViewClose( view );
1614
1615 /* try again */
1616 create_file( "test1.txt", 0 );
1617
1618 rec = MsiCreateRecord( 2 );
1619 MsiRecordSetStringA( rec, 1, "data1" );
1620
1621 r = MsiRecordSetStreamA( rec, 2, "test1.txt" );
1622 ok( r == ERROR_SUCCESS, "Failed to add stream data to the record: %d\n", r );
1623
1624 DeleteFileA( "test1.txt" );
1625
1626 r = MsiDatabaseOpenViewA( hdb,
1627 "INSERT INTO `_Streams` ( `Name`, `Data` ) VALUES ( ?, ? )", &view );
1628 ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r );
1629
1630 r = MsiViewExecute( view, rec );
1631 ok( r == ERROR_FUNCTION_FAILED, "got %u\n", r );
1632
1633 MsiCloseHandle( rec );
1634 MsiViewClose( view );
1636
1637 r = MsiDatabaseOpenViewA( hdb,
1638 "SELECT `Name`, `Data` FROM `_Streams` WHERE `Name` = 'data'", &view );
1639 ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r);
1640
1641 r = MsiViewExecute( view, 0 );
1642 ok( r == ERROR_SUCCESS, "Failed to execute view: %d\n", r);
1643
1644 r = MsiViewFetch( view, &rec );
1645 ok( r == ERROR_SUCCESS, "Failed to fetch record: %d\n", r);
1646
1647 size = MAX_PATH;
1648 r = MsiRecordGetStringA( rec, 1, file, &size );
1649 ok( r == ERROR_SUCCESS, "Failed to get string: %d\n", r);
1650 ok( !lstrcmpA(file, "data"), "Expected 'data', got %s\n", file);
1651
1652 size = MAX_PATH;
1653 memset(buf, 0, MAX_PATH);
1654 r = MsiRecordReadStream( rec, 2, buf, &size );
1655 ok( r == ERROR_SUCCESS, "Failed to get stream: %d\n", r);
1656 ok( !lstrcmpA(buf, "test.txt"), "Expected 'test.txt', got %s\n", buf);
1657
1658 MsiCloseHandle( rec );
1659 MsiViewClose( view );
1661
1662 r = MsiDatabaseOpenViewA( hdb,
1663 "SELECT `Name`, `Data` FROM `_Streams` WHERE `Name` = 'data1'", &view );
1664 ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r);
1665
1666 r = MsiViewExecute( view, 0 );
1667 ok( r == ERROR_SUCCESS, "Failed to execute view: %d\n", r);
1668
1669 r = MsiViewFetch( view, &rec );
1670 ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1671
1672 size = MAX_PATH;
1673 r = MsiRecordGetStringA( rec, 1, file, &size );
1674 ok( r == ERROR_SUCCESS, "Failed to get string: %d\n", r);
1675 ok( !lstrcmpA(file, "data1"), "Expected 'data1', got %s\n", file);
1676
1677 size = MAX_PATH;
1678 memset(buf, 0, MAX_PATH);
1679 r = MsiRecordReadStream( rec, 2, buf, &size );
1680 ok( r == ERROR_SUCCESS, "Failed to get stream: %d\n", r);
1681 ok( !lstrcmpA(buf, "test1.txt"), "Expected 'test1.txt', got %s\n", buf);
1682
1683 MsiCloseHandle( rec );
1684 MsiViewClose( view );
1686
1687 /* perform an update */
1688 create_file( "test2.txt", 0 );
1689 rec = MsiCreateRecord( 1 );
1690
1691 r = MsiRecordSetStreamA( rec, 1, "test2.txt" );
1692 ok( r == ERROR_SUCCESS, "Failed to add stream data to the record: %d\n", r);
1693
1694 DeleteFileA("test2.txt");
1695
1696 r = MsiDatabaseOpenViewA( hdb,
1697 "UPDATE `_Streams` SET `Data` = ? WHERE `Name` = 'data1'", &view );
1698 ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r);
1699
1700 r = MsiViewExecute( view, rec );
1701 ok( r == ERROR_SUCCESS, "Failed to execute view: %d\n", r);
1702
1703 MsiCloseHandle( rec );
1704 MsiViewClose( view );
1706
1707 r = MsiDatabaseOpenViewA( hdb,
1708 "SELECT `Name`, `Data` FROM `_Streams` WHERE `Name` = 'data1'", &view );
1709 ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r);
1710
1711 r = MsiViewExecute( view, 0 );
1712 ok( r == ERROR_SUCCESS, "Failed to execute view: %d\n", r);
1713
1714 r = MsiViewFetch( view, &rec );
1715 ok( r == ERROR_SUCCESS, "Failed to fetch record: %d\n", r);
1716
1717 size = MAX_PATH;
1718 r = MsiRecordGetStringA( rec, 1, file, &size );
1719 ok( r == ERROR_SUCCESS, "Failed to get string: %d\n", r);
1720 ok( !lstrcmpA(file, "data1"), "Expected 'data1', got %s\n", file);
1721
1722 size = MAX_PATH;
1723 memset(buf, 0, MAX_PATH);
1724 r = MsiRecordReadStream( rec, 2, buf, &size );
1725 ok( r == ERROR_SUCCESS, "Failed to get stream: %d\n", r);
1726 ok( !lstrcmpA(buf, "test2.txt"), "Expected 'test2.txt', got %s\n", buf);
1727
1728 MsiCloseHandle( rec );
1729 MsiViewClose( view );
1731 MsiCloseHandle( hdb );
1733
1734 /* insert a file into the _Streams table */
1736 ok(r == ERROR_SUCCESS, "Failed to create database\n");
1737 ok( hdb, "failed to create db\n");
1738 create_file( "test.txt", 0 );
1739 rec = MsiCreateRecord( 2 );
1740 MsiRecordSetStringA( rec, 1, "data" );
1741 r = MsiRecordSetStreamA( rec, 2, "test.txt" );
1742 ok( r == ERROR_SUCCESS, "Failed to add stream data to the record: %d\n", r);
1743 DeleteFileA("test.txt");
1744 r = MsiDatabaseOpenViewA( hdb,
1745 "INSERT INTO `_Streams` ( `Name`, `Data` ) VALUES ( ?, ? )", &view );
1746 ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r);
1747 r = MsiViewExecute( view, rec );
1748 ok( r == ERROR_SUCCESS, "Failed to execute view: %d\n", r);
1749 MsiCloseHandle( rec );
1750 MsiViewClose( view );
1752 r = MsiDatabaseCommit( hdb );
1753 ok( r == ERROR_SUCCESS , "Failed to commit database\n" );
1754
1755 /* open a handle to the "data" stream */
1756 r = MsiDatabaseOpenViewA( hdb,
1757 "SELECT `Name`, `Data` FROM `_Streams` WHERE `Name` = 'data'", &view );
1758 ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r);
1759 r = MsiViewExecute( view, 0 );
1760 ok( r == ERROR_SUCCESS, "Failed to execute view: %d\n", r);
1761 r = MsiViewFetch( view, &rec );
1762 ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1763 MsiViewClose( view );
1765 /* read the stream while it still exists (normal case) */
1766 size = MAX_PATH;
1767 r = MsiRecordGetStringA( rec, 1, file, &size );
1768 ok( r == ERROR_SUCCESS, "Failed to get string: %d\n", r);
1769 ok( !lstrcmpA(file, "data"), "Expected 'data', got %s\n", file);
1770 size = MAX_PATH;
1771 memset(buf, 0, MAX_PATH);
1772 r = MsiRecordReadStream( rec, 2, buf, &size );
1773 ok( r == ERROR_SUCCESS, "Failed to get stream: %d\n", r);
1774 ok( !lstrcmpA(buf, "test.txt"), "Expected 'test.txt', got '%s' (%lu)\n", buf, size);
1775 MsiCloseHandle( rec );
1776
1777 /* open a handle to the "data" stream (and keep it open during removal) */
1778 r = MsiDatabaseOpenViewA( hdb,
1779 "SELECT `Name`, `Data` FROM `_Streams` WHERE `Name` = 'data'", &view );
1780 ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r);
1781 r = MsiViewExecute( view, 0 );
1782 ok( r == ERROR_SUCCESS, "Failed to execute view: %d\n", r);
1783 r = MsiViewFetch( view, &rec );
1784 ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1785 MsiViewClose( view );
1787
1788 /* remove the stream */
1789 r = MsiDatabaseOpenViewA( hdb,
1790 "DELETE FROM `_Streams` WHERE `Name` = 'data'", &view );
1791 ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r);
1792 r = MsiViewExecute( view, 0 );
1793 ok( r == ERROR_SUCCESS, "Failed to execute view: %d\n", r);
1794 MsiViewClose( view );
1796
1797 /* attempt to read the stream that no longer exists (abnormal case) */
1798 size = MAX_PATH;
1799 r = MsiRecordGetStringA( rec, 1, file, &size );
1800 ok( r == ERROR_SUCCESS, "Failed to get string: %d\n", r);
1801 ok( !lstrcmpA(file, "data"), "Expected 'data', got %s\n", file);
1802 size = MAX_PATH;
1803 memset(buf, 0, MAX_PATH);
1804 r = MsiRecordReadStream( rec, 2, buf, &size );
1805 ok( r == ERROR_SUCCESS, "Failed to get stream: %d\n", r);
1806 todo_wine ok( size == 0, "Expected empty buffer, got %lu bytes\n", size);
1807 MsiCloseHandle( rec );
1808
1809 MsiCloseHandle( hdb );
1811}
1812
1813static void test_binary(void)
1814{
1815 MSIHANDLE hdb = 0, rec;
1816 char file[MAX_PATH];
1817 char buf[MAX_PATH];
1818 DWORD size;
1819 LPCSTR query;
1820 UINT r;
1821
1822 /* insert a file into the Binary table */
1824 ok( r == ERROR_SUCCESS , "Failed to open database\n" );
1825
1826 query = "CREATE TABLE `Binary` ( `Name` CHAR(72) NOT NULL, `ID` INT NOT NULL, `Data` OBJECT PRIMARY KEY `Name`, `ID`)";
1827 r = run_query( hdb, 0, query );
1828 ok( r == ERROR_SUCCESS, "Cannot create Binary table: %d\n", r );
1829
1830 create_file( "test.txt", 0 );
1831 rec = MsiCreateRecord( 1 );
1832 r = MsiRecordSetStreamA( rec, 1, "test.txt" );
1833 ok( r == ERROR_SUCCESS, "Failed to add stream data to the record: %d\n", r);
1834 DeleteFileA( "test.txt" );
1835
1836 /* try a name that exceeds maximum OLE stream name length */
1837 query = "INSERT INTO `Binary` ( `Name`, `ID`, `Data` ) VALUES ( 'encryption.dll.CB4E6205_F99A_4C51_ADD4_184506EFAB87', 10000, ? )";
1838 r = run_query( hdb, rec, query );
1839 ok( r == ERROR_SUCCESS, "Insert into Binary table failed: %d\n", r );
1840
1841 r = MsiCloseHandle( rec );
1842 ok( r == ERROR_SUCCESS , "Failed to close record handle\n" );
1843
1844 r = MsiDatabaseCommit( hdb );
1845 ok( r == ERROR_FUNCTION_FAILED , "got %u\n", r );
1846
1847 r = MsiCloseHandle( hdb );
1848 ok( r == ERROR_SUCCESS , "Failed to close database\n" );
1849
1851 ok( r == ERROR_SUCCESS , "Failed to open database\n" );
1852
1853 query = "CREATE TABLE `Binary` ( `Name` CHAR(72) NOT NULL, `ID` INT NOT NULL, `Data` OBJECT PRIMARY KEY `Name`, `ID`)";
1854 r = run_query( hdb, 0, query );
1855 ok( r == ERROR_SUCCESS, "Cannot create Binary table: %d\n", r );
1856
1857 create_file( "test.txt", 0 );
1858 rec = MsiCreateRecord( 1 );
1859 r = MsiRecordSetStreamA( rec, 1, "test.txt" );
1860 ok( r == ERROR_SUCCESS, "Failed to add stream data to the record: %d\n", r );
1861 DeleteFileA( "test.txt" );
1862
1863 query = "INSERT INTO `Binary` ( `Name`, `ID`, `Data` ) VALUES ( 'filename1', 1, ? )";
1864 r = run_query( hdb, rec, query );
1865 ok( r == ERROR_SUCCESS, "Insert into Binary table failed: %d\n", r );
1866
1867 query = "INSERT INTO `Binary` ( `Name`, `ID`, `Data` ) VALUES ( 'filename1', 1, ? )";
1868 r = run_query( hdb, rec, query );
1869 ok( r == ERROR_FUNCTION_FAILED, "got %u\n", r );
1870
1871 r = MsiCloseHandle( rec );
1872 ok( r == ERROR_SUCCESS , "Failed to close record handle\n" );
1873
1874 r = MsiDatabaseCommit( hdb );
1875 ok( r == ERROR_SUCCESS , "Failed to commit database\n" );
1876
1877 r = MsiCloseHandle( hdb );
1878 ok( r == ERROR_SUCCESS , "Failed to close database\n" );
1879
1880 /* read file from the Stream table */
1882 ok( r == ERROR_SUCCESS , "Failed to open database\n" );
1883
1884 query = "SELECT * FROM `_Streams`";
1885 r = do_query( hdb, query, &rec );
1886 ok( r == ERROR_SUCCESS, "SELECT query failed: %d\n", r );
1887
1888 size = MAX_PATH;
1889 r = MsiRecordGetStringA( rec, 1, file, &size );
1890 ok( r == ERROR_SUCCESS, "Failed to get string: %d\n", r );
1891 ok( !lstrcmpA(file, "Binary.filename1.1"), "Expected 'Binary.filename1.1', got %s\n", file );
1892
1893 size = MAX_PATH;
1894 memset( buf, 0, MAX_PATH );
1895 r = MsiRecordReadStream( rec, 2, buf, &size );
1896 ok( r == ERROR_SUCCESS, "Failed to get stream: %d\n", r );
1897 ok( !lstrcmpA(buf, "test.txt"), "Expected 'test.txt', got %s\n", buf );
1898
1899 r = MsiCloseHandle( rec );
1900 ok( r == ERROR_SUCCESS , "Failed to close record handle\n" );
1901
1902 /* read file from the Binary table */
1903 query = "SELECT * FROM `Binary`";
1904 r = do_query( hdb, query, &rec );
1905 ok( r == ERROR_SUCCESS, "SELECT query failed: %d\n", r );
1906
1907 size = MAX_PATH;
1908 r = MsiRecordGetStringA( rec, 1, file, &size );
1909 ok( r == ERROR_SUCCESS, "Failed to get string: %d\n", r );
1910 ok( !lstrcmpA(file, "filename1"), "Expected 'filename1', got %s\n", file );
1911
1912 size = MAX_PATH;
1913 memset( buf, 0, MAX_PATH );
1914 r = MsiRecordReadStream( rec, 3, buf, &size );
1915 ok( r == ERROR_SUCCESS, "Failed to get stream: %d\n", r );
1916 ok( !lstrcmpA(buf, "test.txt"), "Expected 'test.txt', got %s\n", buf );
1917
1918 r = MsiCloseHandle( rec );
1919 ok( r == ERROR_SUCCESS , "Failed to close record handle\n" );
1920
1921 r = MsiCloseHandle( hdb );
1922 ok( r == ERROR_SUCCESS , "Failed to close database\n" );
1923
1925}
1926
1928{
1929 MSIHANDLE hdb = 0, rec, view;
1930 LPCSTR query;
1931 UINT r;
1932
1933 hdb = create_db();
1934 ok( hdb, "failed to create db\n");
1935
1936 r = run_query(hdb, 0,
1937 "CREATE TABLE `IESTable` ("
1938 "`Action` CHAR(64), "
1939 "`Condition` CHAR(64), "
1940 "`Sequence` LONG PRIMARY KEY `Sequence`)");
1941 ok( r == S_OK, "Cannot create IESTable table: %d\n", r);
1942
1943 r = run_query(hdb, 0,
1944 "CREATE TABLE `CATable` ("
1945 "`Action` CHAR(64), "
1946 "`Type` LONG PRIMARY KEY `Type`)");
1947 ok( r == S_OK, "Cannot create CATable table: %d\n", r);
1948
1949 r = run_query(hdb, 0, "INSERT INTO `IESTable` "
1950 "( `Action`, `Condition`, `Sequence`) "
1951 "VALUES ( 'clean', 'cond4', 4)");
1952 ok( r == S_OK, "cannot add entry to IESTable table:%d\n", r );
1953
1954 r = run_query(hdb, 0, "INSERT INTO `IESTable` "
1955 "( `Action`, `Condition`, `Sequence`) "
1956 "VALUES ( 'depends', 'cond1', 1)");
1957 ok( r == S_OK, "cannot add entry to IESTable table:%d\n", r );
1958
1959 r = run_query(hdb, 0, "INSERT INTO `IESTable` "
1960 "( `Action`, `Condition`, `Sequence`) "
1961 "VALUES ( 'build', 'cond2', 2)");
1962 ok( r == S_OK, "cannot add entry to IESTable table:%d\n", r );
1963
1964 r = run_query(hdb, 0, "INSERT INTO `IESTable` "
1965 "( `Action`, `Condition`, `Sequence`) "
1966 "VALUES ( 'build2', 'cond6', 6)");
1967 ok( r == S_OK, "cannot add entry to IESTable table:%d\n", r );
1968
1969 r = run_query(hdb, 0, "INSERT INTO `IESTable` "
1970 "( `Action`, `Condition`, `Sequence`) "
1971 "VALUES ( 'build', 'cond3', 3)");
1972 ok(r == S_OK, "cannot add entry to IESTable table:%d\n", r );
1973
1974 r = run_query(hdb, 0, "INSERT INTO `CATable` "
1975 "( `Action`, `Type` ) "
1976 "VALUES ( 'build', 32)");
1977 ok(r == S_OK, "cannot add entry to CATable table:%d\n", r );
1978
1979 r = run_query(hdb, 0, "INSERT INTO `CATable` "
1980 "( `Action`, `Type` ) "
1981 "VALUES ( 'depends', 64)");
1982 ok(r == S_OK, "cannot add entry to CATable table:%d\n", r );
1983
1984 r = run_query(hdb, 0, "INSERT INTO `CATable` "
1985 "( `Action`, `Type` ) "
1986 "VALUES ( 'clean', 63)");
1987 ok(r == S_OK, "cannot add entry to CATable table:%d\n", r );
1988
1989 r = run_query(hdb, 0, "INSERT INTO `CATable` "
1990 "( `Action`, `Type` ) "
1991 "VALUES ( 'build2', 34)");
1992 ok(r == S_OK, "cannot add entry to CATable table:%d\n", r );
1993 query = "Select IESTable.Condition from CATable, IESTable where "
1994 "CATable.Action = IESTable.Action and CATable.Type = 32";
1995 r = MsiDatabaseOpenViewA(hdb, query, &view);
1996 ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
1997
1998 r = MsiViewExecute(view, 0);
1999 ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
2000
2001 r = MsiViewFetch(view, &rec);
2002 ok( r == ERROR_SUCCESS, "failed to fetch view: %d\n", r );
2003 check_record(rec, 1, "cond2");
2004 MsiCloseHandle( rec );
2005
2006 r = MsiViewFetch(view, &rec);
2007 ok( r == ERROR_SUCCESS, "failed to fetch view: %d\n", r );
2008 check_record(rec, 1, "cond3");
2009 MsiCloseHandle( rec );
2010
2013
2014 MsiCloseHandle( hdb );
2016}
2017
2018
2019static void test_where(void)
2020{
2021 MSIHANDLE hdb = 0, rec, view;
2022 LPCSTR query;
2023 UINT r;
2024
2025 hdb = create_db();
2026 ok( hdb, "failed to create db\n");
2027
2028 r = run_query( hdb, 0,
2029 "CREATE TABLE `Media` ("
2030 "`DiskId` SHORT NOT NULL, "
2031 "`LastSequence` LONG, "
2032 "`DiskPrompt` CHAR(64) LOCALIZABLE, "
2033 "`Cabinet` CHAR(255), "
2034 "`VolumeLabel` CHAR(32), "
2035 "`Source` CHAR(72) "
2036 "PRIMARY KEY `DiskId`)" );
2037 ok( r == S_OK, "cannot create Media table: %d\n", r );
2038
2039 r = run_query( hdb, 0, "INSERT INTO `Media` "
2040 "( `DiskId`, `LastSequence`, `DiskPrompt`, `Cabinet`, `VolumeLabel`, `Source` ) "
2041 "VALUES ( 1, 0, '', 'zero.cab', '', '' )" );
2042 ok( r == S_OK, "cannot add file to the Media table: %d\n", r );
2043
2044 r = run_query( hdb, 0, "INSERT INTO `Media` "
2045 "( `DiskId`, `LastSequence`, `DiskPrompt`, `Cabinet`, `VolumeLabel`, `Source` ) "
2046 "VALUES ( 2, 1, '', 'one.cab', '', '' )" );
2047 ok( r == S_OK, "cannot add file to the Media table: %d\n", r );
2048
2049 r = run_query( hdb, 0, "INSERT INTO `Media` "
2050 "( `DiskId`, `LastSequence`, `DiskPrompt`, `Cabinet`, `VolumeLabel`, `Source` ) "
2051 "VALUES ( 3, 2, '', 'two.cab', '', '' )" );
2052 ok( r == S_OK, "cannot add file to the Media table: %d\n", r );
2053
2054 query = "SELECT * FROM `Media`";
2055 r = do_query(hdb, query, &rec);
2056 ok(r == ERROR_SUCCESS, "MsiViewFetch failed: %d\n", r);
2057 check_record(rec, 6, "1", "0", "", "zero.cab", "", "");
2058 MsiCloseHandle( rec );
2059
2060 query = "SELECT * FROM `Media` WHERE `LastSequence` >= 1";
2061 r = do_query(hdb, query, &rec);
2062 ok(r == ERROR_SUCCESS, "MsiViewFetch failed: %d\n", r);
2063 check_record(rec, 6, "2", "1", "", "one.cab", "", "");
2064 MsiCloseHandle( rec );
2065
2066 query = "SELECT `DiskId` FROM `Media` WHERE `LastSequence` >= 1 AND DiskId >= 0";
2067 r = MsiDatabaseOpenViewA(hdb, query, &view);
2068 ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
2069
2070 r = MsiViewExecute(view, 0);
2071 ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
2072
2073 r = MsiViewFetch(view, &rec);
2074 ok( r == ERROR_SUCCESS, "failed to fetch view: %d\n", r );
2075 check_record(rec, 1, "2");
2076 MsiCloseHandle( rec );
2077
2078 r = MsiViewFetch(view, &rec);
2079 ok( r == ERROR_SUCCESS, "failed to fetch view: %d\n", r );
2080 check_record(rec, 1, "3");
2081 MsiCloseHandle( rec );
2082
2083 r = MsiViewFetch(view, &rec);
2084 ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
2085
2088
2089 MsiCloseHandle( rec );
2090
2091 rec = 0;
2092 query = "SELECT * FROM `Media` WHERE `DiskPrompt` IS NULL";
2093 r = do_query(hdb, query, &rec);
2094 ok( r == ERROR_SUCCESS, "query failed: %d\n", r );
2095 MsiCloseHandle( rec );
2096
2097 rec = 0;
2098 query = "SELECT * FROM `Media` WHERE `DiskPrompt` < 'Cabinet'";
2099 r = do_query(hdb, query, &rec);
2100 ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %d\n", r );
2101 MsiCloseHandle( rec );
2102
2103 rec = 0;
2104 query = "SELECT * FROM `Media` WHERE `DiskPrompt` > 'Cabinet'";
2105 r = do_query(hdb, query, &rec);
2106 ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %d\n", r );
2107 MsiCloseHandle( rec );
2108
2109 rec = 0;
2110 query = "SELECT * FROM `Media` WHERE `DiskPrompt` <> 'Cabinet'";
2111 r = do_query(hdb, query, &rec);
2112 ok( r == ERROR_SUCCESS, "query failed: %d\n", r );
2113 MsiCloseHandle( rec );
2114
2115 rec = 0;
2116 query = "SELECT * FROM `Media` WHERE `DiskPrompt` = 'Cabinet'";
2117 r = do_query(hdb, query, &rec);
2118 ok( r == ERROR_NO_MORE_ITEMS, "query failed: %d\n", r );
2119 MsiCloseHandle( rec );
2120
2121 rec = MsiCreateRecord(1);
2122 MsiRecordSetStringA(rec, 1, "");
2123
2124 query = "SELECT * FROM `Media` WHERE `DiskPrompt` = ?";
2125 r = MsiDatabaseOpenViewA(hdb, query, &view);
2126 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2127 r = MsiViewExecute(view, rec);
2128 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2129
2130 MsiCloseHandle(rec);
2131
2132 r = MsiViewFetch(view, &rec);
2133 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2134
2135 MsiCloseHandle(rec);
2138
2139 MsiCloseHandle( hdb );
2141}
2142
2143static const CHAR test_data[] = "FirstPrimaryColumn\tSecondPrimaryColumn\tShortInt\tShortIntNullable\tLongInt\tLongIntNullable\tString\tLocalizableString\tLocalizableStringNullable\n"
2144 "s255\ti2\ti2\tI2\ti4\tI4\tS255\tS0\ts0\n"
2145 "TestTable\tFirstPrimaryColumn\n"
2146 "stringage\t5\t2\t\t2147483640\t-2147483640\tanother string\tlocalizable\tduh\n";
2147
2148static const CHAR two_primary[] = "PrimaryOne\tPrimaryTwo\n"
2149 "s255\ts255\n"
2150 "TwoPrimary\tPrimaryOne\tPrimaryTwo\n"
2151 "papaya\tleaf\n"
2152 "papaya\tflower\n";
2153
2154static const CHAR endlines1[] = "A\tB\tC\tD\tE\tF\r\n"
2155 "s72\ts72\ts72\ts72\ts72\ts72\n"
2156 "Table\tA\r\n"
2157 "a\tb\tc\td\te\tf\n"
2158 "g\th\ti\t\rj\tk\tl\r\n";
2159
2160static const CHAR endlines2[] = "A\tB\tC\tD\tE\tF\r"
2161 "s72\ts72\ts72\ts72\ts72\ts72\n"
2162 "Table2\tA\r\n"
2163 "a\tb\tc\td\te\tf\n"
2164 "g\th\ti\tj\tk\tl\r\n";
2165
2166static const CHAR suminfo[] = "PropertyId\tValue\n"
2167 "i2\tl255\n"
2168 "_SummaryInformation\tPropertyId\n"
2169 "1\t1252\n"
2170 "2\tInstaller Database\n"
2171 "3\tInstaller description\n"
2172 "4\tWineHQ\n"
2173 "5\tInstaller\n"
2174 "6\tInstaller comments\n"
2175 "7\tIntel;1033,2057\n"
2176 "9\t{12345678-1234-1234-1234-123456789012}\n"
2177 "12\t2009/04/12 15:46:11\n"
2178 "13\t2009/04/12 15:46:11\n"
2179 "14\t200\n"
2180 "15\t2\n"
2181 "18\tVim\n"
2182 "19\t2\n";
2183
2184static void write_file(const CHAR *filename, const char *data, int data_size)
2185{
2186 DWORD size;
2187
2190 WriteFile(hf, data, data_size, &size, NULL);
2191 CloseHandle(hf);
2192}
2193
2195{
2196 UINT r;
2197
2198 write_file("temp_file", table_data, (lstrlenA(table_data) - 1) * sizeof(char));
2199 r = MsiDatabaseImportA(hdb, CURR_DIR, "temp_file");
2200 DeleteFileA("temp_file");
2201
2202 return r;
2203}
2204
2205static void test_suminfo_import(void)
2206{
2207 MSIHANDLE hdb, hsi, view = 0;
2208 LPCSTR query;
2209 UINT r, count, type;
2210 DWORD size;
2211 char str_value[50];
2212 INT int_value;
2213 FILETIME ft_value;
2214
2216
2218 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2219
2220 r = add_table_to_db(hdb, suminfo);
2221 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2222
2223 /* _SummaryInformation is not imported as a regular table... */
2224
2225 query = "SELECT * FROM `_SummaryInformation`";
2226 r = MsiDatabaseOpenViewA(hdb, query, &view);
2227 ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %u\n", r);
2229
2230 /* ...its data is added to the special summary information stream */
2231
2232 r = MsiGetSummaryInformationA(hdb, NULL, 0, &hsi);
2233 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2234
2236 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2237 ok(count == 14, "Expected 14, got %u\n", count);
2238
2239 r = MsiSummaryInfoGetPropertyA(hsi, PID_CODEPAGE, &type, &int_value, NULL, NULL, NULL);
2240 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2241 ok(type == VT_I2, "Expected VT_I2, got %u\n", type);
2242 ok(int_value == 1252, "Expected 1252, got %d\n", int_value);
2243
2244 size = sizeof(str_value);
2245 r = MsiSummaryInfoGetPropertyA(hsi, PID_TITLE, &type, NULL, NULL, str_value, &size);
2246 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2247 ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
2248 ok(size == 18, "Expected 18, got %lu\n", size);
2249 ok(!strcmp(str_value, "Installer Database"),
2250 "Expected \"Installer Database\", got %s\n", str_value);
2251
2252 size = sizeof(str_value);
2253 r = MsiSummaryInfoGetPropertyA(hsi, PID_SUBJECT, &type, NULL, NULL, str_value, &size);
2254 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2255 ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
2256 ok(!strcmp(str_value, "Installer description"),
2257 "Expected \"Installer description\", got %s\n", str_value);
2258
2259 size = sizeof(str_value);
2260 r = MsiSummaryInfoGetPropertyA(hsi, PID_AUTHOR, &type, NULL, NULL, str_value, &size);
2261 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2262 ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
2263 ok(!strcmp(str_value, "WineHQ"),
2264 "Expected \"WineHQ\", got %s\n", str_value);
2265
2266 size = sizeof(str_value);
2267 r = MsiSummaryInfoGetPropertyA(hsi, PID_KEYWORDS, &type, NULL, NULL, str_value, &size);
2268 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2269 ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
2270 ok(!strcmp(str_value, "Installer"),
2271 "Expected \"Installer\", got %s\n", str_value);
2272
2273 size = sizeof(str_value);
2274 r = MsiSummaryInfoGetPropertyA(hsi, PID_COMMENTS, &type, NULL, NULL, str_value, &size);
2275 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2276 ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
2277 ok(!strcmp(str_value, "Installer comments"),
2278 "Expected \"Installer comments\", got %s\n", str_value);
2279
2280 size = sizeof(str_value);
2281 r = MsiSummaryInfoGetPropertyA(hsi, PID_TEMPLATE, &type, NULL, NULL, str_value, &size);
2282 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2283 ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
2284 ok(!strcmp(str_value, "Intel;1033,2057"),
2285 "Expected \"Intel;1033,2057\", got %s\n", str_value);
2286
2287 size = sizeof(str_value);
2288 r = MsiSummaryInfoGetPropertyA(hsi, PID_REVNUMBER, &type, NULL, NULL, str_value, &size);
2289 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2290 ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
2291 ok(!strcmp(str_value, "{12345678-1234-1234-1234-123456789012}"),
2292 "Expected \"{12345678-1234-1234-1234-123456789012}\", got %s\n", str_value);
2293
2295 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2296 ok(type == VT_FILETIME, "Expected VT_FILETIME, got %u\n", type);
2297
2299 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2300 ok(type == VT_FILETIME, "Expected VT_FILETIME, got %u\n", type);
2301
2302 r = MsiSummaryInfoGetPropertyA(hsi, PID_PAGECOUNT, &type, &int_value, NULL, NULL, NULL);
2303 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2304 ok(type == VT_I4, "Expected VT_I4, got %u\n", type);
2305 ok(int_value == 200, "Expected 200, got %d\n", int_value);
2306
2307 r = MsiSummaryInfoGetPropertyA(hsi, PID_WORDCOUNT, &type, &int_value, NULL, NULL, NULL);
2308 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2309 ok(type == VT_I4, "Expected VT_I4, got %u\n", type);
2310 ok(int_value == 2, "Expected 2, got %d\n", int_value);
2311
2312 r = MsiSummaryInfoGetPropertyA(hsi, PID_SECURITY, &type, &int_value, NULL, NULL, NULL);
2313 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2314 ok(type == VT_I4, "Expected VT_I4, got %u\n", type);
2315 ok(int_value == 2, "Expected 2, got %d\n", int_value);
2316
2317 size = sizeof(str_value);
2318 r = MsiSummaryInfoGetPropertyA(hsi, PID_APPNAME, &type, NULL, NULL, str_value, &size);
2319 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2320 ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
2321 ok(!strcmp(str_value, "Vim"), "Expected \"Vim\", got %s\n", str_value);
2322
2323 MsiCloseHandle(hsi);
2324 MsiCloseHandle(hdb);
2326}
2327
2328static void test_msiimport(void)
2329{
2330 MSIHANDLE hdb, view, rec;
2331 LPCSTR query;
2332 UINT r;
2333
2335
2337 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2338
2340 ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
2341
2342 r = MsiDatabaseImportA(hdb, CURR_DIR, "nonexistent");
2343 ok(r == ERROR_FUNCTION_FAILED, "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
2344
2345 r = add_table_to_db(hdb, test_data);
2346 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2347
2349 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2350
2351 r = add_table_to_db(hdb, endlines1);
2352 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2353
2354 r = add_table_to_db(hdb, endlines2);
2355 ok(r == ERROR_FUNCTION_FAILED, "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
2356
2357 query = "SELECT * FROM `TestTable`";
2358 r = MsiDatabaseOpenViewA(hdb, query, &view);
2359 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2360
2362 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2363 check_record(rec, 9, "FirstPrimaryColumn", "SecondPrimaryColumn", "ShortInt",
2364 "ShortIntNullable", "LongInt", "LongIntNullable", "String",
2365 "LocalizableString", "LocalizableStringNullable");
2366 MsiCloseHandle(rec);
2367
2369 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2370 check_record(rec, 9, "s255", "i2", "i2", "I2", "i4", "I4", "S255", "S0", "s0");
2371 MsiCloseHandle(rec);
2372
2373 query = "SELECT * FROM `TestTable`";
2374 r = do_query(hdb, query, &rec);
2375 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2376 check_record(rec, 9, "stringage", "5", "2", "", "2147483640", "-2147483640",
2377 "another string", "localizable", "duh");
2378 MsiCloseHandle(rec);
2379
2382
2383 query = "SELECT * FROM `TwoPrimary`";
2384 r = MsiDatabaseOpenViewA(hdb, query, &view);
2385 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2386
2388 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2389 check_record(rec, 2, "PrimaryOne", "PrimaryTwo");
2390 MsiCloseHandle(rec);
2391
2393 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2394 check_record(rec, 2, "s255", "s255");
2395 MsiCloseHandle(rec);
2396
2397 r = MsiViewExecute(view, 0);
2398 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2399
2400 r = MsiViewFetch(view, &rec);
2401 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2402 check_record(rec, 2, "papaya", "leaf");
2403 MsiCloseHandle(rec);
2404
2405 r = MsiViewFetch(view, &rec);
2406 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2407 check_record(rec, 2, "papaya", "flower");
2408 MsiCloseHandle(rec);
2409
2410 r = MsiViewFetch(view, &rec);
2412 "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
2413
2414 r = MsiViewClose(view);
2415 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2416
2418
2419 query = "SELECT * FROM `Table`";
2420 r = MsiDatabaseOpenViewA(hdb, query, &view);
2421 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2422
2424 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2425 check_record(rec, 6, "A", "B", "C", "D", "E", "F");
2426 MsiCloseHandle(rec);
2427
2429 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2430 check_record(rec, 6, "s72", "s72", "s72", "s72", "s72", "s72");
2431 MsiCloseHandle(rec);
2432
2435
2436 query = "SELECT * FROM `Table`";
2437 r = MsiDatabaseOpenViewA(hdb, query, &view);
2438 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2439
2440 r = MsiViewExecute(view, 0);
2441 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2442
2443 r = MsiViewFetch(view, &rec);
2444 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2445 check_record(rec, 6, "a", "b", "c", "d", "e", "f");
2446 MsiCloseHandle(rec);
2447
2448 r = MsiViewFetch(view, &rec);
2449 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2450 check_record(rec, 6, "g", "h", "i", "j", "k", "l");
2451 MsiCloseHandle(rec);
2452
2453 r = MsiViewFetch(view, &rec);
2455 "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
2456
2459 MsiCloseHandle(hdb);
2461}
2462
2463static const CHAR bin_import_dat[] = "Name\tData\r\n"
2464 "s72\tV0\r\n"
2465 "Binary\tName\r\n"
2466 "filename1\tfilename1.ibd\r\n";
2467
2468static void test_binary_import(void)
2469{
2470 MSIHANDLE hdb = 0, rec;
2471 char file[MAX_PATH];
2472 char buf[MAX_PATH];
2473 char path[MAX_PATH];
2474 DWORD size;
2475 LPCSTR query;
2476 UINT r;
2477
2478 /* create files to import */
2479 write_file("bin_import.idt", bin_import_dat,
2480 (sizeof(bin_import_dat) - 1) * sizeof(char));
2481 CreateDirectoryA("bin_import", NULL);
2482 create_file_data("bin_import/filename1.ibd", "just some words", 15);
2483
2484 /* import files into database */
2486 ok( r == ERROR_SUCCESS , "Failed to open database\n");
2487
2489 r = MsiDatabaseImportA(hdb, path, "bin_import.idt");
2490 ok(r == ERROR_SUCCESS , "Failed to import Binary table\n");
2491
2492 /* read file from the Binary table */
2493 query = "SELECT * FROM `Binary`";
2494 r = do_query(hdb, query, &rec);
2495 ok(r == ERROR_SUCCESS, "SELECT query failed: %d\n", r);
2496
2497 size = MAX_PATH;
2498 r = MsiRecordGetStringA(rec, 1, file, &size);
2499 ok(r == ERROR_SUCCESS, "Failed to get string: %d\n", r);
2500 ok(!lstrcmpA(file, "filename1"), "Expected 'filename1', got %s\n", file);
2501
2502 size = MAX_PATH;
2503 memset(buf, 0, MAX_PATH);
2504 r = MsiRecordReadStream(rec, 2, buf, &size);
2505 ok(r == ERROR_SUCCESS, "Failed to get stream: %d\n", r);
2506 ok(!lstrcmpA(buf, "just some words"), "Expected 'just some words', got %s\n", buf);
2507
2508 r = MsiCloseHandle(rec);
2509 ok(r == ERROR_SUCCESS , "Failed to close record handle\n");
2510
2511 r = MsiCloseHandle(hdb);
2512 ok(r == ERROR_SUCCESS , "Failed to close database\n");
2513
2514 DeleteFileA("bin_import/filename1.ibd");
2515 RemoveDirectoryA("bin_import");
2516 DeleteFileA("bin_import.idt");
2517}
2518
2519static void test_markers(void)
2520{
2521 MSIHANDLE hdb, rec;
2522 LPCSTR query;
2523 UINT r;
2524
2525 hdb = create_db();
2526 ok( hdb, "failed to create db\n");
2527
2528 rec = MsiCreateRecord(3);
2529 MsiRecordSetStringA(rec, 1, "Table");
2530 MsiRecordSetStringA(rec, 2, "Apples");
2531 MsiRecordSetStringA(rec, 3, "Oranges");
2532
2533 /* try a legit create */
2534 query = "CREATE TABLE `Table` ( `One` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`)";
2535 r = run_query(hdb, 0, query);
2536 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2537 MsiCloseHandle(rec);
2538
2539 /* try table name as marker */
2540 rec = MsiCreateRecord(1);
2541 MsiRecordSetStringA(rec, 1, "Fable");
2542 query = "CREATE TABLE `?` ( `One` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`)";
2543 r = run_query(hdb, rec, query);
2544 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2545
2546 /* verify that we just created a table called '?', not 'Fable' */
2547 r = try_query(hdb, "SELECT * from `Fable`");
2548 ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2549
2550 r = try_query(hdb, "SELECT * from `?`");
2551 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2552
2553 /* try table name as marker without backticks */
2554 MsiRecordSetStringA(rec, 1, "Mable");
2555 query = "CREATE TABLE ? ( `One` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`)";
2556 r = run_query(hdb, rec, query);
2557 ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2558
2559 /* try one column name as marker */
2560 MsiRecordSetStringA(rec, 1, "One");
2561 query = "CREATE TABLE `Mable` ( `?` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`)";
2562 r = run_query(hdb, rec, query);
2563 ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2564 MsiCloseHandle(rec);
2565
2566 /* try column names as markers */
2567 rec = MsiCreateRecord(2);
2568 MsiRecordSetStringA(rec, 1, "One");
2569 MsiRecordSetStringA(rec, 2, "Two");
2570 query = "CREATE TABLE `Mable` ( `?` SHORT NOT NULL, `?` CHAR(255) PRIMARY KEY `One`)";
2571 r = run_query(hdb, rec, query);
2572 ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2573 MsiCloseHandle(rec);
2574
2575 /* try names with backticks */
2576 rec = MsiCreateRecord(3);
2577 MsiRecordSetStringA(rec, 1, "One");
2578 MsiRecordSetStringA(rec, 2, "Two");
2579 MsiRecordSetStringA(rec, 3, "One");
2580 query = "CREATE TABLE `Mable` ( `?` SHORT NOT NULL, `?` CHAR(255) PRIMARY KEY `?`)";
2581 r = run_query(hdb, rec, query);
2582 ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2583
2584 /* try names with backticks, minus definitions */
2585 query = "CREATE TABLE `Mable` ( `?`, `?` PRIMARY KEY `?`)";
2586 r = run_query(hdb, rec, query);
2587 ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2588
2589 /* try names without backticks */
2590 query = "CREATE TABLE `Mable` ( ? SHORT NOT NULL, ? CHAR(255) PRIMARY KEY ?)";
2591 r = run_query(hdb, rec, query);
2592 ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2593 MsiCloseHandle(rec);
2594
2595 /* try one long marker */
2596 rec = MsiCreateRecord(1);
2597 MsiRecordSetStringA(rec, 1, "`One` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`");
2598 query = "CREATE TABLE `Mable` ( ? )";
2599 r = run_query(hdb, rec, query);
2600 ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2601 MsiCloseHandle(rec);
2602
2603 /* try all names as markers */
2604 rec = MsiCreateRecord(4);
2605 MsiRecordSetStringA(rec, 1, "Mable");
2606 MsiRecordSetStringA(rec, 2, "One");
2607 MsiRecordSetStringA(rec, 3, "Two");
2608 MsiRecordSetStringA(rec, 4, "One");
2609 query = "CREATE TABLE `?` ( `?` SHORT NOT NULL, `?` CHAR(255) PRIMARY KEY `?`)";
2610 r = run_query(hdb, rec, query);
2611 ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2612 MsiCloseHandle(rec);
2613
2614 /* try a legit insert */
2615 query = "INSERT INTO `Table` ( `One`, `Two` ) VALUES ( 5, 'hello' )";
2616 r = run_query(hdb, 0, query);
2617 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2618
2619 r = try_query(hdb, "SELECT * from `Table`");
2620 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2621
2622 /* try values as markers */
2623 rec = MsiCreateRecord(2);
2624 MsiRecordSetInteger(rec, 1, 4);
2625 MsiRecordSetStringA(rec, 2, "hi");
2626 query = "INSERT INTO `Table` ( `One`, `Two` ) VALUES ( ?, '?' )";
2627 r = run_query(hdb, rec, query);
2628 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2629 MsiCloseHandle(rec);
2630
2631 /* try column names and values as markers */
2632 rec = MsiCreateRecord(4);
2633 MsiRecordSetStringA(rec, 1, "One");
2634 MsiRecordSetStringA(rec, 2, "Two");
2635 MsiRecordSetInteger(rec, 3, 5);
2636 MsiRecordSetStringA(rec, 4, "hi");
2637 query = "INSERT INTO `Table` ( `?`, `?` ) VALUES ( ?, '?' )";
2638 r = run_query(hdb, rec, query);
2639 ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2640 MsiCloseHandle(rec);
2641
2642 /* try column names as markers */
2643 rec = MsiCreateRecord(2);
2644 MsiRecordSetStringA(rec, 1, "One");
2645 MsiRecordSetStringA(rec, 2, "Two");
2646 query = "INSERT INTO `Table` ( `?`, `?` ) VALUES ( 3, 'yellow' )";
2647 r = run_query(hdb, rec, query);
2648 ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2649 MsiCloseHandle(rec);
2650
2651 /* try table name as a marker */
2652 rec = MsiCreateRecord(1);
2653 MsiRecordSetStringA(rec, 1, "Table");
2654 query = "INSERT INTO `?` ( `One`, `Two` ) VALUES ( 2, 'green' )";
2655 r = run_query(hdb, rec, query);
2656 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2657 MsiCloseHandle(rec);
2658
2659 /* try table name and values as markers */
2660 rec = MsiCreateRecord(3);
2661 MsiRecordSetStringA(rec, 1, "Table");
2662 MsiRecordSetInteger(rec, 2, 10);
2663 MsiRecordSetStringA(rec, 3, "haha");
2664 query = "INSERT INTO `?` ( `One`, `Two` ) VALUES ( ?, '?' )";
2665 r = run_query(hdb, rec, query);
2666 ok(r == ERROR_FUNCTION_FAILED, "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
2667 MsiCloseHandle(rec);
2668
2669 /* try all markers */
2670 rec = MsiCreateRecord(5);
2671 MsiRecordSetStringA(rec, 1, "Table");
2672 MsiRecordSetStringA(rec, 1, "One");
2673 MsiRecordSetStringA(rec, 1, "Two");
2674 MsiRecordSetInteger(rec, 2, 10);
2675 MsiRecordSetStringA(rec, 3, "haha");
2676 query = "INSERT INTO `?` ( `?`, `?` ) VALUES ( ?, '?' )";
2677 r = run_query(hdb, rec, query);
2678 ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2679 MsiCloseHandle(rec);
2680
2681 /* insert an integer as a string */
2682 rec = MsiCreateRecord(2);
2683 MsiRecordSetStringA(rec, 1, "11");
2684 MsiRecordSetStringA(rec, 2, "hi");
2685 query = "INSERT INTO `Table` ( `One`, `Two` ) VALUES ( ?, '?' )";
2686 r = run_query(hdb, rec, query);
2687 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2688 MsiCloseHandle(rec);
2689
2690 /* leave off the '' for the string */
2691 rec = MsiCreateRecord(2);
2692 MsiRecordSetInteger(rec, 1, 12);
2693 MsiRecordSetStringA(rec, 2, "hi");
2694 query = "INSERT INTO `Table` ( `One`, `Two` ) VALUES ( ?, ? )";
2695 r = run_query(hdb, rec, query);
2696 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2697 MsiCloseHandle(rec);
2698
2699 MsiCloseHandle(hdb);
2701}
2702
2703#define MY_NVIEWS 4000 /* Largest installer I've seen uses < 2000 */
2704static void test_handle_limit(void)
2705{
2706 int i;
2707 MSIHANDLE hdb;
2708 MSIHANDLE hviews[MY_NVIEWS];
2709 UINT r;
2710
2711 /* create an empty db */
2712 hdb = create_db();
2713 ok( hdb, "failed to create db\n");
2714
2715 memset(hviews, 0, sizeof(hviews));
2716
2717 for (i=0; i<MY_NVIEWS; i++) {
2718 static char szQueryBuf[256] = "SELECT * from `_Tables`";
2719 hviews[i] = 0xdeadbeeb;
2720 r = MsiDatabaseOpenViewA(hdb, szQueryBuf, &hviews[i]);
2721 if( r != ERROR_SUCCESS || hviews[i] == 0xdeadbeeb ||
2722 hviews[i] == 0 || (i && (hviews[i] == hviews[i-1])))
2723 break;
2724 }
2725
2726 ok( i == MY_NVIEWS, "problem opening views\n");
2727
2728 for (i=0; i<MY_NVIEWS; i++) {
2729 if (hviews[i] != 0 && hviews[i] != 0xdeadbeeb) {
2730 MsiViewClose(hviews[i]);
2731 r = MsiCloseHandle(hviews[i]);
2732 if (r != ERROR_SUCCESS)
2733 break;
2734 }
2735 }
2736
2737 ok( i == MY_NVIEWS, "problem closing views\n");
2738
2739 r = MsiCloseHandle(hdb);
2740 ok( r == ERROR_SUCCESS, "failed to close database\n");
2741}
2742
2743static void generate_transform(void)
2744{
2745 MSIHANDLE hdb1, hdb2, hrec;
2746 LPCSTR query;
2747 UINT r;
2748
2749 /* start with two identical databases */
2751
2753 ok( r == ERROR_SUCCESS , "Failed to create database\n" );
2754
2755 r = MsiDatabaseCommit( hdb1 );
2756 ok( r == ERROR_SUCCESS , "Failed to commit database\n" );
2757
2759 ok( r == ERROR_SUCCESS , "Failed to create database\n" );
2760
2761 /* the transform between two identical database should be empty */
2762 r = MsiDatabaseGenerateTransformA(hdb1, hdb2, NULL, 0, 0);
2763 todo_wine {
2764 ok( r == ERROR_NO_DATA, "return code %d, should be ERROR_NO_DATA\n", r );
2765 }
2766
2767 query = "CREATE TABLE `AAR` ( `BAR` SHORT NOT NULL, `CAR` CHAR(255) PRIMARY KEY `CAR`)";
2768 r = run_query(hdb1, 0, query);
2769 ok(r == ERROR_SUCCESS, "failed to add table\n");
2770
2771 query = "INSERT INTO `AAR` ( `BAR`, `CAR` ) VALUES ( 1, 'vw' )";
2772 r = run_query(hdb1, 0, query);
2773 ok(r == ERROR_SUCCESS, "failed to add row 1\n");
2774
2775 query = "INSERT INTO `AAR` ( `BAR`, `CAR` ) VALUES ( 2, 'bmw' )";
2776 r = run_query(hdb1, 0, query);
2777 ok(r == ERROR_SUCCESS, "failed to add row 2\n");
2778
2779 query = "UPDATE `MOO` SET `OOO` = 'c' WHERE `NOO` = 1";
2780 r = run_query(hdb1, 0, query);
2781 ok(r == ERROR_SUCCESS, "failed to modify row\n");
2782
2783 query = "DELETE FROM `MOO` WHERE `NOO` = 3";
2784 r = run_query(hdb1, 0, query);
2785 ok(r == ERROR_SUCCESS, "failed to delete row\n");
2786
2787 hrec = MsiCreateRecord(2);
2788 r = MsiRecordSetInteger(hrec, 1, 1);
2789 ok(r == ERROR_SUCCESS, "failed to set integer\n");
2790
2791 write_file("testdata.bin", "naengmyon", 9);
2792 r = MsiRecordSetStreamA(hrec, 2, "testdata.bin");
2793 ok(r == ERROR_SUCCESS, "failed to set stream\n");
2794
2795 query = "INSERT INTO `BINARY` ( `ID`, `BLOB` ) VALUES ( ?, ? )";
2796 r = run_query(hdb1, hrec, query);
2797 ok(r == ERROR_SUCCESS, "failed to add row with blob\n");
2798
2799 MsiCloseHandle(hrec);
2800
2801 query = "ALTER TABLE `MOO` ADD `COW` INTEGER";
2802 r = run_query(hdb1, 0, query);
2803 ok(r == ERROR_SUCCESS, "failed to add column\n");
2804
2805 query = "ALTER TABLE `MOO` ADD `PIG` INTEGER";
2806 r = run_query(hdb1, 0, query);
2807 ok(r == ERROR_SUCCESS, "failed to add column\n");
2808
2809 query = "UPDATE `MOO` SET `PIG` = 5 WHERE `NOO` = 1";
2810 r = run_query(hdb1, 0, query);
2811 ok(r == ERROR_SUCCESS, "failed to modify row\n");
2812
2813 query = "CREATE TABLE `Property` ( `Property` CHAR(72) NOT NULL, "
2814 "`Value` CHAR(0) PRIMARY KEY `Property`)";
2815 r = run_query(hdb1, 0, query);
2816 ok(r == ERROR_SUCCESS, "failed to add property table\n");
2817
2818 query = "INSERT INTO `Property` ( `Property`, `Value` ) VALUES ( 'prop', 'val' )";
2819 r = run_query(hdb1, 0, query);
2820 ok(r == ERROR_SUCCESS, "failed to add property\n");
2821
2822 /* database needs to be committed */
2823 MsiDatabaseCommit(hdb1);
2824
2825 r = MsiDatabaseGenerateTransformA(hdb1, hdb2, mstfile, 0, 0);
2826 ok( r == ERROR_SUCCESS, "return code %d, should be ERROR_SUCCESS\n", r );
2827
2828 MsiCloseHandle( hdb1 );
2829 MsiCloseHandle( hdb2 );
2830
2831 DeleteFileA("testdata.bin");
2832}
2833
2834/* data for generating a transform */
2835
2836/* tables transform names - encoded as they would be in an msi database file */
2837static const WCHAR name1[] = { 0x4840, 0x3a8a, 0x481b, 0 }; /* AAR */
2838static const WCHAR name2[] = { 0x4840, 0x3b3f, 0x43f2, 0x4438, 0x45b1, 0 }; /* _Columns */
2839static const WCHAR name3[] = { 0x4840, 0x3f7f, 0x4164, 0x422f, 0x4836, 0 }; /* _Tables */
2840static const WCHAR name4[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0 }; /* _StringData */
2841static const WCHAR name5[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0 }; /* _StringPool */
2842static const WCHAR name6[] = { 0x4840, 0x3e16, 0x4818, 0}; /* MOO */
2843static const WCHAR name7[] = { 0x4840, 0x3c8b, 0x3a97, 0x409b, 0 }; /* BINARY */
2844static const WCHAR name8[] = { 0x3c8b, 0x3a97, 0x409b, 0x387e, 0 }; /* BINARY.1 */
2845static const WCHAR name9[] = { 0x4840, 0x4559, 0x44f2, 0x4568, 0x4737, 0 }; /* Property */
2846
2847/* data in each table */
2848static const WCHAR data1[] = { /* AAR */
2849 0x0201, 0x0008, 0x8001, /* 0x0201 = add row (1), two shorts */
2850 0x0201, 0x0009, 0x8002,
2851};
2852static const WCHAR data2[] = { /* _Columns */
2853 0x0401, 0x0001, 0x8003, 0x0002, 0x9502,
2854 0x0401, 0x0001, 0x8004, 0x0003, 0x9502,
2855 0x0401, 0x0005, 0x0000, 0x0006, 0xbdff, /* 0x0401 = add row (1), 4 shorts */
2856 0x0401, 0x0005, 0x0000, 0x0007, 0x8502,
2857 0x0401, 0x000a, 0x0000, 0x000a, 0xad48,
2858 0x0401, 0x000a, 0x0000, 0x000b, 0x9d00,
2859};
2860static const WCHAR data3[] = { /* _Tables */
2861 0x0101, 0x0005, /* 0x0101 = add row (1), 1 short */
2862 0x0101, 0x000a,
2863};
2864static const char data4[] = /* _StringData */
2865 "MOOCOWPIGcAARCARBARvwbmwPropertyValuepropval"; /* all the strings squashed together */
2866static const WCHAR data5[] = { /* _StringPool */
2867/* len, refs */
2868 0, 0, /* string 0 '' */
2869 3, 2, /* string 1 'MOO' */
2870 3, 1, /* string 2 'COW' */
2871 3, 1, /* string 3 'PIG' */
2872 1, 1, /* string 4 'c' */
2873 3, 3, /* string 5 'AAR' */
2874 3, 1, /* string 6 'CAR' */
2875 3, 1, /* string 7 'BAR' */
2876 2, 1, /* string 8 'vw' */
2877 3, 1, /* string 9 'bmw' */
2878 8, 4, /* string 10 'Property' */
2879 5, 1, /* string 11 'Value' */
2880 4, 1, /* string 12 'prop' */
2881 3, 1, /* string 13 'val' */
2882};
2883/* update row, 0x0002 is a bitmask of present column data, keys are excluded */
2884static const WCHAR data6[] = { /* MOO */
2885 0x000a, 0x8001, 0x0004, 0x8005, /* update row */
2886 0x0000, 0x8003, /* delete row */
2887};
2888
2889static const WCHAR data7[] = { /* BINARY */
2890 0x0201, 0x8001, 0x0001,
2891};
2892
2893static const char data8[] = /* stream data for the BINARY table */
2894 "naengmyon";
2895
2896static const WCHAR data9[] = { /* Property */
2897 0x0201, 0x000c, 0x000d,
2898};
2899
2900static const struct {
2902 const void *data;
2905{
2906 { name1, data1, sizeof data1 },
2907 { name2, data2, sizeof data2 },
2908 { name3, data3, sizeof data3 },
2909 { name4, data4, sizeof data4 - 1 },
2910 { name5, data5, sizeof data5 },
2911 { name6, data6, sizeof data6 },
2912 { name7, data7, sizeof data7 },
2913 { name8, data8, sizeof data8 - 1 },
2914 { name9, data9, sizeof data9 },
2916
2918{
2919 IStorage *stg = NULL;
2920 IStream *stm;
2921 WCHAR name[0x20];
2922 HRESULT r;
2923 DWORD i, count;
2925
2926 const CLSID CLSID_MsiTransform = { 0xc1082,0,0,{0xc0,0,0,0,0,0,0,0x46}};
2927
2928 MultiByteToWideChar(CP_ACP, 0, mstfile, -1, name, 0x20);
2929
2930 r = StgCreateDocfile(name, mode, 0, &stg);
2931 ok(r == S_OK, "failed to create storage\n");
2932 if (!stg)
2933 return;
2934
2935 r = IStorage_SetClass( stg, &CLSID_MsiTransform );
2936 ok(r == S_OK, "failed to set storage type\n");
2937
2938 for (i=0; i<ARRAY_SIZE(table_transform_data); i++)
2939 {
2940 r = IStorage_CreateStream( stg, table_transform_data[i].name,
2941 STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stm );
2942 if (FAILED(r))
2943 {
2944 ok(0, "failed to create stream %#lx\n", r);
2945 continue;
2946 }
2947
2948 r = IStream_Write( stm, table_transform_data[i].data,
2951 ok(0, "failed to write stream\n");
2952 IStream_Release(stm);
2953 }
2954
2955 IStorage_Release(stg);
2956}
2957
2959{
2960 UINT res;
2962
2963 /* build summary info */
2965 ok( res == ERROR_SUCCESS , "Failed to open summaryinfo\n" );
2966
2968 "Installation Database");
2969 ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
2970
2972 "Installation Database");
2973 ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
2974
2976 "Wine Hackers");
2977 ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
2978
2980 ";1033,2057");
2981 ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
2982
2984 "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}");
2985 ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
2986
2988 ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
2989
2991 ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
2992
2994 ok( res == ERROR_SUCCESS , "Failed to make summary info persist\n" );
2995
2997 ok( res == ERROR_SUCCESS , "Failed to close suminfo\n" );
2998
2999 return res;
3000}
3001
3003{
3004 MSIHANDLE hdb = 0;
3005 UINT res;
3006
3008
3009 /* create an empty database */
3011 ok( res == ERROR_SUCCESS , "Failed to create database\n" );
3012 if( res != ERROR_SUCCESS )
3013 return hdb;
3014
3015 res = MsiDatabaseCommit( hdb );
3016 ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
3017
3018 res = set_summary_info(hdb);
3019 ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
3020
3022
3023 return hdb;
3024}
3025
3027{
3028 UINT res;
3029 CHAR szPackage[12];
3030 MSIHANDLE hPackage;
3031
3032 sprintf(szPackage, "#%lu", hdb);
3033 res = MsiOpenPackageA(szPackage, &hPackage);
3034 if (res != ERROR_SUCCESS)
3035 return res;
3036
3037 res = MsiCloseHandle(hdb);
3038 if (res != ERROR_SUCCESS)
3039 {
3040 MsiCloseHandle(hPackage);
3041 return res;
3042 }
3043
3044 *handle = hPackage;
3045 return ERROR_SUCCESS;
3046}
3047
3048static void test_try_transform(void)
3049{
3050 static const struct {
3051 const char *table;
3052 const char *column;
3053 const char *row;
3054 const char *data;
3055 const char *current;
3056 } transform_view[] = {
3057 { "MOO", "OOO", "1", "c", "a" },
3058 { "MOO", "COW", "", "5378", "3" },
3059 { "MOO", "PIG", "", "5378", "4" },
3060 { "MOO", "PIG", "1", "5", "" },
3061 { "MOO", "DELETE", "3", "", "" },
3062 { "BINARY", "BLOB", "1", "BINARY.1", "" },
3063 { "BINARY", "INSERT", "1", "", "" },
3064 { "AAR", "CREATE", "", "", "" },
3065 { "AAR", "CAR", "", "15871", "1" },
3066 { "AAR", "BAR", "", "1282", "2" },
3067 { "AAR", "BAR", "vw", "1", "" },
3068 { "AAR", "BAR", "bmw", "2", "" },
3069 { "AAR", "INSERT", "vw", "", "" },
3070 { "AAR", "INSERT", "bmw", "", "" },
3071 { "Property", "CREATE", "", "", "" },
3072 { "Property", "Property", "", "11592", "1" },
3073 { "Property", "Value", "", "7424", "2" },
3074 { "Property", "Value", "prop", "val", "" },
3075 { "Property", "INSERT", "prop", "", "" }
3076 };
3077
3078 MSIHANDLE hdb, hview, hrec, hpkg = 0;
3079 LPCSTR query;
3080 UINT r;
3081 DWORD sz;
3082 char buffer[MAX_PATH];
3083 int i, matched;
3084
3087
3088 /* create the database */
3090 ok(hdb, "Failed to create package db\n");
3091
3092 query = "CREATE TABLE `MOO` ( `NOO` SHORT NOT NULL, `OOO` CHAR(255) PRIMARY KEY `NOO`)";
3093 r = run_query(hdb, 0, query);
3094 ok(r == ERROR_SUCCESS, "failed to add table\n");
3095
3096 query = "INSERT INTO `MOO` ( `NOO`, `OOO` ) VALUES ( 1, 'a' )";
3097 r = run_query(hdb, 0, query);
3098 ok(r == ERROR_SUCCESS, "failed to add row\n");
3099
3100 query = "INSERT INTO `MOO` ( `NOO`, `OOO` ) VALUES ( 2, 'b' )";
3101 r = run_query(hdb, 0, query);
3102 ok(r == ERROR_SUCCESS, "failed to add row\n");
3103
3104 query = "INSERT INTO `MOO` ( `NOO`, `OOO` ) VALUES ( 3, 'c' )";
3105 r = run_query(hdb, 0, query);
3106 ok(r == ERROR_SUCCESS, "failed to add row\n");
3107
3108 query = "CREATE TABLE `BINARY` ( `ID` SHORT NOT NULL, `BLOB` OBJECT PRIMARY KEY `ID`)";
3109 r = run_query(hdb, 0, query);
3110 ok(r == ERROR_SUCCESS, "failed to add table\n");
3111
3112 hrec = MsiCreateRecord(2);
3113 r = MsiRecordSetInteger(hrec, 1, 2);
3114 ok(r == ERROR_SUCCESS, "failed to set integer\n");
3115
3116 write_file("testdata.bin", "lamyon", 6);
3117 r = MsiRecordSetStreamA(hrec, 2, "testdata.bin");
3118 ok(r == ERROR_SUCCESS, "failed to set stream\n");
3119
3120 query = "INSERT INTO `BINARY` ( `ID`, `BLOB` ) VALUES ( ?, ? )";
3121 r = run_query(hdb, hrec, query);
3122 ok(r == ERROR_SUCCESS, "failed to add row with blob\n");
3123
3124 MsiCloseHandle(hrec);
3125
3126 r = MsiDatabaseCommit( hdb );
3127 ok( r == ERROR_SUCCESS , "Failed to commit database\n" );
3128
3129 MsiCloseHandle( hdb );
3130 DeleteFileA("testdata.bin");
3131
3132 /*
3133 * Both these generate an equivalent transform,
3134 * but the first doesn't work in Wine yet
3135 * because MsiDatabaseGenerateTransform is unimplemented.
3136 */
3137 if (0)
3139 else
3141
3143 ok( r == ERROR_SUCCESS , "Failed to create database\n" );
3144
3146 ok(r == ERROR_SUCCESS, "return code %d, should be ERROR_SUCCESS\n", r);
3147
3148 query = "select * from `_TransformView`";
3149 r = MsiDatabaseOpenViewA(hdb, query, &hview);
3150 ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
3151 r = MsiViewExecute(hview, 0);
3152 ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
3153
3154 r = MsiViewGetColumnInfo(hview, MSICOLINFO_NAMES, &hrec);
3155 ok(r == ERROR_SUCCESS, "error\n");
3156 check_record(hrec, 5, "Table", "Column", "Row", "Data", "Current");
3157 MsiCloseHandle(hrec);
3158
3159 r = MsiViewGetColumnInfo(hview, MSICOLINFO_TYPES, &hrec);
3160 ok(r == ERROR_SUCCESS, "error\n");
3161 check_record(hrec, 5, "g0", "g0", "G0", "G0", "G0");
3162 MsiCloseHandle(hrec);
3163
3164 matched = 0;
3165 while (MsiViewFetch(hview, &hrec) == ERROR_SUCCESS)
3166 {
3167 char data[5][256];
3168
3169 for (i = 1; i <= 5; i++) {
3170 sz = ARRAY_SIZE(data[0]);
3171 r = MsiRecordGetStringA(hrec, i, data[i-1], &sz);
3172 ok(r == ERROR_SUCCESS, "%d) MsiRecordGetStringA failed %d\n", i, r);
3173 }
3174
3175 for (i = 0; i < ARRAY_SIZE(transform_view); i++)
3176 {
3177 if (strcmp(data[0], transform_view[i].table) ||
3180 continue;
3181
3182 matched++;
3183 ok(!strcmp(data[3], transform_view[i].data), "%d) data[3] = %s\n", i, data[3]);
3184 ok(!strcmp(data[4], transform_view[i].current), "%d) data[4] = %s\n", i, data[4]);
3185 break;
3186 }
3187 ok(i != ARRAY_SIZE(transform_view), "invalid row: %s, %s, %s\n",
3189 MsiCloseHandle(hrec);
3190 }
3191 ok(matched == ARRAY_SIZE(transform_view), "matched = %d\n", matched);
3192
3193 r = MsiViewClose(hview);
3194 ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
3195 r = MsiCloseHandle(hview);
3196 ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
3197
3198 query = "ALTER TABLE `_TransformView` FREE";
3199 r = run_query( hdb, 0, query );
3200 ok( r == ERROR_SUCCESS, "cannot free _TransformView table: %d\n", r );
3201 r = run_query( hdb, 0, query );
3202 ok( r == ERROR_BAD_QUERY_SYNTAX, "_TransformView table still exist: %d\n", r );
3203
3205 ok( r == ERROR_SUCCESS, "return code %d, should be ERROR_SUCCESS\n", r );
3206
3207 r = MsiDatabaseCommit( hdb );
3208 ok( r == ERROR_SUCCESS , "Failed to commit database\n" );
3209
3210 /* check new values */
3211 hrec = 0;
3212 query = "select `BAR`,`CAR` from `AAR` where `BAR` = 1 AND `CAR` = 'vw'";
3213 r = do_query(hdb, query, &hrec);
3214 ok(r == ERROR_SUCCESS, "select query failed\n");
3215 MsiCloseHandle(hrec);
3216
3217 query = "select `BAR`,`CAR` from `AAR` where `BAR` = 2 AND `CAR` = 'bmw'";
3218 hrec = 0;
3219 r = do_query(hdb, query, &hrec);
3220 ok(r == ERROR_SUCCESS, "select query failed\n");
3221 MsiCloseHandle(hrec);
3222
3223 /* check updated values */
3224 hrec = 0;
3225 query = "select `NOO`,`OOO` from `MOO` where `NOO` = 1 AND `OOO` = 'c'";
3226 r = do_query(hdb, query, &hrec);
3227 ok(r == ERROR_SUCCESS, "select query failed\n");
3228 MsiCloseHandle(hrec);
3229
3230 /* check unchanged value */
3231 hrec = 0;
3232 query = "select `NOO`,`OOO` from `MOO` where `NOO` = 2 AND `OOO` = 'b'";
3233 r = do_query(hdb, query, &hrec);
3234 ok(r == ERROR_SUCCESS, "select query failed\n");
3235 MsiCloseHandle(hrec);
3236
3237 /* check deleted value */
3238 hrec = 0;
3239 query = "select * from `MOO` where `NOO` = 3";
3240 r = do_query(hdb, query, &hrec);
3241 ok(r == ERROR_NO_MORE_ITEMS, "select query failed\n");
3242 if (hrec) MsiCloseHandle(hrec);
3243
3244 /* check added stream */
3245 hrec = 0;
3246 query = "select `BLOB` from `BINARY` where `ID` = 1";
3247 r = do_query(hdb, query, &hrec);
3248 ok(r == ERROR_SUCCESS, "select query failed\n");
3249
3250 /* check the contents of the stream */
3251 sz = sizeof buffer;
3252 r = MsiRecordReadStream( hrec, 1, buffer, &sz );
3253 ok(r == ERROR_SUCCESS, "read stream failed\n");
3254 ok(!memcmp(buffer, "naengmyon", 9), "stream data was wrong\n");
3255 ok(sz == 9, "stream data was wrong size\n");
3256 if (hrec) MsiCloseHandle(hrec);
3257
3258 /* check the validity of the table with a deleted row */
3259 hrec = 0;
3260 query = "select * from `MOO`";
3261 r = MsiDatabaseOpenViewA(hdb, query, &hview);
3262 ok(r == ERROR_SUCCESS, "open view failed\n");
3263
3264 r = MsiViewExecute(hview, 0);
3265 ok(r == ERROR_SUCCESS, "view execute failed\n");
3266
3267 r = MsiViewFetch(hview, &hrec);
3268 ok(r == ERROR_SUCCESS, "view fetch failed\n");
3269 check_record(hrec, 4, "1", "c", "", "5");
3270 MsiCloseHandle(hrec);
3271
3272 r = MsiViewFetch(hview, &hrec);
3273 ok(r == ERROR_SUCCESS, "view fetch failed\n");
3274 check_record(hrec, 4, "2", "b", "", "");
3275 MsiCloseHandle(hrec);
3276
3277 r = MsiViewFetch(hview, &hrec);
3278 ok(r == ERROR_NO_MORE_ITEMS, "view fetch succeeded\n");
3279
3280 MsiCloseHandle(hrec);
3281 MsiViewClose(hview);
3282 MsiCloseHandle(hview);
3283
3284 /* check that the property was added */
3285 r = package_from_db(hdb, &hpkg);
3287 {
3288 skip("Not enough rights to perform tests\n");
3289 goto error;
3290 }
3291 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
3292
3293 sz = MAX_PATH;
3294 r = MsiGetPropertyA(hpkg, "prop", buffer, &sz);
3295 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3296 ok(!lstrcmpA(buffer, "val"), "Expected val, got %s\n", buffer);
3297
3298 MsiCloseHandle(hpkg);
3299
3300error:
3301 MsiCloseHandle(hdb);
3304}
3305
3306static const char *join_res_first[][2] =
3307{
3308 { "alveolar", "procerus" },
3309 { "septum", "procerus" },
3310 { "septum", "nasalis" },
3311 { "ramus", "nasalis" },
3312 { "malar", "mentalis" },
3313};
3314
3315static const char *join_res_second[][2] =
3316{
3317 { "nasal", "septum" },
3318 { "mandible", "ramus" },
3319};
3320
3321static const char *join_res_third[][2] =
3322{
3323 { "msvcp.dll", "abcdefgh" },
3324 { "msvcr.dll", "ijklmnop" },
3325};
3326
3327static const char *join_res_fourth[][2] =
3328{
3329 { "msvcp.dll.01234", "single.dll.31415" },
3330};
3331
3332static const char *join_res_fifth[][2] =
3333{
3334 { "malar", "procerus" },
3335};
3336
3337static const char *join_res_sixth[][2] =
3338{
3339 { "malar", "procerus" },
3340 { "malar", "procerus" },
3341 { "malar", "nasalis" },
3342 { "malar", "nasalis" },
3343 { "malar", "nasalis" },
3344 { "malar", "mentalis" },
3345};
3346
3347static const char *join_res_seventh[][2] =
3348{
3349 { "malar", "nasalis" },
3350 { "malar", "nasalis" },
3351 { "malar", "nasalis" },
3352};
3353
3354static const char *join_res_eighth[][4] =
3355{
3356 { "msvcp.dll", "msvcp.dll.01234", "msvcp.dll.01234", "abcdefgh" },
3357 { "msvcr.dll", "msvcr.dll.56789", "msvcp.dll.01234", "abcdefgh" },
3358 { "msvcp.dll", "msvcp.dll.01234", "msvcr.dll.56789", "ijklmnop" },
3359 { "msvcr.dll", "msvcr.dll.56789", "msvcr.dll.56789", "ijklmnop" },
3360 { "msvcp.dll", "msvcp.dll.01234", "single.dll.31415", "msvcp.dll" },
3361 { "msvcr.dll", "msvcr.dll.56789", "single.dll.31415", "msvcp.dll" },
3362};
3363
3364static const char *join_res_ninth[][6] =
3365{
3366 { "1", "2", "3", "4", "7", "8" },
3367 { "1", "2", "5", "6", "7", "8" },
3368 { "1", "2", "3", "4", "9", "10" },
3369 { "1", "2", "5", "6", "9", "10" },
3370 { "1", "2", "3", "4", "11", "12" },
3371 { "1", "2", "5", "6", "11", "12" },
3372};
3373
3374static void test_join(void)
3375{
3376 MSIHANDLE hdb, hview, hrec;
3377 LPCSTR query;
3378 UINT r;
3379 DWORD i;
3380
3381 hdb = create_db();
3382 ok( hdb, "failed to create db\n");
3383
3385 add_component_entry( hdb, "'zygomatic', 'malar', 'INSTALLDIR', 0, '', ''" );
3386 add_component_entry( hdb, "'maxilla', 'alveolar', 'INSTALLDIR', 0, '', ''" );
3387 add_component_entry( hdb, "'nasal', 'septum', 'INSTALLDIR', 0, '', ''" );
3388 add_component_entry( hdb, "'mandible', 'ramus', 'INSTALLDIR', 0, '', ''" );
3389
3391 add_feature_components_entry( hdb, "'procerus', 'maxilla'" );
3392 add_feature_components_entry( hdb, "'procerus', 'nasal'" );
3393 add_feature_components_entry( hdb, "'nasalis', 'nasal'" );
3394 add_feature_components_entry( hdb, "'nasalis', 'mandible'" );
3395 add_feature_components_entry( hdb, "'nasalis', 'notacomponent'" );
3396 add_feature_components_entry( hdb, "'mentalis', 'zygomatic'" );