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