Release 1.5.29.
[wine] / dlls / msi / tests / db.c
1 /*
2  * Copyright (C) 2005 Mike McCormack for CodeWeavers
3  *
4  * A test program for MSI database files.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #define COBJMACROS
22
23 #include <stdio.h>
24
25 #include <windows.h>
26 #include <msi.h>
27 #include <msidefs.h>
28 #include <msiquery.h>
29
30 #include <objidl.h>
31
32 #include "wine/test.h"
33
34 static const char *msifile = "winetest-db.msi";
35 static const char *msifile2 = "winetst2-db.msi";
36 static const char *mstfile = "winetst-db.mst";
37 static const WCHAR msifileW[] = {'w','i','n','e','t','e','s','t','-','d','b','.','m','s','i',0};
38
39 static void test_msidatabase(void)
40 {
41     MSIHANDLE hdb = 0, hdb2 = 0;
42     UINT res;
43
44     DeleteFile(msifile);
45
46     res = MsiOpenDatabase( msifile, msifile2, &hdb );
47     ok( res == ERROR_OPEN_FAILED, "expected failure\n");
48
49     res = MsiOpenDatabase( msifile, (LPSTR) 0xff, &hdb );
50     ok( res == ERROR_INVALID_PARAMETER, "expected failure\n");
51
52     res = MsiCloseHandle( hdb );
53     ok( res == ERROR_SUCCESS , "Failed to close database\n" );
54
55     /* create an empty database */
56     res = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb );
57     ok( res == ERROR_SUCCESS , "Failed to create database\n" );
58
59     res = MsiDatabaseCommit( hdb );
60     ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
61
62     ok( INVALID_FILE_ATTRIBUTES != GetFileAttributes( msifile ), "database should exist\n");
63
64     res = MsiCloseHandle( hdb );
65     ok( res == ERROR_SUCCESS , "Failed to close database\n" );
66     res = MsiOpenDatabase( msifile, msifile2, &hdb2 );
67     ok( res == ERROR_SUCCESS , "Failed to open database\n" );
68
69     ok( INVALID_FILE_ATTRIBUTES != GetFileAttributes( msifile2 ), "database should exist\n");
70
71     res = MsiDatabaseCommit( hdb2 );
72     ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
73
74     res = MsiCloseHandle( hdb2 );
75     ok( res == ERROR_SUCCESS , "Failed to close database\n" );
76
77     res = MsiOpenDatabase( msifile, msifile2, &hdb2 );
78     ok( res == ERROR_SUCCESS , "Failed to open database\n" );
79
80     res = MsiCloseHandle( hdb2 );
81     ok( res == ERROR_SUCCESS , "Failed to close database\n" );
82
83     ok( INVALID_FILE_ATTRIBUTES == GetFileAttributes( msifile2 ), "uncommitted database should not exist\n");
84
85     res = MsiOpenDatabase( msifile, msifile2, &hdb2 );
86     ok( res == ERROR_SUCCESS , "Failed to close database\n" );
87
88     res = MsiDatabaseCommit( hdb2 );
89     ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
90
91     res = MsiCloseHandle( hdb2 );
92     ok( res == ERROR_SUCCESS , "Failed to close database\n" );
93
94     ok( INVALID_FILE_ATTRIBUTES != GetFileAttributes( msifile2 ), "committed database should exist\n");
95
96     res = MsiOpenDatabase( msifile, MSIDBOPEN_READONLY, &hdb );
97     ok( res == ERROR_SUCCESS , "Failed to open database\n" );
98
99     res = MsiDatabaseCommit( hdb );
100     ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
101
102     res = MsiCloseHandle( hdb );
103     ok( res == ERROR_SUCCESS , "Failed to close database\n" );
104
105     res = MsiOpenDatabase( msifile, MSIDBOPEN_DIRECT, &hdb );
106     ok( res == ERROR_SUCCESS , "Failed to open database\n" );
107
108     res = MsiCloseHandle( hdb );
109     ok( res == ERROR_SUCCESS , "Failed to close database\n" );
110
111     res = MsiOpenDatabase( msifile, MSIDBOPEN_TRANSACT, &hdb );
112     ok( res == ERROR_SUCCESS , "Failed to open database\n" );
113
114     res = MsiCloseHandle( hdb );
115     ok( res == ERROR_SUCCESS , "Failed to close database\n" );
116     ok( INVALID_FILE_ATTRIBUTES != GetFileAttributes( msifile ), "database should exist\n");
117
118     /* MSIDBOPEN_CREATE deletes the database if MsiCommitDatabase isn't called */
119     res = MsiOpenDatabase( msifile, MSIDBOPEN_CREATE, &hdb );
120     ok( res == ERROR_SUCCESS , "Failed to open database\n" );
121
122     ok( INVALID_FILE_ATTRIBUTES != GetFileAttributes( msifile ), "database should exist\n");
123
124     res = MsiCloseHandle( hdb );
125     ok( res == ERROR_SUCCESS , "Failed to close database\n" );
126
127     ok( INVALID_FILE_ATTRIBUTES == GetFileAttributes( msifile ), "database should exist\n");
128
129     res = MsiOpenDatabase( msifile, MSIDBOPEN_CREATE, &hdb );
130     ok( res == ERROR_SUCCESS , "Failed to open database\n" );
131
132     res = MsiDatabaseCommit( hdb );
133     ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
134
135     ok( INVALID_FILE_ATTRIBUTES != GetFileAttributes( msifile ), "database should exist\n");
136
137     res = MsiCloseHandle( hdb );
138     ok( res == ERROR_SUCCESS , "Failed to close database\n" );
139
140     res = DeleteFile( msifile2 );
141     ok( res == TRUE, "Failed to delete database\n" );
142
143     res = DeleteFile( msifile );
144     ok( res == TRUE, "Failed to delete database\n" );
145 }
146
147 static UINT do_query(MSIHANDLE hdb, const char *query, MSIHANDLE *phrec)
148 {
149     MSIHANDLE hview = 0;
150     UINT r, ret;
151
152     if (phrec)
153         *phrec = 0;
154
155     /* open a select query */
156     r = MsiDatabaseOpenView(hdb, query, &hview);
157     if (r != ERROR_SUCCESS)
158         return r;
159     r = MsiViewExecute(hview, 0);
160     if (r != ERROR_SUCCESS)
161         return r;
162     ret = MsiViewFetch(hview, phrec);
163     r = MsiViewClose(hview);
164     if (r != ERROR_SUCCESS)
165         return r;
166     r = MsiCloseHandle(hview);
167     if (r != ERROR_SUCCESS)
168         return r;
169     return ret;
170 }
171
172 static UINT run_query( MSIHANDLE hdb, MSIHANDLE hrec, const char *query )
173 {
174     MSIHANDLE hview = 0;
175     UINT r;
176
177     r = MsiDatabaseOpenView(hdb, query, &hview);
178     if( r != ERROR_SUCCESS )
179         return r;
180
181     r = MsiViewExecute(hview, hrec);
182     if( r == ERROR_SUCCESS )
183         r = MsiViewClose(hview);
184     MsiCloseHandle(hview);
185     return r;
186 }
187
188 static UINT run_queryW( MSIHANDLE hdb, MSIHANDLE hrec, const WCHAR *query )
189 {
190     MSIHANDLE hview = 0;
191     UINT r;
192
193     r = MsiDatabaseOpenViewW(hdb, query, &hview);
194     if( r != ERROR_SUCCESS )
195         return r;
196
197     r = MsiViewExecute(hview, hrec);
198     if( r == ERROR_SUCCESS )
199         r = MsiViewClose(hview);
200     MsiCloseHandle(hview);
201     return r;
202 }
203
204 static UINT create_component_table( MSIHANDLE hdb )
205 {
206     return run_query( hdb, 0,
207             "CREATE TABLE `Component` ( "
208             "`Component` CHAR(72) NOT NULL, "
209             "`ComponentId` CHAR(38), "
210             "`Directory_` CHAR(72) NOT NULL, "
211             "`Attributes` SHORT NOT NULL, "
212             "`Condition` CHAR(255), "
213             "`KeyPath` CHAR(72) "
214             "PRIMARY KEY `Component`)" );
215 }
216
217 static UINT create_custom_action_table( MSIHANDLE hdb )
218 {
219     return run_query( hdb, 0,
220             "CREATE TABLE `CustomAction` ( "
221             "`Action` CHAR(72) NOT NULL, "
222             "`Type` SHORT NOT NULL, "
223             "`Source` CHAR(72), "
224             "`Target` CHAR(255) "
225             "PRIMARY KEY `Action`)" );
226 }
227
228 static UINT create_directory_table( MSIHANDLE hdb )
229 {
230     return run_query( hdb, 0,
231             "CREATE TABLE `Directory` ( "
232             "`Directory` CHAR(255) NOT NULL, "
233             "`Directory_Parent` CHAR(255), "
234             "`DefaultDir` CHAR(255) NOT NULL "
235             "PRIMARY KEY `Directory`)" );
236 }
237
238 static UINT create_feature_components_table( MSIHANDLE hdb )
239 {
240     return run_query( hdb, 0,
241             "CREATE TABLE `FeatureComponents` ( "
242             "`Feature_` CHAR(38) NOT NULL, "
243             "`Component_` CHAR(72) NOT NULL "
244             "PRIMARY KEY `Feature_`, `Component_` )" );
245 }
246
247 static UINT create_std_dlls_table( MSIHANDLE hdb )
248 {
249     return run_query( hdb, 0,
250             "CREATE TABLE `StdDlls` ( "
251             "`File` CHAR(255) NOT NULL, "
252             "`Binary_` CHAR(72) NOT NULL "
253             "PRIMARY KEY `File` )" );
254 }
255
256 static UINT create_binary_table( MSIHANDLE hdb )
257 {
258     return run_query( hdb, 0,
259             "CREATE TABLE `Binary` ( "
260             "`Name` CHAR(72) NOT NULL, "
261             "`Data` CHAR(72) NOT NULL "
262             "PRIMARY KEY `Name` )" );
263 }
264
265 #define make_add_entry(type, qtext) \
266     static UINT add##_##type##_##entry( MSIHANDLE hdb, const char *values ) \
267     { \
268         char insert[] = qtext; \
269         char *query; \
270         UINT sz, r; \
271         sz = strlen(values) + sizeof insert; \
272         query = HeapAlloc(GetProcessHeap(),0,sz); \
273         sprintf(query,insert,values); \
274         r = run_query( hdb, 0, query ); \
275         HeapFree(GetProcessHeap(), 0, query); \
276         return r; \
277     }
278
279 make_add_entry(component,
280                "INSERT INTO `Component`  "
281                "(`Component`, `ComponentId`, `Directory_`, "
282                "`Attributes`, `Condition`, `KeyPath`) VALUES( %s )")
283
284 make_add_entry(custom_action,
285                "INSERT INTO `CustomAction`  "
286                "(`Action`, `Type`, `Source`, `Target`) VALUES( %s )")
287
288 make_add_entry(feature_components,
289                "INSERT INTO `FeatureComponents` "
290                "(`Feature_`, `Component_`) VALUES( %s )")
291
292 make_add_entry(std_dlls,
293                "INSERT INTO `StdDlls` (`File`, `Binary_`) VALUES( %s )")
294
295 make_add_entry(binary,
296                "INSERT INTO `Binary` (`Name`, `Data`) VALUES( %s )")
297
298 static void test_msiinsert(void)
299 {
300     MSIHANDLE hdb = 0, hview = 0, hview2 = 0, hrec = 0;
301     UINT r;
302     const char *query;
303     char buf[80];
304     DWORD sz;
305
306     DeleteFile(msifile);
307
308     /* just MsiOpenDatabase should not create a file */
309     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
310     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
311
312     /* create a table */
313     query = "CREATE TABLE `phone` ( "
314             "`id` INT, `name` CHAR(32), `number` CHAR(32) "
315             "PRIMARY KEY `id`)";
316     r = MsiDatabaseOpenView(hdb, query, &hview);
317     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
318     r = MsiViewExecute(hview, 0);
319     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
320     r = MsiViewClose(hview);
321     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
322     r = MsiCloseHandle(hview);
323     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
324
325     query = "SELECT * FROM phone WHERE number = '8675309'";
326     r = MsiDatabaseOpenView(hdb, query, &hview2);
327     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
328     r = MsiViewExecute(hview2, 0);
329     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
330     r = MsiViewFetch(hview2, &hrec);
331     ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch produced items\n");
332
333     /* insert a value into it */
334     query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
335         "VALUES('1', 'Abe', '8675309')";
336     r = MsiDatabaseOpenView(hdb, query, &hview);
337     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
338     r = MsiViewExecute(hview, 0);
339     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
340     r = MsiViewClose(hview);
341     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
342     r = MsiCloseHandle(hview);
343     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
344
345     r = MsiViewFetch(hview2, &hrec);
346     ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch produced items\n");
347     r = MsiViewExecute(hview2, 0);
348     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
349     r = MsiViewFetch(hview2, &hrec);
350     ok(r == ERROR_SUCCESS, "MsiViewFetch failed: %u\n", r);
351
352     r = MsiCloseHandle(hrec);
353     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
354     r = MsiViewClose(hview2);
355     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
356     r = MsiCloseHandle(hview2);
357     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
358
359     query = "SELECT * FROM `phone` WHERE `id` = 1";
360     r = do_query(hdb, query, &hrec);
361     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
362
363     /* check the record contains what we put in it */
364     r = MsiRecordGetFieldCount(hrec);
365     ok(r == 3, "record count wrong\n");
366
367     r = MsiRecordIsNull(hrec, 0);
368     ok(r == FALSE, "field 0 not null\n");
369
370     r = MsiRecordGetInteger(hrec, 1);
371     ok(r == 1, "field 1 contents wrong\n");
372     sz = sizeof buf;
373     r = MsiRecordGetString(hrec, 2, buf, &sz);
374     ok(r == ERROR_SUCCESS, "field 2 content fetch failed\n");
375     ok(!strcmp(buf,"Abe"), "field 2 content incorrect\n");
376     sz = sizeof buf;
377     r = MsiRecordGetString(hrec, 3, buf, &sz);
378     ok(r == ERROR_SUCCESS, "field 3 content fetch failed\n");
379     ok(!strcmp(buf,"8675309"), "field 3 content incorrect\n");
380
381     r = MsiCloseHandle(hrec);
382     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
383
384     /* open a select query */
385     hrec = 100;
386     query = "SELECT * FROM `phone` WHERE `id` >= 10";
387     r = do_query(hdb, query, &hrec);
388     ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch failed\n");
389     ok(hrec == 0, "hrec should be null\n");
390
391     r = MsiCloseHandle(hrec);
392     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
393
394     query = "SELECT * FROM `phone` WHERE `id` < 0";
395     r = do_query(hdb, query, &hrec);
396     ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch failed\n");
397
398     query = "SELECT * FROM `phone` WHERE `id` <= 0";
399     r = do_query(hdb, query, &hrec);
400     ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch failed\n");
401
402     query = "SELECT * FROM `phone` WHERE `id` <> 1";
403     r = do_query(hdb, query, &hrec);
404     ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch failed\n");
405
406     query = "SELECT * FROM `phone` WHERE `id` > 10";
407     r = do_query(hdb, query, &hrec);
408     ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch failed\n");
409
410     /* now try a few bad INSERT xqueries */
411     query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
412         "VALUES(?, ?)";
413     r = MsiDatabaseOpenView(hdb, query, &hview);
414     ok(r == ERROR_BAD_QUERY_SYNTAX, "MsiDatabaseOpenView failed\n");
415
416     /* construct a record to insert */
417     hrec = MsiCreateRecord(4);
418     r = MsiRecordSetInteger(hrec, 1, 2);
419     ok(r == ERROR_SUCCESS, "MsiRecordSetInteger failed\n");
420     r = MsiRecordSetString(hrec, 2, "Adam");
421     ok(r == ERROR_SUCCESS, "MsiRecordSetString failed\n");
422     r = MsiRecordSetString(hrec, 3, "96905305");
423     ok(r == ERROR_SUCCESS, "MsiRecordSetString failed\n");
424
425     /* insert another value, using a record and wildcards */
426     query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
427         "VALUES(?, ?, ?)";
428     r = MsiDatabaseOpenView(hdb, query, &hview);
429     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
430
431     if (r == ERROR_SUCCESS)
432     {
433         r = MsiViewExecute(hview, hrec);
434         ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
435         r = MsiViewClose(hview);
436         ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
437         r = MsiCloseHandle(hview);
438         ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
439     }
440     r = MsiCloseHandle(hrec);
441     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
442
443     r = MsiViewFetch(0, NULL);
444     ok(r == ERROR_INVALID_PARAMETER, "MsiViewFetch failed\n");
445
446     r = MsiDatabaseCommit(hdb);
447     ok(r == ERROR_SUCCESS, "MsiDatabaseCommit failed\n");
448
449     r = MsiCloseHandle(hdb);
450     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
451
452     r = DeleteFile(msifile);
453     ok(r == TRUE, "file didn't exist after commit\n");
454 }
455
456 static void test_msidecomposedesc(void)
457 {
458     UINT (WINAPI *pMsiDecomposeDescriptorA)(LPCSTR, LPCSTR, LPSTR, LPSTR, DWORD *);
459     char prod[MAX_FEATURE_CHARS+1], comp[MAX_FEATURE_CHARS+1], feature[MAX_FEATURE_CHARS+1];
460     const char *desc;
461     UINT r;
462     DWORD len;
463     HMODULE hmod;
464
465     hmod = GetModuleHandle("msi.dll");
466     pMsiDecomposeDescriptorA = (void*)GetProcAddress(hmod, "MsiDecomposeDescriptorA");
467     if (!pMsiDecomposeDescriptorA)
468         return;
469
470     /* test a valid feature descriptor */
471     desc = "']gAVn-}f(ZXfeAR6.jiFollowTheWhiteRabbit>3w2x^IGfe?CxI5heAvk.";
472     len = 0;
473     r = pMsiDecomposeDescriptorA(desc, prod, feature, comp, &len);
474     ok(r == ERROR_SUCCESS, "returned an error\n");
475     ok(len == strlen(desc), "length was wrong\n");
476     ok(strcmp(prod,"{90110409-6000-11D3-8CFE-0150048383C9}")==0, "product wrong\n");
477     ok(strcmp(feature,"FollowTheWhiteRabbit")==0, "feature wrong\n");
478     ok(strcmp(comp,"{A7CD68DB-EF74-49C8-FBB2-A7C463B2AC24}")==0,"component wrong\n");
479
480     /* test an invalid feature descriptor with too many characters */
481     desc = "']gAVn-}f(ZXfeAR6.ji"
482            "ThisWillFailIfTheresMoreThanAGuidsChars>"
483            "3w2x^IGfe?CxI5heAvk.";
484     len = 0;
485     r = pMsiDecomposeDescriptorA(desc, prod, feature, comp, &len);
486     ok(r == ERROR_INVALID_PARAMETER, "returned wrong error\n");
487
488     /*
489      * Test a valid feature descriptor with the
490      * maximum number of characters and some trailing characters.
491      */
492     desc = "']gAVn-}f(ZXfeAR6.ji"
493            "ThisWillWorkIfTheresLTEThanAGuidsChars>"
494            "3w2x^IGfe?CxI5heAvk."
495            "extra";
496     len = 0;
497     r = pMsiDecomposeDescriptorA(desc, prod, feature, comp, &len);
498     ok(r == ERROR_SUCCESS, "returned wrong error\n");
499     ok(len == (strlen(desc) - strlen("extra")), "length wrong\n");
500
501     len = 0;
502     r = pMsiDecomposeDescriptorA(desc, prod, feature, NULL, &len);
503     ok(r == ERROR_SUCCESS, "returned wrong error\n");
504     ok(len == (strlen(desc) - strlen("extra")), "length wrong\n");
505
506     len = 0;
507     r = pMsiDecomposeDescriptorA(desc, prod, NULL, NULL, &len);
508     ok(r == ERROR_SUCCESS, "returned wrong error\n");
509     ok(len == (strlen(desc) - strlen("extra")), "length wrong\n");
510
511     len = 0;
512     r = pMsiDecomposeDescriptorA(desc, NULL, NULL, NULL, &len);
513     ok(r == ERROR_SUCCESS, "returned wrong error\n");
514     ok(len == (strlen(desc) - strlen("extra")), "length wrong\n");
515
516     len = 0;
517     r = pMsiDecomposeDescriptorA(NULL, NULL, NULL, NULL, &len);
518     ok(r == ERROR_INVALID_PARAMETER, "returned wrong error\n");
519     ok(len == 0, "length wrong\n");
520
521     r = pMsiDecomposeDescriptorA(desc, NULL, NULL, NULL, NULL);
522     ok(r == ERROR_SUCCESS, "returned wrong error\n");
523 }
524
525 static UINT try_query_param( MSIHANDLE hdb, LPCSTR szQuery, MSIHANDLE hrec )
526 {
527     MSIHANDLE htab = 0;
528     UINT res;
529
530     res = MsiDatabaseOpenView( hdb, szQuery, &htab );
531     if(res == ERROR_SUCCESS )
532     {
533         UINT r;
534
535         r = MsiViewExecute( htab, hrec );
536         if(r != ERROR_SUCCESS )
537             res = r;
538
539         r = MsiViewClose( htab );
540         if(r != ERROR_SUCCESS )
541             res = r;
542
543         r = MsiCloseHandle( htab );
544         if(r != ERROR_SUCCESS )
545             res = r;
546     }
547     return res;
548 }
549
550 static UINT try_query( MSIHANDLE hdb, LPCSTR szQuery )
551 {
552     return try_query_param( hdb, szQuery, 0 );
553 }
554
555 static UINT try_insert_query( MSIHANDLE hdb, LPCSTR szQuery )
556 {
557     MSIHANDLE hrec = 0;
558     UINT r;
559
560     hrec = MsiCreateRecord( 1 );
561     MsiRecordSetString( hrec, 1, "Hello");
562
563     r = try_query_param( hdb, szQuery, hrec );
564
565     MsiCloseHandle( hrec );
566     return r;
567 }
568
569 static void test_msibadqueries(void)
570 {
571     MSIHANDLE hdb = 0;
572     UINT r;
573
574     DeleteFile(msifile);
575
576     /* just MsiOpenDatabase should not create a file */
577     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
578     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
579
580     r = MsiDatabaseCommit( hdb );
581     ok(r == ERROR_SUCCESS , "Failed to commit database\n");
582
583     r = MsiCloseHandle( hdb );
584     ok(r == ERROR_SUCCESS , "Failed to close database\n");
585
586     /* open it readonly */
587     r = MsiOpenDatabase(msifile, MSIDBOPEN_READONLY, &hdb );
588     ok(r == ERROR_SUCCESS , "Failed to open database r/o\n");
589
590     /* add a table to it */
591     r = try_query( hdb, "select * from _Tables");
592     ok(r == ERROR_SUCCESS , "query 1 failed\n");
593
594     r = MsiCloseHandle( hdb );
595     ok(r == ERROR_SUCCESS , "Failed to close database r/o\n");
596
597     /* open it read/write */
598     r = MsiOpenDatabase(msifile, MSIDBOPEN_TRANSACT, &hdb );
599     ok(r == ERROR_SUCCESS , "Failed to open database r/w\n");
600
601     /* a bunch of test queries that fail with the native MSI */
602
603     r = try_query( hdb, "CREATE TABLE");
604     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2a return code\n");
605
606     r = try_query( hdb, "CREATE TABLE `a`");
607     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2b return code\n");
608
609     r = try_query( hdb, "CREATE TABLE `a` ()");
610     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2c return code\n");
611
612     r = try_query( hdb, "CREATE TABLE `a` (`b`)");
613     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2d return code\n");
614
615     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) )");
616     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2e return code\n");
617
618     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL)");
619     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2f return code\n");
620
621     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY)");
622     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2g return code\n");
623
624     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY)");
625     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2h return code\n");
626
627     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY)");
628     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2i return code\n");
629
630     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY 'b')");
631     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2j return code\n");
632
633     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY `b')");
634     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2k return code\n");
635
636     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY `b')");
637     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2l return code\n");
638
639     r = try_query( hdb, "CREATE TABLE `a` (`b` CHA(72) NOT NULL PRIMARY KEY `b`)");
640     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2m return code\n");
641
642     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(-1) NOT NULL PRIMARY KEY `b`)");
643     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2n return code\n");
644
645     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(720) NOT NULL PRIMARY KEY `b`)");
646     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2o return code\n");
647
648     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL KEY `b`)");
649     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2p return code\n");
650
651     r = try_query( hdb, "CREATE TABLE `a` (`` CHAR(72) NOT NULL PRIMARY KEY `b`)");
652     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2p return code\n");
653
654     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY `b`)");
655     ok(r == ERROR_SUCCESS , "valid query 2z failed\n");
656
657     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY `b`)");
658     ok(r == ERROR_BAD_QUERY_SYNTAX , "created same table again\n");
659
660     r = try_query( hdb, "CREATE TABLE `aa` (`b` CHAR(72) NOT NULL, `c` "
661           "CHAR(72), `d` CHAR(255) NOT NULL LOCALIZABLE PRIMARY KEY `b`)");
662     ok(r == ERROR_SUCCESS , "query 4 failed\n");
663
664     r = MsiDatabaseCommit( hdb );
665     ok(r == ERROR_SUCCESS , "Failed to commit database after write\n");
666
667     r = try_query( hdb, "CREATE TABLE `blah` (`foo` CHAR(72) NOT NULL "
668                           "PRIMARY KEY `foo`)");
669     ok(r == ERROR_SUCCESS , "query 4 failed\n");
670
671     r = try_insert_query( hdb, "insert into a  ( `b` ) VALUES ( ? )");
672     ok(r == ERROR_SUCCESS , "failed to insert record in db\n");
673
674     r = MsiDatabaseCommit( hdb );
675     ok(r == ERROR_SUCCESS , "Failed to commit database after write\n");
676
677     r = try_query( hdb, "CREATE TABLE `boo` (`foo` CHAR(72) NOT NULL "
678                           "PRIMARY KEY `ba`)");
679     ok(r != ERROR_SUCCESS , "query 5 succeeded\n");
680
681     r = try_query( hdb,"CREATE TABLE `bee` (`foo` CHAR(72) NOT NULL )");
682     ok(r != ERROR_SUCCESS , "query 6 succeeded\n");
683
684     r = try_query( hdb, "CREATE TABLE `temp` (`t` CHAR(72) NOT NULL "
685                           "PRIMARY KEY `t`)");
686     ok(r == ERROR_SUCCESS , "query 7 failed\n");
687
688     r = try_query( hdb, "CREATE TABLE `c` (`b` CHAR NOT NULL PRIMARY KEY `b`)");
689     ok(r == ERROR_SUCCESS , "query 8 failed\n");
690
691     r = try_query( hdb, "select * from c");
692     ok(r == ERROR_SUCCESS , "query failed\n");
693
694     r = try_query( hdb, "select * from c where b = 'x");
695     ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
696
697     r = try_query( hdb, "select * from c where b = 'x'");
698     ok(r == ERROR_SUCCESS, "query failed\n");
699
700     r = try_query( hdb, "select * from 'c'");
701     ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
702
703     r = try_query( hdb, "select * from ''");
704     ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
705
706     r = try_query( hdb, "select * from c where b = x");
707     ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
708
709     r = try_query( hdb, "select * from c where b = \"x\"");
710     ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
711
712     r = try_query( hdb, "select * from c where b = 'x'");
713     ok(r == ERROR_SUCCESS, "query failed\n");
714
715     r = try_query( hdb, "select * from c where b = '\"x'");
716     ok(r == ERROR_SUCCESS, "query failed\n");
717
718     if (0)  /* FIXME: this query causes trouble with other tests */
719     {
720         r = try_query( hdb, "select * from c where b = '\\\'x'");
721         ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
722     }
723
724     r = try_query( hdb, "select * from 'c'");
725     ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
726
727     r = try_query( hdb, "select `c`.`b` from `c` order by `c`.`order`");
728     ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %u\n", r );
729
730     r = try_query( hdb, "select `c`.b` from `c`");
731     ok( r == ERROR_SUCCESS, "query failed: %u\n", r );
732
733     r = try_query( hdb, "select `c`.`b from `c`");
734     ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %u\n", r );
735
736     r = try_query( hdb, "select `c`.b from `c`");
737     ok( r == ERROR_SUCCESS, "query failed: %u\n", r );
738
739     r = try_query( hdb, "select `c.`b` from `c`");
740     ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %u\n", r );
741
742     r = try_query( hdb, "select c`.`b` from `c`");
743     ok( r == ERROR_SUCCESS, "query failed: %u\n", r );
744
745     r = try_query( hdb, "select c.`b` from `c`");
746     ok( r == ERROR_SUCCESS, "query failed: %u\n", r );
747
748     r = try_query( hdb, "select `c`.`b` from c`");
749     ok( r == ERROR_SUCCESS, "query failed: %u\n", r );
750
751     r = try_query( hdb, "select `c`.`b` from `c");
752     ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %u\n", r );
753
754     r = try_query( hdb, "select `c`.`b` from c");
755     ok( r == ERROR_SUCCESS, "query failed: %u\n", r );
756
757     r = try_query( hdb, "CREATE TABLE `\5a` (`b` CHAR NOT NULL PRIMARY KEY `b`)" );
758     ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
759
760     r = try_query( hdb, "SELECT * FROM \5a" );
761     ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
762
763     r = try_query( hdb, "CREATE TABLE `a\5` (`b` CHAR NOT NULL PRIMARY KEY `b`)" );
764     ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
765
766     r = try_query( hdb, "SELECT * FROM a\5" );
767     ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
768
769     r = try_query( hdb, "CREATE TABLE `-a` (`b` CHAR NOT NULL PRIMARY KEY `b`)" );
770     ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
771
772     r = try_query( hdb, "SELECT * FROM -a" );
773     todo_wine ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
774
775     r = try_query( hdb, "CREATE TABLE `a-` (`b` CHAR NOT NULL PRIMARY KEY `b`)" );
776     ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
777
778     r = try_query( hdb, "SELECT * FROM a-" );
779     ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
780
781     r = MsiCloseHandle( hdb );
782     ok(r == ERROR_SUCCESS , "Failed to close database transact\n");
783
784     r = DeleteFile( msifile );
785     ok(r == TRUE, "file didn't exist after commit\n");
786 }
787
788 static void test_viewmodify(void)
789 {
790     MSIHANDLE hdb = 0, hview = 0, hrec = 0;
791     UINT r;
792     MSIDBERROR err;
793     const char *query;
794     char buffer[0x100];
795     DWORD sz;
796
797     DeleteFile(msifile);
798
799     /* just MsiOpenDatabase should not create a file */
800     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
801     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
802
803     query = "CREATE TABLE `phone` ( "
804             "`id` INT, `name` CHAR(32), `number` CHAR(32) "
805             "PRIMARY KEY `id`)";
806     r = run_query( hdb, 0, query );
807     ok(r == ERROR_SUCCESS, "query failed\n");
808
809     query = "CREATE TABLE `_Validation` ( "
810             "`Table` CHAR(32) NOT NULL, `Column` CHAR(32) NOT NULL, "
811             "`Nullable` CHAR(4) NOT NULL, `MinValue` INT, `MaxValue` INT, "
812             "`KeyTable` CHAR(255), `KeyColumn` SHORT, `Category` CHAR(32), "
813             "`Set` CHAR(255), `Description` CHAR(255) PRIMARY KEY `Table`, `Column`)";
814     r = run_query( hdb, 0, query );
815     ok(r == ERROR_SUCCESS, "query failed\n");
816
817     query = "INSERT INTO `_Validation` ( `Table`, `Column`, `Nullable` ) "
818             "VALUES('phone', 'id', 'N')";
819     r = run_query( hdb, 0, query );
820     ok(r == ERROR_SUCCESS, "query failed\n");
821
822     /* check what the error function reports without doing anything */
823     sz = 0;
824     /* passing NULL as the 3rd param make function to crash on older platforms */
825     err = MsiViewGetError( 0, NULL, &sz );
826     ok(err == MSIDBERROR_INVALIDARG, "MsiViewGetError return\n");
827
828     /* open a view */
829     query = "SELECT * FROM `phone`";
830     r = MsiDatabaseOpenView(hdb, query, &hview);
831     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
832
833     /* see what happens with a good hview and bad args */
834     err = MsiViewGetError( hview, NULL, NULL );
835     ok(err == MSIDBERROR_INVALIDARG || err == MSIDBERROR_NOERROR,
836        "MsiViewGetError returns %u (expected -3)\n", err);
837     err = MsiViewGetError( hview, buffer, NULL );
838     ok(err == MSIDBERROR_INVALIDARG, "MsiViewGetError return\n");
839
840     /* see what happens with a zero length buffer */
841     sz = 0;
842     buffer[0] = 'x';
843     err = MsiViewGetError( hview, buffer, &sz );
844     ok(err == MSIDBERROR_MOREDATA, "MsiViewGetError return\n");
845     ok(buffer[0] == 'x', "buffer cleared\n");
846     ok(sz == 0, "size not zero\n");
847
848     /* ok this one is strange */
849     sz = 0;
850     err = MsiViewGetError( hview, NULL, &sz );
851     ok(err == MSIDBERROR_NOERROR, "MsiViewGetError return\n");
852     ok(sz == 0, "size not zero\n");
853
854     /* see if it really has an error */
855     sz = sizeof buffer;
856     buffer[0] = 'x';
857     err = MsiViewGetError( hview, buffer, &sz );
858     ok(err == MSIDBERROR_NOERROR, "MsiViewGetError return\n");
859     ok(buffer[0] == 0, "buffer not cleared\n");
860     ok(sz == 0, "size not zero\n");
861
862     r = MsiViewExecute(hview, 0);
863     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
864
865     /* try some invalid records */
866     r = MsiViewModify(hview, MSIMODIFY_INSERT, 0 );
867     ok(r == ERROR_INVALID_HANDLE, "MsiViewModify failed\n");
868     r = MsiViewModify(hview, -1, 0 );
869     ok(r == ERROR_INVALID_HANDLE, "MsiViewModify failed\n");
870
871     /* try an small record */
872     hrec = MsiCreateRecord(1);
873     r = MsiViewModify(hview, -1, hrec );
874     ok(r == ERROR_INVALID_DATA, "MsiViewModify failed\n");
875
876     sz = sizeof buffer;
877     buffer[0] = 'x';
878     err = MsiViewGetError( hview, buffer, &sz );
879     ok(err == MSIDBERROR_NOERROR, "MsiViewGetError return\n");
880     ok(buffer[0] == 0, "buffer not cleared\n");
881     ok(sz == 0, "size not zero\n");
882
883     r = MsiCloseHandle(hrec);
884     ok(r == ERROR_SUCCESS, "failed to close record\n");
885
886     /* insert a valid record */
887     hrec = MsiCreateRecord(3);
888
889     r = MsiRecordSetInteger(hrec, 1, 1);
890     ok(r == ERROR_SUCCESS, "failed to set integer\n");
891     r = MsiRecordSetString(hrec, 2, "bob");
892     ok(r == ERROR_SUCCESS, "failed to set string\n");
893     r = MsiRecordSetString(hrec, 3, "7654321");
894     ok(r == ERROR_SUCCESS, "failed to set string\n");
895
896     r = MsiViewExecute(hview, 0);
897     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
898     r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec );
899     ok(r == ERROR_SUCCESS, "MsiViewModify failed\n");
900
901     /* validate it */
902     r = MsiViewExecute(hview, 0);
903     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
904
905     r = MsiViewModify(hview, MSIMODIFY_VALIDATE_NEW, hrec );
906     ok(r == ERROR_INVALID_DATA, "MsiViewModify failed %u\n", r);
907
908     sz = sizeof buffer;
909     buffer[0] = 'x';
910     err = MsiViewGetError( hview, buffer, &sz );
911     ok(err == MSIDBERROR_DUPLICATEKEY, "MsiViewGetError returned %u\n", err);
912     ok(!strcmp(buffer, "id"), "expected \"id\" c, got \"%s\"\n", buffer);
913     ok(sz == 2, "size not 2\n");
914
915     /* insert the same thing again */
916     r = MsiViewExecute(hview, 0);
917     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
918
919     /* should fail ... */
920     r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec );
921     ok(r == ERROR_FUNCTION_FAILED, "MsiViewModify failed\n");
922
923     /* try to merge the same record */
924     r = MsiViewExecute(hview, 0);
925     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
926     r = MsiViewModify(hview, MSIMODIFY_MERGE, hrec );
927     ok(r == ERROR_SUCCESS, "MsiViewModify failed\n");
928
929     r = MsiCloseHandle(hrec);
930     ok(r == ERROR_SUCCESS, "failed to close record\n");
931
932     /* try merging a new record */
933     hrec = MsiCreateRecord(3);
934
935     r = MsiRecordSetInteger(hrec, 1, 10);
936     ok(r == ERROR_SUCCESS, "failed to set integer\n");
937     r = MsiRecordSetString(hrec, 2, "pepe");
938     ok(r == ERROR_SUCCESS, "failed to set string\n");
939     r = MsiRecordSetString(hrec, 3, "7654321");
940     ok(r == ERROR_SUCCESS, "failed to set string\n");
941
942     r = MsiViewModify(hview, MSIMODIFY_MERGE, hrec );
943     ok(r == ERROR_SUCCESS, "MsiViewModify failed\n");
944     r = MsiViewExecute(hview, 0);
945     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
946
947     r = MsiCloseHandle(hrec);
948     ok(r == ERROR_SUCCESS, "failed to close record\n");
949
950     r = MsiViewClose(hview);
951     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
952     r = MsiCloseHandle(hview);
953     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
954
955     query = "SELECT * FROM `phone`";
956     r = MsiDatabaseOpenView(hdb, query, &hview);
957     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
958
959     r = MsiViewExecute(hview, 0);
960     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
961
962     r = MsiViewFetch(hview, &hrec);
963     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
964
965     r = MsiRecordGetInteger(hrec, 1);
966     ok(r == 1, "Expected 1, got %d\n", r);
967
968     sz = sizeof(buffer);
969     r = MsiRecordGetString(hrec, 2, buffer, &sz);
970     ok(r == ERROR_SUCCESS, "MsiRecordGetString failed\n");
971     ok(!lstrcmp(buffer, "bob"), "Expected bob, got %s\n", buffer);
972
973     sz = sizeof(buffer);
974     r = MsiRecordGetString(hrec, 3, buffer, &sz);
975     ok(r == ERROR_SUCCESS, "MsiRecordGetString failed\n");
976     ok(!lstrcmp(buffer, "7654321"), "Expected 7654321, got %s\n", buffer);
977
978     /* update the view, non-primary key */
979     r = MsiRecordSetString(hrec, 3, "3141592");
980     ok(r == ERROR_SUCCESS, "MsiRecordSetString failed\n");
981
982     r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
983     ok(r == ERROR_SUCCESS, "MsiViewModify failed\n");
984
985     /* do it again */
986     r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
987     ok(r == ERROR_SUCCESS, "MsiViewModify failed: %d\n", r);
988
989     /* update the view, primary key */
990     r = MsiRecordSetInteger(hrec, 1, 5);
991     ok(r == ERROR_SUCCESS, "MsiRecordSetInteger failed\n");
992
993     r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
994     ok(r == ERROR_FUNCTION_FAILED, "MsiViewModify failed\n");
995
996     r = MsiCloseHandle(hrec);
997     ok(r == ERROR_SUCCESS, "failed to close record\n");
998
999     r = MsiViewClose(hview);
1000     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
1001     r = MsiCloseHandle(hview);
1002     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
1003
1004     query = "SELECT * FROM `phone`";
1005     r = MsiDatabaseOpenView(hdb, query, &hview);
1006     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
1007
1008     r = MsiViewExecute(hview, 0);
1009     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
1010
1011     r = MsiViewFetch(hview, &hrec);
1012     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
1013
1014     r = MsiRecordGetInteger(hrec, 1);
1015     ok(r == 1, "Expected 1, got %d\n", r);
1016
1017     sz = sizeof(buffer);
1018     r = MsiRecordGetString(hrec, 2, buffer, &sz);
1019     ok(r == ERROR_SUCCESS, "MsiRecordGetString failed\n");
1020     ok(!lstrcmp(buffer, "bob"), "Expected bob, got %s\n", buffer);
1021
1022     sz = sizeof(buffer);
1023     r = MsiRecordGetString(hrec, 3, buffer, &sz);
1024     ok(r == ERROR_SUCCESS, "MsiRecordGetString failed\n");
1025     ok(!lstrcmp(buffer, "3141592"), "Expected 3141592, got %s\n", buffer);
1026
1027     r = MsiCloseHandle(hrec);
1028     ok(r == ERROR_SUCCESS, "failed to close record\n");
1029
1030     /* use a record that doesn't come from a view fetch */
1031     hrec = MsiCreateRecord(3);
1032     ok(hrec != 0, "MsiCreateRecord failed\n");
1033
1034     r = MsiRecordSetInteger(hrec, 1, 3);
1035     ok(r == ERROR_SUCCESS, "failed to set integer\n");
1036     r = MsiRecordSetString(hrec, 2, "jane");
1037     ok(r == ERROR_SUCCESS, "failed to set string\n");
1038     r = MsiRecordSetString(hrec, 3, "112358");
1039     ok(r == ERROR_SUCCESS, "failed to set string\n");
1040
1041     r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
1042     ok(r == ERROR_FUNCTION_FAILED, "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
1043
1044     r = MsiCloseHandle(hrec);
1045     ok(r == ERROR_SUCCESS, "failed to close record\n");
1046
1047     /* use a record that doesn't come from a view fetch, primary key matches */
1048     hrec = MsiCreateRecord(3);
1049     ok(hrec != 0, "MsiCreateRecord failed\n");
1050
1051     r = MsiRecordSetInteger(hrec, 1, 1);
1052     ok(r == ERROR_SUCCESS, "failed to set integer\n");
1053     r = MsiRecordSetString(hrec, 2, "jane");
1054     ok(r == ERROR_SUCCESS, "failed to set string\n");
1055     r = MsiRecordSetString(hrec, 3, "112358");
1056     ok(r == ERROR_SUCCESS, "failed to set string\n");
1057
1058     r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
1059     ok(r == ERROR_FUNCTION_FAILED, "MsiViewModify failed\n");
1060
1061     r = MsiCloseHandle(hrec);
1062     ok(r == ERROR_SUCCESS, "failed to close record\n");
1063
1064     hrec = MsiCreateRecord(3);
1065
1066     r = MsiRecordSetInteger(hrec, 1, 2);
1067     ok(r == ERROR_SUCCESS, "failed to set integer\n");
1068     r = MsiRecordSetString(hrec, 2, "nick");
1069     ok(r == ERROR_SUCCESS, "failed to set string\n");
1070     r = MsiRecordSetString(hrec, 3, "141421");
1071     ok(r == ERROR_SUCCESS, "failed to set string\n");
1072
1073     r = MsiViewExecute(hview, 0);
1074     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
1075     r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec );
1076     ok(r == ERROR_SUCCESS, "MsiViewModify failed\n");
1077
1078     r = MsiCloseHandle(hrec);
1079     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
1080     r = MsiViewClose(hview);
1081     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
1082     r = MsiCloseHandle(hview);
1083     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
1084
1085     query = "SELECT * FROM `phone` WHERE `id` = 1";
1086     r = MsiDatabaseOpenView(hdb, query, &hview);
1087     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
1088     r = MsiViewExecute(hview, 0);
1089     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
1090     r = MsiViewFetch(hview, &hrec);
1091     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
1092
1093     /* change the id to match the second row */
1094     r = MsiRecordSetInteger(hrec, 1, 2);
1095     ok(r == ERROR_SUCCESS, "failed to set integer\n");
1096     r = MsiRecordSetString(hrec, 2, "jerry");
1097     ok(r == ERROR_SUCCESS, "failed to set string\n");
1098
1099     r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
1100     ok(r == ERROR_FUNCTION_FAILED, "MsiViewModify failed\n");
1101
1102     r = MsiCloseHandle(hrec);
1103     ok(r == ERROR_SUCCESS, "failed to close record\n");
1104     r = MsiViewClose(hview);
1105     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
1106     r = MsiCloseHandle(hview);
1107     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
1108
1109     /* broader search */
1110     query = "SELECT * FROM `phone` ORDER BY `id`";
1111     r = MsiDatabaseOpenView(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 = MsiRecordSetString(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     r = MsiCloseHandle( hdb );
1135     ok(r == ERROR_SUCCESS, "MsiOpenDatabase close failed\n");
1136 }
1137
1138 static MSIHANDLE create_db(void)
1139 {
1140     MSIHANDLE hdb = 0;
1141     UINT res;
1142
1143     DeleteFile(msifile);
1144
1145     /* create an empty database */
1146     res = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb );
1147     ok( res == ERROR_SUCCESS , "Failed to create database\n" );
1148     if( res != ERROR_SUCCESS )
1149         return hdb;
1150
1151     res = MsiDatabaseCommit( hdb );
1152     ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
1153
1154     return hdb;
1155 }
1156
1157 static void test_getcolinfo(void)
1158 {
1159     MSIHANDLE hdb, hview = 0, rec = 0;
1160     UINT r;
1161     DWORD sz;
1162     char buffer[0x20];
1163
1164     /* create an empty db */
1165     hdb = create_db();
1166     ok( hdb, "failed to create db\n");
1167
1168     /* tables should be present */
1169     r = MsiDatabaseOpenView(hdb, "select * from _Tables", &hview);
1170     ok( r == ERROR_SUCCESS, "failed to open query\n");
1171
1172     r = MsiViewExecute(hview, 0);
1173     ok( r == ERROR_SUCCESS, "failed to execute query\n");
1174
1175     /* check that NAMES works */
1176     rec = 0;
1177     r = MsiViewGetColumnInfo( hview, MSICOLINFO_NAMES, &rec );
1178     ok( r == ERROR_SUCCESS, "failed to get names\n");
1179     sz = sizeof buffer;
1180     r = MsiRecordGetString(rec, 1, buffer, &sz );
1181     ok( r == ERROR_SUCCESS, "failed to get string\n");
1182     ok( !strcmp(buffer,"Name"), "_Tables has wrong column name\n");
1183     r = MsiCloseHandle( rec );
1184     ok( r == ERROR_SUCCESS, "failed to close record handle\n");
1185
1186     /* check that TYPES works */
1187     rec = 0;
1188     r = MsiViewGetColumnInfo( hview, MSICOLINFO_TYPES, &rec );
1189     ok( r == ERROR_SUCCESS, "failed to get names\n");
1190     sz = sizeof buffer;
1191     r = MsiRecordGetString(rec, 1, buffer, &sz );
1192     ok( r == ERROR_SUCCESS, "failed to get string\n");
1193     ok( !strcmp(buffer,"s64"), "_Tables has wrong column type\n");
1194     r = MsiCloseHandle( rec );
1195     ok( r == ERROR_SUCCESS, "failed to close record handle\n");
1196
1197     /* check that invalid values fail */
1198     rec = 0;
1199     r = MsiViewGetColumnInfo( hview, 100, &rec );
1200     ok( r == ERROR_INVALID_PARAMETER, "wrong error code\n");
1201     ok( rec == 0, "returned a record\n");
1202
1203     r = MsiViewGetColumnInfo( hview, MSICOLINFO_TYPES, NULL );
1204     ok( r == ERROR_INVALID_PARAMETER, "wrong error code\n");
1205
1206     r = MsiViewGetColumnInfo( 0, MSICOLINFO_TYPES, &rec );
1207     ok( r == ERROR_INVALID_HANDLE, "wrong error code\n");
1208
1209     r = MsiViewClose(hview);
1210     ok( r == ERROR_SUCCESS, "failed to close view\n");
1211     r = MsiCloseHandle(hview);
1212     ok( r == ERROR_SUCCESS, "failed to close view handle\n");
1213     r = MsiCloseHandle(hdb);
1214     ok( r == ERROR_SUCCESS, "failed to close database\n");
1215 }
1216
1217 static MSIHANDLE get_column_info(MSIHANDLE hdb, const char *query, MSICOLINFO type)
1218 {
1219     MSIHANDLE hview = 0, rec = 0;
1220     UINT r;
1221
1222     r = MsiDatabaseOpenView(hdb, query, &hview);
1223     if( r != ERROR_SUCCESS )
1224         return r;
1225
1226     r = MsiViewExecute(hview, 0);
1227     if( r == ERROR_SUCCESS )
1228     {
1229         MsiViewGetColumnInfo( hview, type, &rec );
1230     }
1231     MsiViewClose(hview);
1232     MsiCloseHandle(hview);
1233     return rec;
1234 }
1235
1236 static UINT get_columns_table_type(MSIHANDLE hdb, const char *table, UINT field)
1237 {
1238     MSIHANDLE hview = 0, rec = 0;
1239     UINT r, type = 0;
1240     char query[0x100];
1241
1242     sprintf(query, "select * from `_Columns` where  `Table` = '%s'", table );
1243
1244     r = MsiDatabaseOpenView(hdb, query, &hview);
1245     if( r != ERROR_SUCCESS )
1246         return r;
1247
1248     r = MsiViewExecute(hview, 0);
1249     if( r == ERROR_SUCCESS )
1250     {
1251         while (1)
1252         {
1253             r = MsiViewFetch( hview, &rec );
1254             if( r != ERROR_SUCCESS)
1255                 break;
1256             r = MsiRecordGetInteger( rec, 2 );
1257             if (r == field)
1258                 type = MsiRecordGetInteger( rec, 4 );
1259             MsiCloseHandle( rec );
1260         }
1261     }
1262     MsiViewClose(hview);
1263     MsiCloseHandle(hview);
1264     return type;
1265 }
1266
1267 static BOOL check_record( MSIHANDLE rec, UINT field, LPCSTR val )
1268 {
1269     CHAR buffer[0x20];
1270     UINT r;
1271     DWORD sz;
1272
1273     sz = sizeof buffer;
1274     r = MsiRecordGetString( rec, field, buffer, &sz );
1275     return (r == ERROR_SUCCESS ) && !strcmp(val, buffer);
1276 }
1277
1278 static void test_viewgetcolumninfo(void)
1279 {
1280     MSIHANDLE hdb = 0, rec;
1281     UINT r;
1282
1283     hdb = create_db();
1284     ok( hdb, "failed to create db\n");
1285
1286     r = run_query( hdb, 0,
1287             "CREATE TABLE `Properties` "
1288             "( `Property` CHAR(255), "
1289             "  `Value` CHAR(1), "
1290             "  `Intvalue` INT, "
1291             "  `Integervalue` INTEGER, "
1292             "  `Shortvalue` SHORT, "
1293             "  `Longvalue` LONG, "
1294             "  `Longcharvalue` LONGCHAR "
1295             "  PRIMARY KEY `Property`)" );
1296     ok( r == ERROR_SUCCESS , "Failed to create table\n" );
1297
1298     /* check the column types */
1299     rec = get_column_info( hdb, "select * from `Properties`", MSICOLINFO_TYPES );
1300     ok( rec, "failed to get column info record\n" );
1301
1302     ok( check_record( rec, 1, "S255"), "wrong record type\n");
1303     ok( check_record( rec, 2, "S1"), "wrong record type\n");
1304     ok( check_record( rec, 3, "I2"), "wrong record type\n");
1305     ok( check_record( rec, 4, "I2"), "wrong record type\n");
1306     ok( check_record( rec, 5, "I2"), "wrong record type\n");
1307     ok( check_record( rec, 6, "I4"), "wrong record type\n");
1308     ok( check_record( rec, 7, "S0"), "wrong record type\n");
1309
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
1321     /* now try the names */
1322     rec = get_column_info( hdb, "select * from `Properties`", MSICOLINFO_NAMES );
1323     ok( rec, "failed to get column info record\n" );
1324
1325     ok( check_record( rec, 1, "Property"), "wrong record type\n");
1326     ok( check_record( rec, 2, "Value"), "wrong record type\n");
1327     ok( check_record( rec, 3, "Intvalue"), "wrong record type\n");
1328     ok( check_record( rec, 4, "Integervalue"), "wrong record type\n");
1329     ok( check_record( rec, 5, "Shortvalue"), "wrong record type\n");
1330     ok( check_record( rec, 6, "Longvalue"), "wrong record type\n");
1331     ok( check_record( rec, 7, "Longcharvalue"), "wrong record type\n");
1332
1333     MsiCloseHandle( rec );
1334
1335     r = run_query( hdb, 0,
1336             "CREATE TABLE `Binary` "
1337             "( `Name` CHAR(255), `Data` OBJECT  PRIMARY KEY `Name`)" );
1338     ok( r == ERROR_SUCCESS , "Failed to create table\n" );
1339
1340     /* check the column types */
1341     rec = get_column_info( hdb, "select * from `Binary`", MSICOLINFO_TYPES );
1342     ok( rec, "failed to get column info record\n" );
1343
1344     ok( check_record( rec, 1, "S255"), "wrong record type\n");
1345     ok( check_record( rec, 2, "V0"), "wrong record type\n");
1346
1347     MsiCloseHandle( rec );
1348
1349     /* check the type in _Columns */
1350     ok( 0x3dff == get_columns_table_type(hdb, "Binary", 1 ), "_columns table wrong\n");
1351     ok( 0x1900 == get_columns_table_type(hdb, "Binary", 2 ), "_columns table wrong\n");
1352
1353     /* now try the names */
1354     rec = get_column_info( hdb, "select * from `Binary`", MSICOLINFO_NAMES );
1355     ok( rec, "failed to get column info record\n" );
1356
1357     ok( check_record( rec, 1, "Name"), "wrong record type\n");
1358     ok( check_record( rec, 2, "Data"), "wrong record type\n");
1359     MsiCloseHandle( rec );
1360
1361     r = run_query( hdb, 0,
1362             "CREATE TABLE `UIText` "
1363             "( `Key` CHAR(72) NOT NULL, `Text` CHAR(255) LOCALIZABLE PRIMARY KEY `Key`)" );
1364     ok( r == ERROR_SUCCESS , "Failed to create table\n" );
1365
1366     ok( 0x2d48 == get_columns_table_type(hdb, "UIText", 1 ), "_columns table wrong\n");
1367     ok( 0x1fff == get_columns_table_type(hdb, "UIText", 2 ), "_columns table wrong\n");
1368
1369     rec = get_column_info( hdb, "select * from `UIText`", MSICOLINFO_NAMES );
1370     ok( rec, "failed to get column info record\n" );
1371     ok( check_record( rec, 1, "Key"), "wrong record type\n");
1372     ok( check_record( rec, 2, "Text"), "wrong record type\n");
1373     MsiCloseHandle( rec );
1374
1375     rec = get_column_info( hdb, "select * from `UIText`", MSICOLINFO_TYPES );
1376     ok( rec, "failed to get column info record\n" );
1377     ok( check_record( rec, 1, "s72"), "wrong record type\n");
1378     ok( check_record( rec, 2, "L255"), "wrong record type\n");
1379     MsiCloseHandle( rec );
1380
1381     MsiCloseHandle( hdb );
1382 }
1383
1384 static void test_msiexport(void)
1385 {
1386     MSIHANDLE hdb = 0, hview = 0;
1387     UINT r;
1388     const char *query;
1389     char path[MAX_PATH];
1390     const char file[] = "phone.txt";
1391     HANDLE handle;
1392     char buffer[0x100];
1393     DWORD length;
1394     const char expected[] =
1395         "id\tname\tnumber\r\n"
1396         "I2\tS32\tS32\r\n"
1397         "phone\tid\r\n"
1398         "1\tAbe\t8675309\r\n";
1399
1400     DeleteFile(msifile);
1401
1402     /* just MsiOpenDatabase should not create a file */
1403     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
1404     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
1405
1406     /* create a table */
1407     query = "CREATE TABLE `phone` ( "
1408             "`id` INT, `name` CHAR(32), `number` CHAR(32) "
1409             "PRIMARY KEY `id`)";
1410     r = MsiDatabaseOpenView(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
1419     /* insert a value into it */
1420     query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
1421         "VALUES('1', 'Abe', '8675309')";
1422     r = MsiDatabaseOpenView(hdb, query, &hview);
1423     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
1424     r = MsiViewExecute(hview, 0);
1425     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
1426     r = MsiViewClose(hview);
1427     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
1428     r = MsiCloseHandle(hview);
1429     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
1430
1431     GetCurrentDirectory(MAX_PATH, path);
1432
1433     r = MsiDatabaseExport(hdb, "phone", path, file);
1434     ok(r == ERROR_SUCCESS, "MsiDatabaseExport failed\n");
1435
1436     MsiCloseHandle(hdb);
1437
1438     lstrcat(path, "\\");
1439     lstrcat(path, file);
1440
1441     /* check the data that was written */
1442     length = 0;
1443     memset(buffer, 0, sizeof buffer);
1444     handle = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
1445     if (handle != INVALID_HANDLE_VALUE)
1446     {
1447         ReadFile(handle, buffer, sizeof buffer, &length, NULL);
1448         CloseHandle(handle);
1449         DeleteFile(path);
1450     }
1451     else
1452         ok(0, "failed to open file %s\n", path);
1453
1454     ok( length == strlen(expected), "length of data wrong\n");
1455     ok( !lstrcmp(buffer, expected), "data doesn't match\n");
1456     DeleteFile(msifile);
1457 }
1458
1459 static void test_longstrings(void)
1460 {
1461     const char insert_query[] = 
1462         "INSERT INTO `strings` ( `id`, `val` ) VALUES('1', 'Z')";
1463     char *str;
1464     MSIHANDLE hdb = 0, hview = 0, hrec = 0;
1465     DWORD len;
1466     UINT r;
1467     const DWORD STRING_LENGTH = 0x10005;
1468
1469     DeleteFile(msifile);
1470     /* just MsiOpenDatabase should not create a file */
1471     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
1472     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
1473
1474     /* create a table */
1475     r = try_query( hdb, 
1476         "CREATE TABLE `strings` ( `id` INT, `val` CHAR(0) PRIMARY KEY `id`)");
1477     ok(r == ERROR_SUCCESS, "query failed\n");
1478
1479     /* try a insert a very long string */
1480     str = HeapAlloc(GetProcessHeap(), 0, STRING_LENGTH+sizeof insert_query);
1481     len = strchr(insert_query, 'Z') - insert_query;
1482     strcpy(str, insert_query);
1483     memset(str+len, 'Z', STRING_LENGTH);
1484     strcpy(str+len+STRING_LENGTH, insert_query+len+1);
1485     r = try_query( hdb, str );
1486     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
1487
1488     HeapFree(GetProcessHeap(), 0, str);
1489
1490     r = MsiDatabaseCommit(hdb);
1491     ok(r == ERROR_SUCCESS, "MsiDatabaseCommit failed\n");
1492     MsiCloseHandle(hdb);
1493
1494     r = MsiOpenDatabase(msifile, MSIDBOPEN_READONLY, &hdb);
1495     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
1496
1497     r = MsiDatabaseOpenView(hdb, "select * from `strings` where `id` = 1", &hview);
1498     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
1499
1500     r = MsiViewExecute(hview, 0);
1501     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
1502
1503     r = MsiViewFetch(hview, &hrec);
1504     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
1505
1506     MsiViewClose(hview);
1507     MsiCloseHandle(hview);
1508
1509     r = MsiRecordGetString(hrec, 2, NULL, &len);
1510     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
1511     ok(len == STRING_LENGTH, "string length wrong\n");
1512
1513     MsiCloseHandle(hrec);
1514     MsiCloseHandle(hdb);
1515     DeleteFile(msifile);
1516 }
1517
1518 static void create_file_data(LPCSTR name, LPCSTR data, DWORD size)
1519 {
1520     HANDLE file;
1521     DWORD written;
1522
1523     file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
1524     if (file == INVALID_HANDLE_VALUE)
1525         return;
1526
1527     WriteFile(file, data, strlen(data), &written, NULL);
1528     WriteFile(file, "\n", strlen("\n"), &written, NULL);
1529
1530     if (size)
1531     {
1532         SetFilePointer(file, size, NULL, FILE_BEGIN);
1533         SetEndOfFile(file);
1534     }
1535
1536     CloseHandle(file);
1537 }
1538
1539 #define create_file(name) create_file_data(name, name, 0)
1540  
1541 static void test_streamtable(void)
1542 {
1543     MSIHANDLE hdb = 0, rec, view, hsi;
1544     char file[MAX_PATH];
1545     char buf[MAX_PATH];
1546     DWORD size;
1547     UINT r;
1548
1549     hdb = create_db();
1550     ok( hdb, "failed to create db\n");
1551
1552     r = run_query( hdb, 0,
1553             "CREATE TABLE `Properties` "
1554             "( `Property` CHAR(255), `Value` CHAR(1)  PRIMARY KEY `Property`)" );
1555     ok( r == ERROR_SUCCESS , "Failed to create table\n" );
1556
1557     r = run_query( hdb, 0,
1558             "INSERT INTO `Properties` "
1559             "( `Value`, `Property` ) VALUES ( 'Prop', 'value' )" );
1560     ok( r == ERROR_SUCCESS, "Failed to add to table\n" );
1561
1562     r = MsiDatabaseCommit( hdb );
1563     ok( r == ERROR_SUCCESS , "Failed to commit database\n" );
1564
1565     MsiCloseHandle( hdb );
1566
1567     r = MsiOpenDatabase(msifile, MSIDBOPEN_TRANSACT, &hdb );
1568     ok( r == ERROR_SUCCESS , "Failed to open database\n" );
1569
1570     /* check the column types */
1571     rec = get_column_info( hdb, "select * from `_Streams`", MSICOLINFO_TYPES );
1572     ok( rec, "failed to get column info record\n" );
1573
1574     ok( check_record( rec, 1, "s62"), "wrong record type\n");
1575     ok( check_record( rec, 2, "V0"), "wrong record type\n");
1576
1577     MsiCloseHandle( rec );
1578
1579     /* now try the names */
1580     rec = get_column_info( hdb, "select * from `_Streams`", MSICOLINFO_NAMES );
1581     ok( rec, "failed to get column info record\n" );
1582
1583     ok( check_record( rec, 1, "Name"), "wrong record type\n");
1584     ok( check_record( rec, 2, "Data"), "wrong record type\n");
1585
1586     MsiCloseHandle( rec );
1587
1588     r = MsiDatabaseOpenView( hdb,
1589             "SELECT * FROM `_Streams` WHERE `Name` = '\5SummaryInformation'", &view );
1590     ok( r == ERROR_SUCCESS, "Failed to open database view: %u\n", r );
1591
1592     r = MsiViewExecute( view, 0 );
1593     ok( r == ERROR_SUCCESS, "Failed to execute view: %u\n", r );
1594
1595     r = MsiViewFetch( view, &rec );
1596     ok( r == ERROR_NO_MORE_ITEMS, "Unexpected result: %u\n", r );
1597
1598     MsiCloseHandle( rec );
1599     MsiViewClose( view );
1600     MsiCloseHandle( view );
1601
1602     /* create a summary information stream */
1603     r = MsiGetSummaryInformationA( hdb, NULL, 1, &hsi );
1604     ok( r == ERROR_SUCCESS, "Failed to get summary information handle: %u\n", r );
1605
1606     r = MsiSummaryInfoSetPropertyA( hsi, PID_SECURITY, VT_I4, 2, NULL, NULL );
1607     ok( r == ERROR_SUCCESS, "Failed to set property: %u\n", r );
1608
1609     r = MsiSummaryInfoPersist( hsi );
1610     ok( r == ERROR_SUCCESS, "Failed to save summary information: %u\n", r );
1611
1612     MsiCloseHandle( hsi );
1613
1614     r = MsiDatabaseOpenView( hdb,
1615             "SELECT * FROM `_Streams` WHERE `Name` = '\5SummaryInformation'", &view );
1616     ok( r == ERROR_SUCCESS, "Failed to open database view: %u\n", r );
1617
1618     r = MsiViewExecute( view, 0 );
1619     ok( r == ERROR_SUCCESS, "Failed to execute view: %u\n", r );
1620
1621     r = MsiViewFetch( view, &rec );
1622     ok( r == ERROR_SUCCESS, "Unexpected result: %u\n", r );
1623
1624     MsiCloseHandle( rec );
1625     MsiViewClose( view );
1626     MsiCloseHandle( view );
1627
1628     /* insert a file into the _Streams table */
1629     create_file( "test.txt" );
1630
1631     rec = MsiCreateRecord( 2 );
1632     MsiRecordSetString( rec, 1, "data" );
1633
1634     r = MsiRecordSetStream( rec, 2, "test.txt" );
1635     ok( r == ERROR_SUCCESS, "Failed to add stream data to the record: %d\n", r);
1636
1637     DeleteFile("test.txt");
1638
1639     r = MsiDatabaseOpenView( hdb,
1640             "INSERT INTO `_Streams` ( `Name`, `Data` ) VALUES ( ?, ? )", &view );
1641     ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r);
1642
1643     r = MsiViewExecute( view, rec );
1644     ok( r == ERROR_SUCCESS, "Failed to execute view: %d\n", r);
1645
1646     MsiCloseHandle( rec );
1647     MsiViewClose( view );
1648     MsiCloseHandle( view );
1649
1650     /* insert another one */
1651     create_file( "test1.txt" );
1652
1653     rec = MsiCreateRecord( 2 );
1654     MsiRecordSetString( rec, 1, "data1" );
1655
1656     r = MsiRecordSetStream( rec, 2, "test1.txt" );
1657     ok( r == ERROR_SUCCESS, "Failed to add stream data to the record: %d\n", r);
1658
1659     DeleteFile("test1.txt");
1660
1661     r = MsiDatabaseOpenView( hdb,
1662             "INSERT INTO `_Streams` ( `Name`, `Data` ) VALUES ( ?, ? )", &view );
1663     ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r);
1664
1665     r = MsiViewExecute( view, rec );
1666     ok( r == ERROR_SUCCESS, "Failed to execute view: %d\n", r);
1667
1668     MsiCloseHandle( rec );
1669     MsiViewClose( view );
1670     MsiCloseHandle( view );
1671
1672     r = MsiDatabaseOpenView( hdb,
1673             "SELECT `Name`, `Data` FROM `_Streams` WHERE `Name` = 'data'", &view );
1674     ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r);
1675
1676     r = MsiViewExecute( view, 0 );
1677     ok( r == ERROR_SUCCESS, "Failed to execute view: %d\n", r);
1678
1679     r = MsiViewFetch( view, &rec );
1680     ok( r == ERROR_SUCCESS, "Failed to fetch record: %d\n", r);
1681
1682     size = MAX_PATH;
1683     r = MsiRecordGetString( rec, 1, file, &size );
1684     ok( r == ERROR_SUCCESS, "Failed to get string: %d\n", r);
1685     ok( !lstrcmp(file, "data"), "Expected 'data', got %s\n", file);
1686
1687     size = MAX_PATH;
1688     memset(buf, 0, MAX_PATH);
1689     r = MsiRecordReadStream( rec, 2, buf, &size );
1690     ok( r == ERROR_SUCCESS, "Failed to get stream: %d\n", r);
1691     ok( !lstrcmp(buf, "test.txt\n"), "Expected 'test.txt\\n', got %s\n", buf);
1692
1693     MsiCloseHandle( rec );
1694     MsiViewClose( view );
1695     MsiCloseHandle( view );
1696
1697     r = MsiDatabaseOpenView( hdb,
1698             "SELECT `Name`, `Data` FROM `_Streams` WHERE `Name` = 'data1'", &view );
1699     ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r);
1700
1701     r = MsiViewExecute( view, 0 );
1702     ok( r == ERROR_SUCCESS, "Failed to execute view: %d\n", r);
1703
1704     r = MsiViewFetch( view, &rec );
1705     ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1706
1707     size = MAX_PATH;
1708     r = MsiRecordGetString( rec, 1, file, &size );
1709     ok( r == ERROR_SUCCESS, "Failed to get string: %d\n", r);
1710     ok( !lstrcmp(file, "data1"), "Expected 'data1', got %s\n", file);
1711
1712     size = MAX_PATH;
1713     memset(buf, 0, MAX_PATH);
1714     r = MsiRecordReadStream( rec, 2, buf, &size );
1715     ok( r == ERROR_SUCCESS, "Failed to get stream: %d\n", r);
1716     ok( !lstrcmp(buf, "test1.txt\n"), "Expected 'test1.txt\\n', got %s\n", buf);
1717
1718     MsiCloseHandle( rec );
1719     MsiViewClose( view );
1720     MsiCloseHandle( view );
1721
1722     /* perform an update */
1723     create_file( "test2.txt" );
1724     rec = MsiCreateRecord( 1 );
1725
1726     r = MsiRecordSetStream( rec, 1, "test2.txt" );
1727     ok( r == ERROR_SUCCESS, "Failed to add stream data to the record: %d\n", r);
1728
1729     DeleteFile("test2.txt");
1730
1731     r = MsiDatabaseOpenView( hdb,
1732             "UPDATE `_Streams` SET `Data` = ? WHERE `Name` = 'data1'", &view );
1733     ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r);
1734
1735     r = MsiViewExecute( view, rec );
1736     ok( r == ERROR_SUCCESS, "Failed to execute view: %d\n", r);
1737
1738     MsiCloseHandle( rec );
1739     MsiViewClose( view );
1740     MsiCloseHandle( view );
1741
1742     r = MsiDatabaseOpenView( hdb,
1743             "SELECT `Name`, `Data` FROM `_Streams` WHERE `Name` = 'data1'", &view );
1744     ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r);
1745
1746     r = MsiViewExecute( view, 0 );
1747     ok( r == ERROR_SUCCESS, "Failed to execute view: %d\n", r);
1748
1749     r = MsiViewFetch( view, &rec );
1750     ok( r == ERROR_SUCCESS, "Failed to fetch record: %d\n", r);
1751
1752     size = MAX_PATH;
1753     r = MsiRecordGetString( rec, 1, file, &size );
1754     ok( r == ERROR_SUCCESS, "Failed to get string: %d\n", r);
1755     ok( !lstrcmp(file, "data1"), "Expected 'data1', got %s\n", file);
1756
1757     size = MAX_PATH;
1758     memset(buf, 0, MAX_PATH);
1759     r = MsiRecordReadStream( rec, 2, buf, &size );
1760     ok( r == ERROR_SUCCESS, "Failed to get stream: %d\n", r);
1761     todo_wine ok( !lstrcmp(buf, "test2.txt\n"), "Expected 'test2.txt\\n', got %s\n", buf);
1762
1763     MsiCloseHandle( rec );
1764     MsiViewClose( view );
1765     MsiCloseHandle( view );
1766     MsiCloseHandle( hdb );
1767     DeleteFile(msifile);
1768 }
1769
1770 static void test_binary(void)
1771 {
1772     MSIHANDLE hdb = 0, rec;
1773     char file[MAX_PATH];
1774     char buf[MAX_PATH];
1775     DWORD size;
1776     LPCSTR query;
1777     UINT r;
1778
1779     /* insert a file into the Binary table */
1780     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb );
1781     ok( r == ERROR_SUCCESS , "Failed to open database\n" );
1782
1783     query = "CREATE TABLE `Binary` ( `Name` CHAR(72) NOT NULL, `ID` INT NOT NULL, `Data` OBJECT  PRIMARY KEY `Name`, `ID`)";
1784     r = run_query( hdb, 0, query );
1785     ok( r == ERROR_SUCCESS, "Cannot create Binary table: %d\n", r );
1786
1787     create_file( "test.txt" );
1788     rec = MsiCreateRecord( 1 );
1789     r = MsiRecordSetStream( rec, 1, "test.txt" );
1790     ok( r == ERROR_SUCCESS, "Failed to add stream data to the record: %d\n", r);
1791     DeleteFile( "test.txt" );
1792
1793     query = "INSERT INTO `Binary` ( `Name`, `ID`, `Data` ) VALUES ( 'filename1', 1, ? )";
1794     r = run_query( hdb, rec, query );
1795     ok( r == ERROR_SUCCESS, "Insert into Binary table failed: %d\n", r );
1796
1797     r = MsiCloseHandle( rec );
1798     ok( r == ERROR_SUCCESS , "Failed to close record handle\n" );
1799
1800     r = MsiDatabaseCommit( hdb );
1801     ok( r == ERROR_SUCCESS , "Failed to commit database\n" );
1802
1803     r = MsiCloseHandle( hdb );
1804     ok( r == ERROR_SUCCESS , "Failed to close database\n" );
1805
1806     /* read file from the Stream table */
1807     r = MsiOpenDatabase( msifile, MSIDBOPEN_READONLY, &hdb );
1808     ok( r == ERROR_SUCCESS , "Failed to open database\n" );
1809
1810     query = "SELECT * FROM `_Streams`";
1811     r = do_query( hdb, query, &rec );
1812     ok( r == ERROR_SUCCESS, "SELECT query failed: %d\n", r );
1813
1814     size = MAX_PATH;
1815     r = MsiRecordGetString( rec, 1, file, &size );
1816     ok( r == ERROR_SUCCESS, "Failed to get string: %d\n", r );
1817     ok( !lstrcmp(file, "Binary.filename1.1"), "Expected 'Binary.filename1.1', got %s\n", file );
1818
1819     size = MAX_PATH;
1820     memset( buf, 0, MAX_PATH );
1821     r = MsiRecordReadStream( rec, 2, buf, &size );
1822     ok( r == ERROR_SUCCESS, "Failed to get stream: %d\n", r );
1823     ok( !lstrcmp(buf, "test.txt\n"), "Expected 'test.txt\\n', got %s\n", buf );
1824
1825     r = MsiCloseHandle( rec );
1826     ok( r == ERROR_SUCCESS , "Failed to close record handle\n" );
1827
1828     /* read file from the Binary table */
1829     query = "SELECT * FROM `Binary`";
1830     r = do_query( hdb, query, &rec );
1831     ok( r == ERROR_SUCCESS, "SELECT query failed: %d\n", r );
1832
1833     size = MAX_PATH;
1834     r = MsiRecordGetString( rec, 1, file, &size );
1835     ok( r == ERROR_SUCCESS, "Failed to get string: %d\n", r );
1836     ok( !lstrcmp(file, "filename1"), "Expected 'filename1', got %s\n", file );
1837
1838     size = MAX_PATH;
1839     memset( buf, 0, MAX_PATH );
1840     r = MsiRecordReadStream( rec, 3, buf, &size );
1841     ok( r == ERROR_SUCCESS, "Failed to get stream: %d\n", r );
1842     ok( !lstrcmp(buf, "test.txt\n"), "Expected 'test.txt\\n', got %s\n", buf );
1843
1844     r = MsiCloseHandle( rec );
1845     ok( r == ERROR_SUCCESS , "Failed to close record handle\n" );
1846
1847     r = MsiCloseHandle( hdb );
1848     ok( r == ERROR_SUCCESS , "Failed to close database\n" );
1849
1850     DeleteFile( msifile );
1851 }
1852
1853 static void test_where_not_in_selected(void)
1854 {
1855     MSIHANDLE hdb = 0, rec, view;
1856     LPCSTR query;
1857     UINT r;
1858
1859     hdb = create_db();
1860     ok( hdb, "failed to create db\n");
1861
1862     r = run_query(hdb, 0,
1863             "CREATE TABLE `IESTable` ("
1864             "`Action` CHAR(64), "
1865             "`Condition` CHAR(64), "
1866             "`Sequence` LONG PRIMARY KEY `Sequence`)");
1867     ok( r == S_OK, "Cannot create IESTable table: %d\n", r);
1868
1869     r = run_query(hdb, 0,
1870             "CREATE TABLE `CATable` ("
1871             "`Action` CHAR(64), "
1872             "`Type` LONG PRIMARY KEY `Type`)");
1873     ok( r == S_OK, "Cannot create CATable table: %d\n", r);
1874
1875     r = run_query(hdb, 0, "INSERT INTO `IESTable` "
1876             "( `Action`, `Condition`, `Sequence`) "
1877             "VALUES ( 'clean', 'cond4', 4)");
1878     ok( r == S_OK, "cannot add entry to IESTable table:%d\n", r );
1879
1880     r = run_query(hdb, 0, "INSERT INTO `IESTable` "
1881             "( `Action`, `Condition`, `Sequence`) "
1882             "VALUES ( 'depends', 'cond1', 1)");
1883     ok( r == S_OK, "cannot add entry to IESTable table:%d\n", r );
1884
1885     r = run_query(hdb, 0, "INSERT INTO `IESTable` "
1886             "( `Action`, `Condition`, `Sequence`) "
1887             "VALUES ( 'build', 'cond2', 2)");
1888     ok( r == S_OK, "cannot add entry to IESTable table:%d\n", r );
1889
1890     r = run_query(hdb, 0, "INSERT INTO `IESTable` "
1891             "( `Action`, `Condition`, `Sequence`) "
1892             "VALUES ( 'build2', 'cond6', 6)");
1893     ok( r == S_OK, "cannot add entry to IESTable table:%d\n", r );
1894
1895     r = run_query(hdb, 0, "INSERT INTO `IESTable` "
1896             "( `Action`, `Condition`, `Sequence`) "
1897             "VALUES ( 'build', 'cond3', 3)");
1898     ok(r == S_OK, "cannot add entry to IESTable table:%d\n", r );
1899
1900     r = run_query(hdb, 0, "INSERT INTO `CATable` "
1901             "( `Action`, `Type` ) "
1902             "VALUES ( 'build', 32)");
1903     ok(r == S_OK, "cannot add entry to CATable table:%d\n", r );
1904
1905     r = run_query(hdb, 0, "INSERT INTO `CATable` "
1906             "( `Action`, `Type` ) "
1907             "VALUES ( 'depends', 64)");
1908     ok(r == S_OK, "cannot add entry to CATable table:%d\n", r );
1909
1910     r = run_query(hdb, 0, "INSERT INTO `CATable` "
1911             "( `Action`, `Type` ) "
1912             "VALUES ( 'clean', 63)");
1913     ok(r == S_OK, "cannot add entry to CATable table:%d\n", r );
1914
1915     r = run_query(hdb, 0, "INSERT INTO `CATable` "
1916             "( `Action`, `Type` ) "
1917             "VALUES ( 'build2', 34)");
1918     ok(r == S_OK, "cannot add entry to CATable table:%d\n", r );
1919     query = "Select IESTable.Condition from CATable, IESTable where "
1920             "CATable.Action = IESTable.Action and CATable.Type = 32";
1921     r = MsiDatabaseOpenView(hdb, query, &view);
1922     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
1923
1924     r = MsiViewExecute(view, 0);
1925     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
1926
1927     r = MsiViewFetch(view, &rec);
1928     ok( r == ERROR_SUCCESS, "failed to fetch view: %d\n", r );
1929
1930     ok( check_record( rec, 1, "cond2"), "wrong condition\n");
1931
1932     MsiCloseHandle( rec );
1933     r = MsiViewFetch(view, &rec);
1934     ok( r == ERROR_SUCCESS, "failed to fetch view: %d\n", r );
1935
1936     ok( check_record( rec, 1, "cond3"), "wrong condition\n");
1937
1938     MsiCloseHandle( rec );
1939     MsiViewClose(view);
1940     MsiCloseHandle(view);
1941
1942     MsiCloseHandle( hdb );
1943     DeleteFile(msifile);
1944
1945 }
1946
1947
1948 static void test_where(void)
1949 {
1950     MSIHANDLE hdb = 0, rec, view;
1951     LPCSTR query;
1952     UINT r;
1953     DWORD size;
1954     CHAR buf[MAX_PATH];
1955     UINT count;
1956
1957     hdb = create_db();
1958     ok( hdb, "failed to create db\n");
1959
1960     r = run_query( hdb, 0,
1961             "CREATE TABLE `Media` ("
1962             "`DiskId` SHORT NOT NULL, "
1963             "`LastSequence` LONG, "
1964             "`DiskPrompt` CHAR(64) LOCALIZABLE, "
1965             "`Cabinet` CHAR(255), "
1966             "`VolumeLabel` CHAR(32), "
1967             "`Source` CHAR(72) "
1968             "PRIMARY KEY `DiskId`)" );
1969     ok( r == S_OK, "cannot create Media table: %d\n", r );
1970
1971     r = run_query( hdb, 0, "INSERT INTO `Media` "
1972             "( `DiskId`, `LastSequence`, `DiskPrompt`, `Cabinet`, `VolumeLabel`, `Source` ) "
1973             "VALUES ( 1, 0, '', 'zero.cab', '', '' )" );
1974     ok( r == S_OK, "cannot add file to the Media table: %d\n", r );
1975
1976     r = run_query( hdb, 0, "INSERT INTO `Media` "
1977             "( `DiskId`, `LastSequence`, `DiskPrompt`, `Cabinet`, `VolumeLabel`, `Source` ) "
1978             "VALUES ( 2, 1, '', 'one.cab', '', '' )" );
1979     ok( r == S_OK, "cannot add file to the Media table: %d\n", r );
1980
1981     r = run_query( hdb, 0, "INSERT INTO `Media` "
1982             "( `DiskId`, `LastSequence`, `DiskPrompt`, `Cabinet`, `VolumeLabel`, `Source` ) "
1983             "VALUES ( 3, 2, '', 'two.cab', '', '' )" );
1984     ok( r == S_OK, "cannot add file to the Media table: %d\n", r );
1985
1986     query = "SELECT * FROM `Media`";
1987     r = do_query(hdb, query, &rec);
1988     ok(r == ERROR_SUCCESS, "MsiViewFetch failed: %d\n", r);
1989     ok( check_record( rec, 4, "zero.cab"), "wrong cabinet\n");
1990     MsiCloseHandle( rec );
1991
1992     query = "SELECT * FROM `Media` WHERE `LastSequence` >= 1";
1993     r = do_query(hdb, query, &rec);
1994     ok(r == ERROR_SUCCESS, "MsiViewFetch failed: %d\n", r);
1995     ok( check_record( rec, 4, "one.cab"), "wrong cabinet\n");
1996
1997     r = MsiRecordGetInteger(rec, 1);
1998     ok( 2 == r, "field wrong\n");
1999     r = MsiRecordGetInteger(rec, 2);
2000     ok( 1 == r, "field wrong\n");
2001     MsiCloseHandle( rec );
2002
2003     query = "SELECT `DiskId` FROM `Media` WHERE `LastSequence` >= 1 AND DiskId >= 0";
2004     r = MsiDatabaseOpenView(hdb, query, &view);
2005     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
2006
2007     r = MsiViewExecute(view, 0);
2008     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
2009
2010     r = MsiViewFetch(view, &rec);
2011     ok( r == ERROR_SUCCESS, "failed to fetch view: %d\n", r );
2012
2013     count = MsiRecordGetFieldCount( rec );
2014     ok( count == 1, "Expected 1 record fields, got %d\n", count );
2015
2016     size = MAX_PATH;
2017     r = MsiRecordGetString( rec, 1, buf, &size );
2018     ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
2019     ok( !lstrcmp( buf, "2" ),
2020         "For (row %d, column 1) expected '%d', got %s\n", 0, 2, buf );
2021     MsiCloseHandle( rec );
2022
2023     r = MsiViewFetch(view, &rec);
2024     ok( r == ERROR_SUCCESS, "failed to fetch view: %d\n", r );
2025
2026     size = MAX_PATH;
2027     r = MsiRecordGetString( rec, 1, buf, &size );
2028     ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
2029     ok( !lstrcmp( buf, "3" ),
2030         "For (row %d, column 1) expected '%d', got %s\n", 1, 3, buf );
2031     MsiCloseHandle( rec );
2032
2033     r = MsiViewFetch(view, &rec);
2034     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
2035
2036     MsiViewClose(view);
2037     MsiCloseHandle(view);
2038
2039     MsiCloseHandle( rec );
2040
2041     rec = 0;
2042     query = "SELECT * FROM `Media` WHERE `DiskPrompt` IS NULL";
2043     r = do_query(hdb, query, &rec);
2044     ok( r == ERROR_SUCCESS, "query failed: %d\n", r );
2045     MsiCloseHandle( rec );
2046
2047     rec = 0;
2048     query = "SELECT * FROM `Media` WHERE `DiskPrompt` < 'Cabinet'";
2049     r = do_query(hdb, query, &rec);
2050     ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %d\n", r );
2051     MsiCloseHandle( rec );
2052
2053     rec = 0;
2054     query = "SELECT * FROM `Media` WHERE `DiskPrompt` > 'Cabinet'";
2055     r = do_query(hdb, query, &rec);
2056     ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %d\n", r );
2057     MsiCloseHandle( rec );
2058
2059     rec = 0;
2060     query = "SELECT * FROM `Media` WHERE `DiskPrompt` <> 'Cabinet'";
2061     r = do_query(hdb, query, &rec);
2062     ok( r == ERROR_SUCCESS, "query failed: %d\n", r );
2063     MsiCloseHandle( rec );
2064
2065     rec = 0;
2066     query = "SELECT * FROM `Media` WHERE `DiskPrompt` = 'Cabinet'";
2067     r = do_query(hdb, query, &rec);
2068     ok( r == ERROR_NO_MORE_ITEMS, "query failed: %d\n", r );
2069     MsiCloseHandle( rec );
2070
2071     rec = MsiCreateRecord(1);
2072     MsiRecordSetString(rec, 1, "");
2073
2074     query = "SELECT * FROM `Media` WHERE `DiskPrompt` = ?";
2075     r = MsiDatabaseOpenView(hdb, query, &view);
2076     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2077     r = MsiViewExecute(view, rec);
2078     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2079
2080     MsiCloseHandle(rec);
2081
2082     r = MsiViewFetch(view, &rec);
2083     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2084
2085     MsiCloseHandle(rec);
2086     MsiViewClose(view);
2087     MsiCloseHandle(view);
2088
2089     MsiCloseHandle( hdb );
2090     DeleteFile(msifile);
2091 }
2092
2093 static CHAR CURR_DIR[MAX_PATH];
2094
2095 static const CHAR test_data[] = "FirstPrimaryColumn\tSecondPrimaryColumn\tShortInt\tShortIntNullable\tLongInt\tLongIntNullable\tString\tLocalizableString\tLocalizableStringNullable\n"
2096                                 "s255\ti2\ti2\tI2\ti4\tI4\tS255\tS0\ts0\n"
2097                                 "TestTable\tFirstPrimaryColumn\n"
2098                                 "stringage\t5\t2\t\t2147483640\t-2147483640\tanother string\tlocalizable\tduh\n";
2099
2100 static const CHAR two_primary[] = "PrimaryOne\tPrimaryTwo\n"
2101                                   "s255\ts255\n"
2102                                   "TwoPrimary\tPrimaryOne\tPrimaryTwo\n"
2103                                   "papaya\tleaf\n"
2104                                   "papaya\tflower\n";
2105
2106 static const CHAR endlines1[] = "A\tB\tC\tD\tE\tF\r\n"
2107                                 "s72\ts72\ts72\ts72\ts72\ts72\n"
2108                                 "Table\tA\r\n"
2109                                 "a\tb\tc\td\te\tf\n"
2110                                 "g\th\ti\t\rj\tk\tl\r\n";
2111
2112 static const CHAR endlines2[] = "A\tB\tC\tD\tE\tF\r"
2113                                 "s72\ts72\ts72\ts72\ts72\ts72\n"
2114                                 "Table2\tA\r\n"
2115                                 "a\tb\tc\td\te\tf\n"
2116                                 "g\th\ti\tj\tk\tl\r\n";
2117
2118 static const CHAR suminfo[] = "PropertyId\tValue\n"
2119                               "i2\tl255\n"
2120                               "_SummaryInformation\tPropertyId\n"
2121                               "1\t1252\n"
2122                               "2\tInstaller Database\n"
2123                               "3\tInstaller description\n"
2124                               "4\tWineHQ\n"
2125                               "5\tInstaller\n"
2126                               "6\tInstaller comments\n"
2127                               "7\tIntel;1033,2057\n"
2128                               "9\t{12345678-1234-1234-1234-123456789012}\n"
2129                               "12\t2009/04/12 15:46:11\n"
2130                               "13\t2009/04/12 15:46:11\n"
2131                               "14\t200\n"
2132                               "15\t2\n"
2133                               "18\tVim\n"
2134                               "19\t2\n";
2135
2136 static void write_file(const CHAR *filename, const char *data, int data_size)
2137 {
2138     DWORD size;
2139
2140     HANDLE hf = CreateFile(filename, GENERIC_WRITE, 0, NULL,
2141                            CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2142
2143     WriteFile(hf, data, data_size, &size, NULL);
2144     CloseHandle(hf);
2145 }
2146
2147 static UINT add_table_to_db(MSIHANDLE hdb, LPCSTR table_data)
2148 {
2149     UINT r;
2150
2151     write_file("temp_file", table_data, (lstrlen(table_data) - 1) * sizeof(char));
2152     r = MsiDatabaseImportA(hdb, CURR_DIR, "temp_file");
2153     DeleteFileA("temp_file");
2154
2155     return r;
2156 }
2157
2158 static void test_suminfo_import(void)
2159 {
2160     MSIHANDLE hdb, hsi, view = 0;
2161     LPCSTR query;
2162     UINT r, count, size, type;
2163     char str_value[50];
2164     INT int_value;
2165     FILETIME ft_value;
2166
2167     GetCurrentDirectoryA(MAX_PATH, CURR_DIR);
2168
2169     r = MsiOpenDatabaseA(msifile, MSIDBOPEN_CREATE, &hdb);
2170     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2171
2172     r = add_table_to_db(hdb, suminfo);
2173     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2174
2175     /* _SummaryInformation is not imported as a regular table... */
2176
2177     query = "SELECT * FROM `_SummaryInformation`";
2178     r = MsiDatabaseOpenViewA(hdb, query, &view);
2179     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %u\n", r);
2180     MsiCloseHandle(view);
2181
2182     /* ...its data is added to the special summary information stream */
2183
2184     r = MsiGetSummaryInformationA(hdb, NULL, 0, &hsi);
2185     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2186
2187     r = MsiSummaryInfoGetPropertyCount(hsi, &count);
2188     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2189     ok(count == 14, "Expected 14, got %u\n", count);
2190
2191     r = MsiSummaryInfoGetPropertyA(hsi, PID_CODEPAGE, &type, &int_value, NULL, NULL, NULL);
2192     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2193     ok(type ==  VT_I2, "Expected VT_I2, got %u\n", type);
2194     ok(int_value == 1252, "Expected 1252, got %d\n", int_value);
2195
2196     size = sizeof(str_value);
2197     r = MsiSummaryInfoGetPropertyA(hsi, PID_TITLE, &type, NULL, NULL, str_value, &size);
2198     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2199     ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
2200     ok(size == 18, "Expected 18, got %u\n", size);
2201     ok(!strcmp(str_value, "Installer Database"),
2202        "Expected \"Installer Database\", got %s\n", str_value);
2203
2204     size = sizeof(str_value);
2205     r = MsiSummaryInfoGetPropertyA(hsi, PID_SUBJECT, &type, NULL, NULL, str_value, &size);
2206     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2207     ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
2208     ok(!strcmp(str_value, "Installer description"),
2209        "Expected \"Installer description\", got %s\n", str_value);
2210
2211     size = sizeof(str_value);
2212     r = MsiSummaryInfoGetPropertyA(hsi, PID_AUTHOR, &type, NULL, NULL, str_value, &size);
2213     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2214     ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
2215     ok(!strcmp(str_value, "WineHQ"),
2216        "Expected \"WineHQ\", got %s\n", str_value);
2217
2218     size = sizeof(str_value);
2219     r = MsiSummaryInfoGetPropertyA(hsi, PID_KEYWORDS, &type, NULL, NULL, str_value, &size);
2220     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2221     ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
2222     ok(!strcmp(str_value, "Installer"),
2223        "Expected \"Installer\", got %s\n", str_value);
2224
2225     size = sizeof(str_value);
2226     r = MsiSummaryInfoGetPropertyA(hsi, PID_COMMENTS, &type, NULL, NULL, str_value, &size);
2227     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2228     ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
2229     ok(!strcmp(str_value, "Installer comments"),
2230        "Expected \"Installer comments\", got %s\n", str_value);
2231
2232     size = sizeof(str_value);
2233     r = MsiSummaryInfoGetPropertyA(hsi, PID_TEMPLATE, &type, NULL, NULL, str_value, &size);
2234     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2235     ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
2236     ok(!strcmp(str_value, "Intel;1033,2057"),
2237        "Expected \"Intel;1033,2057\", got %s\n", str_value);
2238
2239     size = sizeof(str_value);
2240     r = MsiSummaryInfoGetPropertyA(hsi, PID_REVNUMBER, &type, NULL, NULL, str_value, &size);
2241     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2242     ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
2243     ok(!strcmp(str_value, "{12345678-1234-1234-1234-123456789012}"),
2244        "Expected \"{12345678-1234-1234-1234-123456789012}\", got %s\n", str_value);
2245
2246     r = MsiSummaryInfoGetPropertyA(hsi, PID_CREATE_DTM, &type, NULL, &ft_value, NULL, NULL);
2247     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2248     ok(type == VT_FILETIME, "Expected VT_FILETIME, got %u\n", type);
2249
2250     r = MsiSummaryInfoGetPropertyA(hsi, PID_LASTSAVE_DTM, &type, NULL, &ft_value, NULL, NULL);
2251     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2252     ok(type == VT_FILETIME, "Expected VT_FILETIME, got %u\n", type);
2253
2254     r = MsiSummaryInfoGetPropertyA(hsi, PID_PAGECOUNT, &type, &int_value, NULL, NULL, NULL);
2255     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2256     ok(type ==  VT_I4, "Expected VT_I4, got %u\n", type);
2257     ok(int_value == 200, "Expected 200, got %d\n", int_value);
2258
2259     r = MsiSummaryInfoGetPropertyA(hsi, PID_WORDCOUNT, &type, &int_value, NULL, NULL, NULL);
2260     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2261     ok(type ==  VT_I4, "Expected VT_I4, got %u\n", type);
2262     ok(int_value == 2, "Expected 2, got %d\n", int_value);
2263
2264     r = MsiSummaryInfoGetPropertyA(hsi, PID_SECURITY, &type, &int_value, NULL, NULL, NULL);
2265     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2266     ok(type ==  VT_I4, "Expected VT_I4, got %u\n", type);
2267     ok(int_value == 2, "Expected 2, got %d\n", int_value);
2268
2269     size = sizeof(str_value);
2270     r = MsiSummaryInfoGetPropertyA(hsi, PID_APPNAME, &type, NULL, NULL, str_value, &size);
2271     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2272     ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
2273     ok(!strcmp(str_value, "Vim"), "Expected \"Vim\", got %s\n", str_value);
2274
2275     MsiCloseHandle(hsi);
2276     MsiCloseHandle(hdb);
2277     DeleteFileA(msifile);
2278 }
2279
2280 static void test_msiimport(void)
2281 {
2282     MSIHANDLE hdb, view, rec;
2283     LPCSTR query;
2284     UINT r, count;
2285     signed int i;
2286
2287     GetCurrentDirectoryA(MAX_PATH, CURR_DIR);
2288
2289     r = MsiOpenDatabaseA(msifile, MSIDBOPEN_CREATE, &hdb);
2290     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2291
2292     r = add_table_to_db(hdb, test_data);
2293     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2294
2295     r = add_table_to_db(hdb, two_primary);
2296     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2297
2298     r = add_table_to_db(hdb, endlines1);
2299     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2300
2301     r = add_table_to_db(hdb, endlines2);
2302     ok(r == ERROR_FUNCTION_FAILED, "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
2303
2304     query = "SELECT * FROM `TestTable`";
2305     r = MsiDatabaseOpenView(hdb, query, &view);
2306     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2307
2308     r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec);
2309     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2310     count = MsiRecordGetFieldCount(rec);
2311     ok(count == 9, "Expected 9, got %d\n", count);
2312     ok(check_record(rec, 1, "FirstPrimaryColumn"), "Expected FirstPrimaryColumn\n");
2313     ok(check_record(rec, 2, "SecondPrimaryColumn"), "Expected SecondPrimaryColumn\n");
2314     ok(check_record(rec, 3, "ShortInt"), "Expected ShortInt\n");
2315     ok(check_record(rec, 4, "ShortIntNullable"), "Expected ShortIntNullalble\n");
2316     ok(check_record(rec, 5, "LongInt"), "Expected LongInt\n");
2317     ok(check_record(rec, 6, "LongIntNullable"), "Expected LongIntNullalble\n");
2318     ok(check_record(rec, 7, "String"), "Expected String\n");
2319     ok(check_record(rec, 8, "LocalizableString"), "Expected LocalizableString\n");
2320     ok(check_record(rec, 9, "LocalizableStringNullable"), "Expected LocalizableStringNullable\n");
2321     MsiCloseHandle(rec);
2322
2323     r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
2324     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2325     count = MsiRecordGetFieldCount(rec);
2326     ok(count == 9, "Expected 9, got %d\n", count);
2327     ok(check_record(rec, 1, "s255"), "Expected s255\n");
2328     ok(check_record(rec, 2, "i2"), "Expected i2\n");
2329     ok(check_record(rec, 3, "i2"), "Expected i2\n");
2330     ok(check_record(rec, 4, "I2"), "Expected I2\n");
2331     ok(check_record(rec, 5, "i4"), "Expected i4\n");
2332     ok(check_record(rec, 6, "I4"), "Expected I4\n");
2333     ok(check_record(rec, 7, "S255"), "Expected S255\n");
2334     ok(check_record(rec, 8, "S0"), "Expected S0\n");
2335     ok(check_record(rec, 9, "s0"), "Expected s0\n");
2336     MsiCloseHandle(rec);
2337
2338     query = "SELECT * FROM `TestTable`";
2339     r = do_query(hdb, query, &rec);
2340     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2341     ok(check_record(rec, 1, "stringage"), "Expected 'stringage'\n");
2342     ok(check_record(rec, 7, "another string"), "Expected 'another string'\n");
2343     ok(check_record(rec, 8, "localizable"), "Expected 'localizable'\n");
2344     ok(check_record(rec, 9, "duh"), "Expected 'duh'\n");
2345
2346     i = MsiRecordGetInteger(rec, 2);
2347     ok(i == 5, "Expected 5, got %d\n", i);
2348
2349     i = MsiRecordGetInteger(rec, 3);
2350     ok(i == 2, "Expected 2, got %d\n", i);
2351
2352     i = MsiRecordGetInteger(rec, 4);
2353     ok(i == MSI_NULL_INTEGER, "Expected MSI_NULL_INTEGER, got %d\n", i);
2354
2355     i = MsiRecordGetInteger(rec, 5);
2356     ok(i == 2147483640, "Expected 2147483640, got %d\n", i);
2357
2358     i = MsiRecordGetInteger(rec, 6);
2359     ok(i == -2147483640, "Expected -2147483640, got %d\n", i);
2360
2361     MsiCloseHandle(rec);
2362     MsiViewClose(view);
2363     MsiCloseHandle(view);
2364
2365     query = "SELECT * FROM `TwoPrimary`";
2366     r = MsiDatabaseOpenView(hdb, query, &view);
2367     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2368
2369     r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec);
2370     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2371     count = MsiRecordGetFieldCount(rec);
2372     ok(count == 2, "Expected 2, got %d\n", count);
2373     ok(check_record(rec, 1, "PrimaryOne"), "Expected PrimaryOne\n");
2374     ok(check_record(rec, 2, "PrimaryTwo"), "Expected PrimaryTwo\n");
2375
2376     MsiCloseHandle(rec);
2377
2378     r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
2379     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2380     count = MsiRecordGetFieldCount(rec);
2381     ok(count == 2, "Expected 2, got %d\n", count);
2382     ok(check_record(rec, 1, "s255"), "Expected s255\n");
2383     ok(check_record(rec, 2, "s255"), "Expected s255\n");
2384     MsiCloseHandle(rec);
2385
2386     r = MsiViewExecute(view, 0);
2387     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2388
2389     r = MsiViewFetch(view, &rec);
2390     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2391
2392     ok(check_record(rec, 1, "papaya"), "Expected 'papaya'\n");
2393     ok(check_record(rec, 2, "leaf"), "Expected 'leaf'\n");
2394
2395     MsiCloseHandle(rec);
2396
2397     r = MsiViewFetch(view, &rec);
2398     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2399
2400     ok(check_record(rec, 1, "papaya"), "Expected 'papaya'\n");
2401     ok(check_record(rec, 2, "flower"), "Expected 'flower'\n");
2402
2403     MsiCloseHandle(rec);
2404
2405     r = MsiViewFetch(view, &rec);
2406     ok(r == ERROR_NO_MORE_ITEMS,
2407        "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
2408
2409     r = MsiViewClose(view);
2410     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2411
2412     MsiCloseHandle(view);
2413
2414     query = "SELECT * FROM `Table`";
2415     r = MsiDatabaseOpenView(hdb, query, &view);
2416     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2417
2418     r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec);
2419     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2420     count = MsiRecordGetFieldCount(rec);
2421     ok(count == 6, "Expected 6, got %d\n", count);
2422     ok(check_record(rec, 1, "A"), "Expected A\n");
2423     ok(check_record(rec, 2, "B"), "Expected B\n");
2424     ok(check_record(rec, 3, "C"), "Expected C\n");
2425     ok(check_record(rec, 4, "D"), "Expected D\n");
2426     ok(check_record(rec, 5, "E"), "Expected E\n");
2427     ok(check_record(rec, 6, "F"), "Expected F\n");
2428     MsiCloseHandle(rec);
2429
2430     r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
2431     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2432     count = MsiRecordGetFieldCount(rec);
2433     ok(count == 6, "Expected 6, got %d\n", count);
2434     ok(check_record(rec, 1, "s72"), "Expected s72\n");
2435     ok(check_record(rec, 2, "s72"), "Expected s72\n");
2436     ok(check_record(rec, 3, "s72"), "Expected s72\n");
2437     ok(check_record(rec, 4, "s72"), "Expected s72\n");
2438     ok(check_record(rec, 5, "s72"), "Expected s72\n");
2439     ok(check_record(rec, 6, "s72"), "Expected s72\n");
2440     MsiCloseHandle(rec);
2441
2442     MsiViewClose(view);
2443     MsiCloseHandle(view);
2444
2445     query = "SELECT * FROM `Table`";
2446     r = MsiDatabaseOpenView(hdb, query, &view);
2447     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2448
2449     r = MsiViewExecute(view, 0);
2450     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2451
2452     r = MsiViewFetch(view, &rec);
2453     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2454     ok(check_record(rec, 1, "a"), "Expected 'a'\n");
2455     ok(check_record(rec, 2, "b"), "Expected 'b'\n");
2456     ok(check_record(rec, 3, "c"), "Expected 'c'\n");
2457     ok(check_record(rec, 4, "d"), "Expected 'd'\n");
2458     ok(check_record(rec, 5, "e"), "Expected 'e'\n");
2459     ok(check_record(rec, 6, "f"), "Expected 'f'\n");
2460
2461     MsiCloseHandle(rec);
2462
2463     r = MsiViewFetch(view, &rec);
2464     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2465     ok(check_record(rec, 1, "g"), "Expected 'g'\n");
2466     ok(check_record(rec, 2, "h"), "Expected 'h'\n");
2467     ok(check_record(rec, 3, "i"), "Expected 'i'\n");
2468     ok(check_record(rec, 4, "j"), "Expected 'j'\n");
2469     ok(check_record(rec, 5, "k"), "Expected 'k'\n");
2470     ok(check_record(rec, 6, "l"), "Expected 'l'\n");
2471
2472     MsiCloseHandle(rec);
2473
2474     r = MsiViewFetch(view, &rec);
2475     ok(r == ERROR_NO_MORE_ITEMS,
2476        "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
2477
2478     MsiViewClose(view);
2479     MsiCloseHandle(view);
2480     MsiCloseHandle(hdb);
2481     DeleteFileA(msifile);
2482 }
2483
2484 static const CHAR bin_import_dat[] = "Name\tData\r\n"
2485                                      "s72\tV0\r\n"
2486                                      "Binary\tName\r\n"
2487                                      "filename1\tfilename1.ibd\r\n";
2488
2489 static void test_binary_import(void)
2490 {
2491     MSIHANDLE hdb = 0, rec;
2492     char file[MAX_PATH];
2493     char buf[MAX_PATH];
2494     char path[MAX_PATH];
2495     DWORD size;
2496     LPCSTR query;
2497     UINT r;
2498
2499     /* create files to import */
2500     write_file("bin_import.idt", bin_import_dat,
2501           (sizeof(bin_import_dat) - 1) * sizeof(char));
2502     CreateDirectory("bin_import", NULL);
2503     create_file_data("bin_import/filename1.ibd", "just some words", 15);
2504
2505     /* import files into database */
2506     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
2507     ok( r == ERROR_SUCCESS , "Failed to open database\n");
2508
2509     GetCurrentDirectory(MAX_PATH, path);
2510     r = MsiDatabaseImport(hdb, path, "bin_import.idt");
2511     ok(r == ERROR_SUCCESS , "Failed to import Binary table\n");
2512
2513     /* read file from the Binary table */
2514     query = "SELECT * FROM `Binary`";
2515     r = do_query(hdb, query, &rec);
2516     ok(r == ERROR_SUCCESS, "SELECT query failed: %d\n", r);
2517
2518     size = MAX_PATH;
2519     r = MsiRecordGetString(rec, 1, file, &size);
2520     ok(r == ERROR_SUCCESS, "Failed to get string: %d\n", r);
2521     ok(!lstrcmp(file, "filename1"), "Expected 'filename1', got %s\n", file);
2522
2523     size = MAX_PATH;
2524     memset(buf, 0, MAX_PATH);
2525     r = MsiRecordReadStream(rec, 2, buf, &size);
2526     ok(r == ERROR_SUCCESS, "Failed to get stream: %d\n", r);
2527     ok(!lstrcmp(buf, "just some words"),
2528         "Expected 'just some words', got %s\n", buf);
2529
2530     r = MsiCloseHandle(rec);
2531     ok(r == ERROR_SUCCESS , "Failed to close record handle\n");
2532
2533     r = MsiCloseHandle(hdb);
2534     ok(r == ERROR_SUCCESS , "Failed to close database\n");
2535
2536     DeleteFile("bin_import/filename1.ibd");
2537     RemoveDirectory("bin_import");
2538     DeleteFile("bin_import.idt");
2539 }
2540
2541 static void test_markers(void)
2542 {
2543     MSIHANDLE hdb, rec;
2544     LPCSTR query;
2545     UINT r;
2546
2547     hdb = create_db();
2548     ok( hdb, "failed to create db\n");
2549
2550     rec = MsiCreateRecord(3);
2551     MsiRecordSetString(rec, 1, "Table");
2552     MsiRecordSetString(rec, 2, "Apples");
2553     MsiRecordSetString(rec, 3, "Oranges");
2554
2555     /* try a legit create */
2556     query = "CREATE TABLE `Table` ( `One` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`)";
2557     r = run_query(hdb, 0, query);
2558     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2559     MsiCloseHandle(rec);
2560
2561     /* try table name as marker */
2562     rec = MsiCreateRecord(1);
2563     MsiRecordSetString(rec, 1, "Fable");
2564     query = "CREATE TABLE `?` ( `One` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`)";
2565     r = run_query(hdb, rec, query);
2566     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2567
2568     /* verify that we just created a table called '?', not 'Fable' */
2569     r = try_query(hdb, "SELECT * from `Fable`");
2570     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2571
2572     r = try_query(hdb, "SELECT * from `?`");
2573     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2574
2575     /* try table name as marker without backticks */
2576     MsiRecordSetString(rec, 1, "Mable");
2577     query = "CREATE TABLE ? ( `One` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`)";
2578     r = run_query(hdb, rec, query);
2579     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2580
2581     /* try one column name as marker */
2582     MsiRecordSetString(rec, 1, "One");
2583     query = "CREATE TABLE `Mable` ( `?` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`)";
2584     r = run_query(hdb, rec, query);
2585     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2586     MsiCloseHandle(rec);
2587
2588     /* try column names as markers */
2589     rec = MsiCreateRecord(2);
2590     MsiRecordSetString(rec, 1, "One");
2591     MsiRecordSetString(rec, 2, "Two");
2592     query = "CREATE TABLE `Mable` ( `?` SHORT NOT NULL, `?` CHAR(255) PRIMARY KEY `One`)";
2593     r = run_query(hdb, rec, query);
2594     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2595     MsiCloseHandle(rec);
2596
2597     /* try names with backticks */
2598     rec = MsiCreateRecord(3);
2599     MsiRecordSetString(rec, 1, "One");
2600     MsiRecordSetString(rec, 2, "Two");
2601     MsiRecordSetString(rec, 3, "One");
2602     query = "CREATE TABLE `Mable` ( `?` SHORT NOT NULL, `?` CHAR(255) PRIMARY KEY `?`)";
2603     r = run_query(hdb, rec, query);
2604     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2605
2606     /* try names with backticks, minus definitions */
2607     query = "CREATE TABLE `Mable` ( `?`, `?` PRIMARY KEY `?`)";
2608     r = run_query(hdb, rec, query);
2609     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2610
2611     /* try names without backticks */
2612     query = "CREATE TABLE `Mable` ( ? SHORT NOT NULL, ? CHAR(255) PRIMARY KEY ?)";
2613     r = run_query(hdb, rec, query);
2614     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2615     MsiCloseHandle(rec);
2616
2617     /* try one long marker */
2618     rec = MsiCreateRecord(1);
2619     MsiRecordSetString(rec, 1, "`One` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`");
2620     query = "CREATE TABLE `Mable` ( ? )";
2621     r = run_query(hdb, rec, query);
2622     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2623     MsiCloseHandle(rec);
2624
2625     /* try all names as markers */
2626     rec = MsiCreateRecord(4);
2627     MsiRecordSetString(rec, 1, "Mable");
2628     MsiRecordSetString(rec, 2, "One");
2629     MsiRecordSetString(rec, 3, "Two");
2630     MsiRecordSetString(rec, 4, "One");
2631     query = "CREATE TABLE `?` ( `?` SHORT NOT NULL, `?` CHAR(255) PRIMARY KEY `?`)";
2632     r = run_query(hdb, rec, query);
2633     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2634     MsiCloseHandle(rec);
2635
2636     /* try a legit insert */
2637     query = "INSERT INTO `Table` ( `One`, `Two` ) VALUES ( 5, 'hello' )";
2638     r = run_query(hdb, 0, query);
2639     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2640
2641     r = try_query(hdb, "SELECT * from `Table`");
2642     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2643
2644     /* try values as markers */
2645     rec = MsiCreateRecord(2);
2646     MsiRecordSetInteger(rec, 1, 4);
2647     MsiRecordSetString(rec, 2, "hi");
2648     query = "INSERT INTO `Table` ( `One`, `Two` ) VALUES ( ?, '?' )";
2649     r = run_query(hdb, rec, query);
2650     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2651     MsiCloseHandle(rec);
2652
2653     /* try column names and values as markers */
2654     rec = MsiCreateRecord(4);
2655     MsiRecordSetString(rec, 1, "One");
2656     MsiRecordSetString(rec, 2, "Two");
2657     MsiRecordSetInteger(rec, 3, 5);
2658     MsiRecordSetString(rec, 4, "hi");
2659     query = "INSERT INTO `Table` ( `?`, `?` ) VALUES ( ?, '?' )";
2660     r = run_query(hdb, rec, query);
2661     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2662     MsiCloseHandle(rec);
2663
2664     /* try column names as markers */
2665     rec = MsiCreateRecord(2);
2666     MsiRecordSetString(rec, 1, "One");
2667     MsiRecordSetString(rec, 2, "Two");
2668     query = "INSERT INTO `Table` ( `?`, `?` ) VALUES ( 3, 'yellow' )";
2669     r = run_query(hdb, rec, query);
2670     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2671     MsiCloseHandle(rec);
2672
2673     /* try table name as a marker */
2674     rec = MsiCreateRecord(1);
2675     MsiRecordSetString(rec, 1, "Table");
2676     query = "INSERT INTO `?` ( `One`, `Two` ) VALUES ( 2, 'green' )";
2677     r = run_query(hdb, rec, query);
2678     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2679     MsiCloseHandle(rec);
2680
2681     /* try table name and values as markers */
2682     rec = MsiCreateRecord(3);
2683     MsiRecordSetString(rec, 1, "Table");
2684     MsiRecordSetInteger(rec, 2, 10);
2685     MsiRecordSetString(rec, 3, "haha");
2686     query = "INSERT INTO `?` ( `One`, `Two` ) VALUES ( ?, '?' )";
2687     r = run_query(hdb, rec, query);
2688     ok(r == ERROR_FUNCTION_FAILED, "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
2689     MsiCloseHandle(rec);
2690
2691     /* try all markers */
2692     rec = MsiCreateRecord(5);
2693     MsiRecordSetString(rec, 1, "Table");
2694     MsiRecordSetString(rec, 1, "One");
2695     MsiRecordSetString(rec, 1, "Two");
2696     MsiRecordSetInteger(rec, 2, 10);
2697     MsiRecordSetString(rec, 3, "haha");
2698     query = "INSERT INTO `?` ( `?`, `?` ) VALUES ( ?, '?' )";
2699     r = run_query(hdb, rec, query);
2700     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2701     MsiCloseHandle(rec);
2702
2703     /* insert an integer as a string */
2704     rec = MsiCreateRecord(2);
2705     MsiRecordSetString(rec, 1, "11");
2706     MsiRecordSetString(rec, 2, "hi");
2707     query = "INSERT INTO `Table` ( `One`, `Two` ) VALUES ( ?, '?' )";
2708     r = run_query(hdb, rec, query);
2709     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2710     MsiCloseHandle(rec);
2711
2712     /* leave off the '' for the string */
2713     rec = MsiCreateRecord(2);
2714     MsiRecordSetInteger(rec, 1, 12);
2715     MsiRecordSetString(rec, 2, "hi");
2716     query = "INSERT INTO `Table` ( `One`, `Two` ) VALUES ( ?, ? )";
2717     r = run_query(hdb, rec, query);
2718     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2719     MsiCloseHandle(rec);
2720
2721     MsiCloseHandle(hdb);
2722     DeleteFileA(msifile);
2723 }
2724
2725 #define MY_NVIEWS 4000    /* Largest installer I've seen uses < 2k */
2726 static void test_handle_limit(void)
2727 {
2728     int i;
2729     MSIHANDLE hdb;
2730     MSIHANDLE hviews[MY_NVIEWS];
2731     UINT r;
2732
2733     /* create an empty db */
2734     hdb = create_db();
2735     ok( hdb, "failed to create db\n");
2736
2737     memset(hviews, 0, sizeof(hviews));
2738
2739     for (i=0; i<MY_NVIEWS; i++) {
2740         static char szQueryBuf[256] = "SELECT * from `_Tables`";
2741         hviews[i] = 0xdeadbeeb;
2742         r = MsiDatabaseOpenView(hdb, szQueryBuf, &hviews[i]);
2743         if( r != ERROR_SUCCESS || hviews[i] == 0xdeadbeeb || 
2744             hviews[i] == 0 || (i && (hviews[i] == hviews[i-1])))
2745             break;
2746     }
2747
2748     ok( i == MY_NVIEWS, "problem opening views\n");
2749
2750     for (i=0; i<MY_NVIEWS; i++) {
2751         if (hviews[i] != 0 && hviews[i] != 0xdeadbeeb) {
2752             MsiViewClose(hviews[i]);
2753             r = MsiCloseHandle(hviews[i]);
2754             if (r != ERROR_SUCCESS)
2755                 break;
2756         }
2757     }
2758
2759     ok( i == MY_NVIEWS, "problem closing views\n");
2760
2761     r = MsiCloseHandle(hdb);
2762     ok( r == ERROR_SUCCESS, "failed to close database\n");
2763 }
2764
2765 static void generate_transform(void)
2766 {
2767     MSIHANDLE hdb1, hdb2, hrec;
2768     LPCSTR query;
2769     UINT r;
2770
2771     /* start with two identical databases */
2772     CopyFile(msifile2, msifile, FALSE);
2773
2774     r = MsiOpenDatabase(msifile, MSIDBOPEN_TRANSACT, &hdb1 );
2775     ok( r == ERROR_SUCCESS , "Failed to create database\n" );
2776
2777     r = MsiDatabaseCommit( hdb1 );
2778     ok( r == ERROR_SUCCESS , "Failed to commit database\n" );
2779
2780     r = MsiOpenDatabase(msifile2, MSIDBOPEN_READONLY, &hdb2 );
2781     ok( r == ERROR_SUCCESS , "Failed to create database\n" );
2782
2783     /* the transform between two identical database should be empty */
2784     r = MsiDatabaseGenerateTransform(hdb1, hdb2, NULL, 0, 0);
2785     todo_wine {
2786     ok( r == ERROR_NO_DATA, "return code %d, should be ERROR_NO_DATA\n", r );
2787     }
2788
2789     query = "CREATE TABLE `AAR` ( `BAR` SHORT NOT NULL, `CAR` CHAR(255) PRIMARY KEY `CAR`)";
2790     r = run_query(hdb1, 0, query);
2791     ok(r == ERROR_SUCCESS, "failed to add table\n");
2792
2793     query = "INSERT INTO `AAR` ( `BAR`, `CAR` ) VALUES ( 1, 'vw' )";
2794     r = run_query(hdb1, 0, query);
2795     ok(r == ERROR_SUCCESS, "failed to add row 1\n");
2796
2797     query = "INSERT INTO `AAR` ( `BAR`, `CAR` ) VALUES ( 2, 'bmw' )";
2798     r = run_query(hdb1, 0, query);
2799     ok(r == ERROR_SUCCESS, "failed to add row 2\n");
2800
2801     query = "UPDATE `MOO` SET `OOO` = 'c' WHERE `NOO` = 1";
2802     r = run_query(hdb1, 0, query);
2803     ok(r == ERROR_SUCCESS, "failed to modify row\n");
2804
2805     query = "DELETE FROM `MOO` WHERE `NOO` = 3";
2806     r = run_query(hdb1, 0, query);
2807     ok(r == ERROR_SUCCESS, "failed to delete row\n");
2808
2809     hrec = MsiCreateRecord(2);
2810     r = MsiRecordSetInteger(hrec, 1, 1);
2811     ok(r == ERROR_SUCCESS, "failed to set integer\n");
2812
2813     write_file("testdata.bin", "naengmyon", 9);
2814     r = MsiRecordSetStream(hrec, 2, "testdata.bin");
2815     ok(r == ERROR_SUCCESS, "failed to set stream\n");
2816
2817     query = "INSERT INTO `BINARY` ( `ID`, `BLOB` ) VALUES ( ?, ? )";
2818     r = run_query(hdb1, hrec, query);
2819     ok(r == ERROR_SUCCESS, "failed to add row with blob\n");
2820
2821     MsiCloseHandle(hrec);
2822
2823     query = "ALTER TABLE `MOO` ADD `COW` INTEGER";
2824     r = run_query(hdb1, 0, query);
2825     ok(r == ERROR_SUCCESS, "failed to add column\n");
2826
2827     query = "ALTER TABLE `MOO` ADD `PIG` INTEGER";
2828     r = run_query(hdb1, 0, query);
2829     ok(r == ERROR_SUCCESS, "failed to add column\n");
2830
2831     query = "UPDATE `MOO` SET `PIG` = 5 WHERE `NOO` = 1";
2832     r = run_query(hdb1, 0, query);
2833     ok(r == ERROR_SUCCESS, "failed to modify row\n");
2834
2835     query = "CREATE TABLE `Property` ( `Property` CHAR(72) NOT NULL, "
2836             "`Value` CHAR(0) PRIMARY KEY `Property`)";
2837     r = run_query(hdb1, 0, query);
2838     ok(r == ERROR_SUCCESS, "failed to add property table\n");
2839
2840     query = "INSERT INTO `Property` ( `Property`, `Value` ) VALUES ( 'prop', 'val' )";
2841     r = run_query(hdb1, 0, query);
2842     ok(r == ERROR_SUCCESS, "failed to add property\n");
2843
2844     /* database needs to be committed */
2845     MsiDatabaseCommit(hdb1);
2846
2847     r = MsiDatabaseGenerateTransform(hdb1, hdb2, mstfile, 0, 0);
2848     ok( r == ERROR_SUCCESS, "return code %d, should be ERROR_SUCCESS\n", r );
2849
2850     MsiCloseHandle( hdb1 );
2851     MsiCloseHandle( hdb2 );
2852
2853     DeleteFile("testdata.bin");
2854 }
2855
2856 /* data for generating a transform */
2857
2858 /* tables transform names - encoded as they would be in an msi database file */
2859 static const WCHAR name1[] = { 0x4840, 0x3a8a, 0x481b, 0 }; /* AAR */
2860 static const WCHAR name2[] = { 0x4840, 0x3b3f, 0x43f2, 0x4438, 0x45b1, 0 }; /* _Columns */
2861 static const WCHAR name3[] = { 0x4840, 0x3f7f, 0x4164, 0x422f, 0x4836, 0 }; /* _Tables */
2862 static const WCHAR name4[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0 }; /* _StringData */
2863 static const WCHAR name5[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0 }; /* _StringPool */
2864 static const WCHAR name6[] = { 0x4840, 0x3e16, 0x4818, 0}; /* MOO */
2865 static const WCHAR name7[] = { 0x4840, 0x3c8b, 0x3a97, 0x409b, 0 }; /* BINARY */
2866 static const WCHAR name8[] = { 0x3c8b, 0x3a97, 0x409b, 0x387e, 0 }; /* BINARY.1 */
2867 static const WCHAR name9[] = { 0x4840, 0x4559, 0x44f2, 0x4568, 0x4737, 0 }; /* Property */
2868
2869 /* data in each table */
2870 static const WCHAR data1[] = { /* AAR */
2871     0x0201, 0x0008, 0x8001,  /* 0x0201 = add row (1), two shorts */
2872     0x0201, 0x0009, 0x8002,
2873 };
2874 static const WCHAR data2[] = { /* _Columns */
2875     0x0401, 0x0001, 0x8003, 0x0002, 0x9502,
2876     0x0401, 0x0001, 0x8004, 0x0003, 0x9502,
2877     0x0401, 0x0005, 0x0000, 0x0006, 0xbdff,  /* 0x0401 = add row (1), 4 shorts */
2878     0x0401, 0x0005, 0x0000, 0x0007, 0x8502,
2879     0x0401, 0x000a, 0x0000, 0x000a, 0xad48,
2880     0x0401, 0x000a, 0x0000, 0x000b, 0x9d00,
2881 };
2882 static const WCHAR data3[] = { /* _Tables */
2883     0x0101, 0x0005, /* 0x0101 = add row (1), 1 short */
2884     0x0101, 0x000a,
2885 };
2886 static const char data4[] = /* _StringData */
2887     "MOOCOWPIGcAARCARBARvwbmwPropertyValuepropval";  /* all the strings squashed together */
2888 static const WCHAR data5[] = { /* _StringPool */
2889 /*  len, refs */
2890     0,   0,    /* string 0 ''    */
2891     3,   2,    /* string 1 'MOO' */
2892     3,   1,    /* string 2 'COW' */
2893     3,   1,    /* string 3 'PIG' */
2894     1,   1,    /* string 4 'c'   */
2895     3,   3,    /* string 5 'AAR' */
2896     3,   1,    /* string 6 'CAR' */
2897     3,   1,    /* string 7 'BAR' */
2898     2,   1,    /* string 8 'vw'  */
2899     3,   1,    /* string 9 'bmw' */
2900     8,   4,    /* string 10 'Property' */
2901     5,   1,    /* string 11 'Value' */
2902     4,   1,    /* string 12 'prop' */
2903     3,   1,    /* string 13 'val' */
2904 };
2905 /* update row, 0x0002 is a bitmask of present column data, keys are excluded */
2906 static const WCHAR data6[] = { /* MOO */
2907     0x000a, 0x8001, 0x0004, 0x8005, /* update row */
2908     0x0000, 0x8003,         /* delete row */
2909 };
2910
2911 static const WCHAR data7[] = { /* BINARY */
2912     0x0201, 0x8001, 0x0001,
2913 };
2914
2915 static const char data8[] =  /* stream data for the BINARY table */
2916     "naengmyon";
2917
2918 static const WCHAR data9[] = { /* Property */
2919     0x0201, 0x000c, 0x000d,
2920 };
2921
2922 static const struct {
2923     LPCWSTR name;
2924     const void *data;
2925     DWORD size;
2926 } table_transform_data[] =
2927 {
2928     { name1, data1, sizeof data1 },
2929     { name2, data2, sizeof data2 },
2930     { name3, data3, sizeof data3 },
2931     { name4, data4, sizeof data4 - 1 },
2932     { name5, data5, sizeof data5 },
2933     { name6, data6, sizeof data6 },
2934     { name7, data7, sizeof data7 },
2935     { name8, data8, sizeof data8 - 1 },
2936     { name9, data9, sizeof data9 },
2937 };
2938
2939 #define NUM_TRANSFORM_TABLES (sizeof table_transform_data/sizeof table_transform_data[0])
2940
2941 static void generate_transform_manual(void)
2942 {
2943     IStorage *stg = NULL;
2944     IStream *stm;
2945     WCHAR name[0x20];
2946     HRESULT r;
2947     DWORD i, count;
2948     const DWORD mode = STGM_CREATE|STGM_READWRITE|STGM_DIRECT|STGM_SHARE_EXCLUSIVE;
2949
2950     const CLSID CLSID_MsiTransform = { 0xc1082,0,0,{0xc0,0,0,0,0,0,0,0x46}};
2951
2952     MultiByteToWideChar(CP_ACP, 0, mstfile, -1, name, 0x20);
2953
2954     r = StgCreateDocfile(name, mode, 0, &stg);
2955     ok(r == S_OK, "failed to create storage\n");
2956     if (!stg)
2957         return;
2958
2959     r = IStorage_SetClass( stg, &CLSID_MsiTransform );
2960     ok(r == S_OK, "failed to set storage type\n");
2961
2962     for (i=0; i<NUM_TRANSFORM_TABLES; i++)
2963     {
2964         r = IStorage_CreateStream( stg, table_transform_data[i].name,
2965                             STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stm );
2966         if (FAILED(r))
2967         {
2968             ok(0, "failed to create stream %08x\n", r);
2969             continue;
2970         }
2971
2972         r = IStream_Write( stm, table_transform_data[i].data,
2973                           table_transform_data[i].size, &count );
2974         if (FAILED(r) || count != table_transform_data[i].size)
2975             ok(0, "failed to write stream\n");
2976         IStream_Release(stm);
2977     }
2978
2979     IStorage_Release(stg);
2980 }
2981
2982 static UINT set_summary_info(MSIHANDLE hdb)
2983 {
2984     UINT res;
2985     MSIHANDLE suminfo;
2986
2987     /* build summary info */
2988     res = MsiGetSummaryInformation(hdb, NULL, 7, &suminfo);
2989     ok( res == ERROR_SUCCESS , "Failed to open summaryinfo\n" );
2990
2991     res = MsiSummaryInfoSetProperty(suminfo,2, VT_LPSTR, 0,NULL,
2992                         "Installation Database");
2993     ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
2994
2995     res = MsiSummaryInfoSetProperty(suminfo,3, VT_LPSTR, 0,NULL,
2996                         "Installation Database");
2997     ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
2998
2999     res = MsiSummaryInfoSetProperty(suminfo,4, VT_LPSTR, 0,NULL,
3000                         "Wine Hackers");
3001     ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
3002
3003     res = MsiSummaryInfoSetProperty(suminfo,7, VT_LPSTR, 0,NULL,
3004                     ";1033,2057");
3005     ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
3006
3007     res = MsiSummaryInfoSetProperty(suminfo,9, VT_LPSTR, 0,NULL,
3008                     "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}");
3009     ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
3010
3011     res = MsiSummaryInfoSetProperty(suminfo, 14, VT_I4, 100, NULL, NULL);
3012     ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
3013
3014     res = MsiSummaryInfoSetProperty(suminfo, 15, VT_I4, 0, NULL, NULL);
3015     ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
3016
3017     res = MsiSummaryInfoPersist(suminfo);
3018     ok( res == ERROR_SUCCESS , "Failed to make summary info persist\n" );
3019
3020     res = MsiCloseHandle( suminfo);
3021     ok( res == ERROR_SUCCESS , "Failed to close suminfo\n" );
3022
3023     return res;
3024 }
3025
3026 static MSIHANDLE create_package_db(LPCSTR filename)
3027 {
3028     MSIHANDLE hdb = 0;
3029     UINT res;
3030
3031     DeleteFile(msifile);
3032
3033     /* create an empty database */
3034     res = MsiOpenDatabase(filename, MSIDBOPEN_CREATE, &hdb );
3035     ok( res == ERROR_SUCCESS , "Failed to create database\n" );
3036     if( res != ERROR_SUCCESS )
3037         return hdb;
3038
3039     res = MsiDatabaseCommit( hdb );
3040     ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
3041
3042     res = set_summary_info(hdb);
3043     ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
3044
3045     res = create_directory_table(hdb);
3046     ok( res == ERROR_SUCCESS , "Failed to create directory table\n" );
3047
3048     return hdb;
3049 }
3050
3051 static UINT package_from_db(MSIHANDLE hdb, MSIHANDLE *handle)
3052 {
3053     UINT res;
3054     CHAR szPackage[12];
3055     MSIHANDLE hPackage;
3056
3057     sprintf(szPackage, "#%u", hdb);
3058     res = MsiOpenPackage(szPackage, &hPackage);
3059     if (res != ERROR_SUCCESS)
3060         return res;
3061
3062     res = MsiCloseHandle(hdb);
3063     if (res != ERROR_SUCCESS)
3064     {
3065         MsiCloseHandle(hPackage);
3066         return res;
3067     }
3068
3069     *handle = hPackage;
3070     return ERROR_SUCCESS;
3071 }
3072
3073 static void test_try_transform(void)
3074 {
3075     MSIHANDLE hdb, hview, hrec, hpkg = 0;
3076     LPCSTR query;
3077     UINT r;
3078     DWORD sz;
3079     char buffer[MAX_PATH];
3080
3081     DeleteFile(msifile);
3082     DeleteFile(mstfile);
3083
3084     /* create the database */
3085     hdb = create_package_db(msifile);
3086     ok(hdb, "Failed to create package db\n");
3087
3088     query = "CREATE TABLE `MOO` ( `NOO` SHORT NOT NULL, `OOO` CHAR(255) PRIMARY KEY `NOO`)";
3089     r = run_query(hdb, 0, query);
3090     ok(r == ERROR_SUCCESS, "failed to add table\n");
3091
3092     query = "INSERT INTO `MOO` ( `NOO`, `OOO` ) VALUES ( 1, 'a' )";
3093     r = run_query(hdb, 0, query);
3094     ok(r == ERROR_SUCCESS, "failed to add row\n");
3095
3096     query = "INSERT INTO `MOO` ( `NOO`, `OOO` ) VALUES ( 2, 'b' )";
3097     r = run_query(hdb, 0, query);
3098     ok(r == ERROR_SUCCESS, "failed to add row\n");
3099
3100     query = "INSERT INTO `MOO` ( `NOO`, `OOO` ) VALUES ( 3, 'c' )";
3101     r = run_query(hdb, 0, query);
3102     ok(r == ERROR_SUCCESS, "failed to add row\n");
3103
3104     query = "CREATE TABLE `BINARY` ( `ID` SHORT NOT NULL, `BLOB` OBJECT PRIMARY KEY `ID`)";
3105     r = run_query(hdb, 0, query);
3106     ok(r == ERROR_SUCCESS, "failed to add table\n");
3107
3108     hrec = MsiCreateRecord(2);
3109     r = MsiRecordSetInteger(hrec, 1, 2);
3110     ok(r == ERROR_SUCCESS, "failed to set integer\n");
3111
3112     write_file("testdata.bin", "lamyon", 6);
3113     r = MsiRecordSetStream(hrec, 2, "testdata.bin");
3114     ok(r == ERROR_SUCCESS, "failed to set stream\n");
3115
3116     query = "INSERT INTO `BINARY` ( `ID`, `BLOB` ) VALUES ( ?, ? )";
3117     r = run_query(hdb, hrec, query);
3118     ok(r == ERROR_SUCCESS, "failed to add row with blob\n");
3119
3120     MsiCloseHandle(hrec);
3121
3122     r = MsiDatabaseCommit( hdb );
3123     ok( r == ERROR_SUCCESS , "Failed to commit database\n" );
3124
3125     MsiCloseHandle( hdb );
3126     DeleteFileA("testdata.bin");
3127
3128     /*
3129      * Both these generate an equivalent transform,
3130      *  but the first doesn't work in Wine yet
3131      *  because MsiDatabaseGenerateTransform is unimplemented.
3132      */
3133     if (0)
3134         generate_transform();
3135     else
3136         generate_transform_manual();
3137
3138     r = MsiOpenDatabase(msifile, MSIDBOPEN_DIRECT, &hdb );
3139     ok( r == ERROR_SUCCESS , "Failed to create database\n" );
3140
3141     r = MsiDatabaseApplyTransform( hdb, mstfile, 0 );
3142     ok( r == ERROR_SUCCESS, "return code %d, should be ERROR_SUCCESS\n", r );
3143
3144     MsiDatabaseCommit( hdb );
3145
3146     /* check new values */
3147     hrec = 0;
3148     query = "select `BAR`,`CAR` from `AAR` where `BAR` = 1 AND `CAR` = 'vw'";
3149     r = do_query(hdb, query, &hrec);
3150     ok(r == ERROR_SUCCESS, "select query failed\n");
3151     MsiCloseHandle(hrec);
3152
3153     query = "select `BAR`,`CAR` from `AAR` where `BAR` = 2 AND `CAR` = 'bmw'";
3154     hrec = 0;
3155     r = do_query(hdb, query, &hrec);
3156     ok(r == ERROR_SUCCESS, "select query failed\n");
3157     MsiCloseHandle(hrec);
3158
3159     /* check updated values */
3160     hrec = 0;
3161     query = "select `NOO`,`OOO` from `MOO` where `NOO` = 1 AND `OOO` = 'c'";
3162     r = do_query(hdb, query, &hrec);
3163     ok(r == ERROR_SUCCESS, "select query failed\n");
3164     MsiCloseHandle(hrec);
3165
3166     /* check unchanged value */
3167     hrec = 0;
3168     query = "select `NOO`,`OOO` from `MOO` where `NOO` = 2 AND `OOO` = 'b'";
3169     r = do_query(hdb, query, &hrec);
3170     ok(r == ERROR_SUCCESS, "select query failed\n");
3171     MsiCloseHandle(hrec);
3172
3173     /* check deleted value */
3174     hrec = 0;
3175     query = "select * from `MOO` where `NOO` = 3";
3176     r = do_query(hdb, query, &hrec);
3177     ok(r == ERROR_NO_MORE_ITEMS, "select query failed\n");
3178     if (hrec) MsiCloseHandle(hrec);
3179
3180     /* check added stream */
3181     hrec = 0;
3182     query = "select `BLOB` from `BINARY` where `ID` = 1";
3183     r = do_query(hdb, query, &hrec);
3184     ok(r == ERROR_SUCCESS, "select query failed\n");
3185
3186     /* check the contents of the stream */
3187     sz = sizeof buffer;
3188     r = MsiRecordReadStream( hrec, 1, buffer, &sz );
3189     ok(r == ERROR_SUCCESS, "read stream failed\n");
3190     ok(!memcmp(buffer, "naengmyon", 9), "stream data was wrong\n");
3191     ok(sz == 9, "stream data was wrong size\n");
3192     if (hrec) MsiCloseHandle(hrec);
3193
3194     /* check the validity of the table with a deleted row */
3195     hrec = 0;
3196     query = "select * from `MOO`";
3197     r = MsiDatabaseOpenView(hdb, query, &hview);
3198     ok(r == ERROR_SUCCESS, "open view failed\n");
3199
3200     r = MsiViewExecute(hview, 0);
3201     ok(r == ERROR_SUCCESS, "view execute failed\n");
3202
3203     r = MsiViewFetch(hview, &hrec);
3204     ok(r == ERROR_SUCCESS, "view fetch failed\n");
3205
3206     r = MsiRecordGetInteger(hrec, 1);
3207     ok(r == 1, "Expected 1, got %d\n", r);
3208
3209     sz = sizeof buffer;
3210     r = MsiRecordGetString(hrec, 2, buffer, &sz);
3211     ok(r == ERROR_SUCCESS, "record get string failed\n");
3212     ok(!lstrcmpA(buffer, "c"), "Expected c, got %s\n", buffer);
3213
3214     r = MsiRecordGetInteger(hrec, 3);
3215     ok(r == 0x80000000, "Expected 0x80000000, got %d\n", r);
3216
3217     r = MsiRecordGetInteger(hrec, 4);
3218     ok(r == 5, "Expected 5, got %d\n", r);
3219
3220     MsiCloseHandle(hrec);
3221
3222     r = MsiViewFetch(hview, &hrec);
3223     ok(r == ERROR_SUCCESS, "view fetch failed\n");
3224
3225     r = MsiRecordGetInteger(hrec, 1);
3226     ok(r == 2, "Expected 2, got %d\n", r);
3227
3228     sz = sizeof buffer;
3229     r = MsiRecordGetString(hrec, 2, buffer, &sz);
3230     ok(r == ERROR_SUCCESS, "record get string failed\n");
3231     ok(!lstrcmpA(buffer, "b"), "Expected b, got %s\n", buffer);
3232
3233     r = MsiRecordGetInteger(hrec, 3);
3234     ok(r == 0x80000000, "Expected 0x80000000, got %d\n", r);
3235
3236     r = MsiRecordGetInteger(hrec, 4);
3237     ok(r == 0x80000000, "Expected 0x80000000, got %d\n", r);
3238
3239     MsiCloseHandle(hrec);
3240
3241     r = MsiViewFetch(hview, &hrec);
3242     ok(r == ERROR_NO_MORE_ITEMS, "view fetch succeeded\n");
3243
3244     MsiCloseHandle(hrec);
3245     MsiViewClose(hview);
3246     MsiCloseHandle(hview);
3247
3248     /* check that the property was added */
3249     r = package_from_db(hdb, &hpkg);
3250     if (r == ERROR_INSTALL_PACKAGE_REJECTED)
3251     {
3252         skip("Not enough rights to perform tests\n");
3253         goto error;
3254     }
3255     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
3256
3257     sz = MAX_PATH;
3258     r = MsiGetProperty(hpkg, "prop", buffer, &sz);
3259     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3260     ok(!lstrcmp(buffer, "val"), "Expected val, got %s\n", buffer);
3261
3262     MsiCloseHandle(hpkg);
3263
3264 error:
3265     MsiCloseHandle(hdb);
3266     DeleteFile(msifile);
3267     DeleteFile(mstfile);
3268 }
3269
3270 struct join_res
3271 {
3272     const CHAR one[MAX_PATH];
3273     const CHAR two[MAX_PATH];
3274 };
3275
3276 struct join_res_4col
3277 {
3278     const CHAR one[MAX_PATH];
3279     const CHAR two[MAX_PATH];
3280     const CHAR three[MAX_PATH];
3281     const CHAR four[MAX_PATH];
3282 };
3283
3284 struct join_res_uint
3285 {
3286     UINT one;
3287     UINT two;
3288     UINT three;
3289     UINT four;
3290     UINT five;
3291     UINT six;
3292 };
3293
3294 static const struct join_res join_res_first[] =
3295 {
3296     { "alveolar", "procerus" },
3297     { "septum", "procerus" },
3298     { "septum", "nasalis" },
3299     { "ramus", "nasalis" },
3300     { "malar", "mentalis" },
3301 };
3302
3303 static const struct join_res join_res_second[] =
3304 {
3305     { "nasal", "septum" },
3306     { "mandible", "ramus" },
3307 };
3308
3309 static const struct join_res join_res_third[] =
3310 {
3311     { "msvcp.dll", "abcdefgh" },
3312     { "msvcr.dll", "ijklmnop" },
3313 };
3314
3315 static const struct join_res join_res_fourth[] =
3316 {
3317     { "msvcp.dll.01234", "single.dll.31415" },
3318 };
3319
3320 static const struct join_res join_res_fifth[] =
3321 {
3322     { "malar", "procerus" },
3323 };
3324
3325 static const struct join_res join_res_sixth[] =
3326 {
3327     { "malar", "procerus" },
3328     { "malar", "procerus" },
3329     { "malar", "nasalis" },
3330     { "malar", "nasalis" },
3331     { "malar", "nasalis" },
3332     { "malar", "mentalis" },
3333 };
3334
3335 static const struct join_res join_res_seventh[] =
3336 {
3337     { "malar", "nasalis" },
3338     { "malar", "nasalis" },
3339     { "malar", "nasalis" },
3340 };
3341
3342 static const struct join_res_4col join_res_eighth[] =
3343 {
3344     { "msvcp.dll", "msvcp.dll.01234", "msvcp.dll.01234", "abcdefgh" },
3345     { "msvcr.dll", "msvcr.dll.56789", "msvcp.dll.01234", "abcdefgh" },
3346     { "msvcp.dll", "msvcp.dll.01234", "msvcr.dll.56789", "ijklmnop" },
3347     { "msvcr.dll", "msvcr.dll.56789", "msvcr.dll.56789", "ijklmnop" },
3348     { "msvcp.dll", "msvcp.dll.01234", "single.dll.31415", "msvcp.dll" },
3349     { "msvcr.dll", "msvcr.dll.56789", "single.dll.31415", "msvcp.dll" },
3350 };
3351
3352 static const struct join_res_uint join_res_ninth[] =
3353 {
3354     { 1, 2, 3, 4, 7, 8 },
3355     { 1, 2, 5, 6, 7, 8 },
3356     { 1, 2, 3, 4, 9, 10 },
3357     { 1, 2, 5, 6, 9, 10 },
3358     { 1, 2, 3, 4, 11, 12 },
3359     { 1, 2, 5, 6, 11, 12 },
3360 };
3361
3362 static void test_join(void)
3363 {
3364     MSIHANDLE hdb, hview, hrec;
3365     LPCSTR query;
3366     CHAR buf[MAX_PATH];
3367     UINT r, count;
3368     DWORD size, i;
3369     BOOL data_correct;
3370
3371     hdb = create_db();
3372     ok( hdb, "failed to create db\n");
3373
3374     r = create_component_table( hdb );
3375     ok( r == ERROR_SUCCESS, "cannot create Component table: %d\n", r );
3376
3377     r = add_component_entry( hdb, "'zygomatic', 'malar', 'INSTALLDIR', 0, '', ''" );
3378     ok( r == ERROR_SUCCESS, "cannot add component: %d\n", r );
3379
3380     r = add_component_entry( hdb, "'maxilla', 'alveolar', 'INSTALLDIR', 0, '', ''" );
3381     ok( r == ERROR_SUCCESS, "cannot add component: %d\n", r );
3382
3383     r = add_component_entry( hdb, "'nasal', 'septum', 'INSTALLDIR', 0, '', ''" );
3384     ok( r == ERROR_SUCCESS, "cannot add component: %d\n", r );
3385
3386     r = add_component_entry( hdb, "'mandible', 'ramus', 'INSTALLDIR', 0, '', ''" );
3387     ok( r == ERROR_SUCCESS, "cannot add component: %d\n", r );
3388
3389     r = create_feature_components_table( hdb );
3390     ok( r == ERROR_SUCCESS, "cannot create FeatureComponents table: %d\n", r );
3391
3392     r = add_feature_components_entry( hdb, "'procerus', 'maxilla'" );
3393     ok( r == ERROR_SUCCESS, "cannot add feature components: %d\n", r );
3394
3395     r = add_feature_components_entry( hdb, "'procerus', 'nasal'" );
3396     ok( r == ERROR_SUCCESS, "cannot add feature components: %d\n", r );
3397
3398     r = add_feature_components_entry( hdb, "'nasalis', 'nasal'" );
3399     ok( r == ERROR_SUCCESS, "cannot add feature components: %d\n", r );
3400
3401     r = add_feature_components_entry( hdb, "'nasalis', 'mandible'" );
3402     ok( r == ERROR_SUCCESS, "cannot add feature components: %d\n", r );
3403
3404     r = add_feature_components_entry( hdb, "'nasalis', 'notacomponent'" );
3405     ok( r == ERROR_SUCCESS, "cannot add feature components: %d\n", r );
3406
3407     r = add_feature_components_entry( hdb, "'mentalis', 'zygomatic'" );
3408     ok( r == ERROR_SUCCESS, "cannot add feature components: %d\n", r );
3409
3410     r = create_std_dlls_table( hdb );
3411     ok( r == ERROR_SUCCESS, "cannot create StdDlls table: %d\n", r );
3412
3413     r = add_std_dlls_entry( hdb, "'msvcp.dll', 'msvcp.dll.01234'" );
3414     ok( r == ERROR_SUCCESS, "cannot add std dlls: %d\n", r );
3415
3416     r = add_std_dlls_entry( hdb, "'msvcr.dll', 'msvcr.dll.56789'" );
3417     ok( r == ERROR_SUCCESS, "cannot add std dlls: %d\n", r );
3418
3419     r = create_binary_table( hdb );
3420     ok( r == ERROR_SUCCESS, "cannot create Binary table: %d\n", r );
3421
3422     r = add_binary_entry( hdb, "'msvcp.dll.01234', 'abcdefgh'" );
3423     ok( r == ERROR_SUCCESS, "cannot add binary: %d\n", r );
3424
3425     r = add_binary_entry( hdb, "'msvcr.dll.56789', 'ijklmnop'" );
3426     ok( r == ERROR_SUCCESS, "cannot add binary: %d\n", r );
3427
3428     r = add_binary_entry( hdb, "'single.dll.31415', 'msvcp.dll'" );
3429     ok( r == ERROR_SUCCESS, "cannot add binary: %d\n", r );
3430
3431     query = "CREATE TABLE `One` (`A` SHORT, `B` SHORT PRIMARY KEY `A`)";
3432     r = run_query( hdb, 0, query);
3433     ok(r == ERROR_SUCCESS, "cannot create table: %d\n", r );
3434
3435     query = "CREATE TABLE `Two` (`C` SHORT, `D` SHORT PRIMARY KEY `C`)";
3436     r = run_query( hdb, 0, query);
3437     ok(r == ERROR_SUCCESS, "cannot create table: %d\n", r );
3438
3439     query = "CREATE TABLE `Three` (`E` SHORT, `F` SHORT PRIMARY KEY `E`)";
3440     r = run_query( hdb, 0, query);
3441     ok(r == ERROR_SUCCESS, "cannot create table: %d\n", r );
3442
3443     query = "INSERT INTO `One` (`A`, `B`) VALUES (1, 2)";
3444     r = run_query( hdb, 0, query);
3445     ok(r == ERROR_SUCCESS, "cannot insert into table: %d\n", r );
3446
3447     query = "INSERT INTO `Two` (`C`, `D`) VALUES (3, 4)";
3448     r = run_query( hdb, 0, query);
3449     ok(r == ERROR_SUCCESS, "cannot insert into table: %d\n", r );
3450
3451     query = "INSERT INTO `Two` (`C`, `D`) VALUES (5, 6)";
3452     r = run_query( hdb, 0, query);
3453     ok(r == ERROR_SUCCESS, "cannot insert into table: %d\n", r );
3454
3455     query = "INSERT INTO `Three` (`E`, `F`) VALUES (7, 8)";
3456     r = run_query( hdb, 0, query);
3457     ok(r == ERROR_SUCCESS, "cannot insert into table: %d\n", r );
3458
3459     query = "INSERT INTO `Three` (`E`, `F`) VALUES (9, 10)";
3460     r = run_query( hdb, 0, query);
3461     ok(r == ERROR_SUCCESS, "cannot insert into table: %d\n", r );
3462
3463     query = "INSERT INTO `Three` (`E`, `F`) VALUES (11, 12)";
3464     r = run_query( hdb, 0, query);
3465     ok(r == ERROR_SUCCESS, "cannot insert into table: %d\n", r );
3466
3467     query = "CREATE TABLE `Four` (`G` SHORT, `H` SHORT PRIMARY KEY `G`)";
3468     r = run_query( hdb, 0, query);
3469     ok(r == ERROR_SUCCESS, "cannot create table: %d\n", r );
3470
3471     query = "CREATE TABLE `Five` (`I` SHORT, `J` SHORT PRIMARY KEY `I`)";
3472     r = run_query( hdb, 0, query);
3473     ok(r == ERROR_SUCCESS, "cannot create table: %d\n", r );
3474
3475     query = "INSERT INTO `Five` (`I`, `J`) VALUES (13, 14)";
3476     r = run_query( hdb, 0, query);
3477     ok(r == ERROR_SUCCESS, "cannot insert into table: %d\n", r );
3478
3479     query = "INSERT INTO `Five` (`I`, `J`) VALUES (15, 16)";
3480     r = run_query( hdb, 0, query);
3481     ok(r == ERROR_SUCCESS, "cannot insert into table: %d\n", r );
3482
3483     query = "SELECT `Component`.`ComponentId`, `FeatureComponents`.`Feature_` "
3484             "FROM `Component`, `FeatureComponents` "
3485             "WHERE `Component`.`Component` = `FeatureComponents`.`Component_` "
3486             "ORDER BY `Feature_`";
3487     r = MsiDatabaseOpenView(hdb, query, &hview);
3488     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3489
3490     r = MsiViewExecute(hview, 0);
3491     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3492
3493     i = 0;
3494     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3495     {
3496         count = MsiRecordGetFieldCount( hrec );
3497         ok( count == 2, "Expected 2 record fields, got %d\n", count );
3498
3499         size = MAX_PATH;
3500         r = MsiRecordGetString( hrec, 1, buf, &size );
3501         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3502         ok( !lstrcmp( buf, join_res_first[i].one ),
3503             "For (row %d, column 1) expected '%s', got %s\n", i, join_res_first[i].one, buf );
3504
3505         size = MAX_PATH;
3506         r = MsiRecordGetString( hrec, 2, buf, &size );
3507         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3508         ok( !lstrcmp( buf, join_res_first[i].two ),
3509             "For (row %d, column 2) expected '%s', got %s\n", i, join_res_first[i].two, buf );
3510
3511         i++;
3512         MsiCloseHandle(hrec);
3513     }
3514
3515     ok( i == 5, "Expected 5 rows, got %d\n", i );
3516     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3517
3518     MsiViewClose(hview);
3519     MsiCloseHandle(hview);
3520
3521     /* try a join without a WHERE condition */
3522     query = "SELECT `Component`.`ComponentId`, `FeatureComponents`.`Feature_` "
3523             "FROM `Component`, `FeatureComponents` ";
3524     r = MsiDatabaseOpenView(hdb, query, &hview);
3525     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3526
3527     r = MsiViewExecute(hview, 0);
3528     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3529
3530     i = 0;
3531     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3532     {
3533         i++;
3534         MsiCloseHandle(hrec);
3535     }
3536     ok( i == 24, "Expected 24 rows, got %d\n", i );
3537
3538     MsiViewClose(hview);
3539     MsiCloseHandle(hview);
3540
3541     query = "SELECT DISTINCT Component, ComponentId FROM FeatureComponents, Component "
3542             "WHERE FeatureComponents.Component_=Component.Component "
3543             "AND (Feature_='nasalis') ORDER BY Feature_";
3544     r = MsiDatabaseOpenView(hdb, query, &hview);
3545     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3546
3547     r = MsiViewExecute(hview, 0);
3548     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3549
3550     i = 0;
3551     data_correct = TRUE;
3552     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3553     {
3554         count = MsiRecordGetFieldCount( hrec );
3555         ok( count == 2, "Expected 2 record fields, got %d\n", count );
3556
3557         size = MAX_PATH;
3558         r = MsiRecordGetString( hrec, 1, buf, &size );
3559         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3560         if( lstrcmp( buf, join_res_second[i].one ))
3561             data_correct = FALSE;
3562
3563         size = MAX_PATH;
3564         r = MsiRecordGetString( hrec, 2, buf, &size );
3565         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3566         if( lstrcmp( buf, join_res_second[i].two ))
3567             data_correct = FALSE;
3568
3569         i++;
3570         MsiCloseHandle(hrec);
3571     }
3572
3573     ok( data_correct, "data returned in the wrong order\n");
3574
3575     ok( i == 2, "Expected 2 rows, got %d\n", i );
3576     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3577
3578     MsiViewClose(hview);
3579     MsiCloseHandle(hview);
3580
3581     query = "SELECT `StdDlls`.`File`, `Binary`.`Data` "
3582             "FROM `StdDlls`, `Binary` "
3583             "WHERE `StdDlls`.`Binary_` = `Binary`.`Name` "
3584             "ORDER BY `File`";
3585     r = MsiDatabaseOpenView(hdb, query, &hview);
3586     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3587
3588     r = MsiViewExecute(hview, 0);
3589     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3590
3591     i = 0;
3592     data_correct = TRUE;
3593     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3594     {
3595         count = MsiRecordGetFieldCount( hrec );
3596         ok( count == 2, "Expected 2 record fields, got %d\n", count );
3597
3598         size = MAX_PATH;
3599         r = MsiRecordGetString( hrec, 1, buf, &size );
3600         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3601         if( lstrcmp( buf, join_res_third[i].one ) )
3602             data_correct = FALSE;
3603
3604         size = MAX_PATH;
3605         r = MsiRecordGetString( hrec, 2, buf, &size );
3606         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3607         if( lstrcmp( buf, join_res_third[i].two ) )
3608             data_correct = FALSE;
3609
3610         i++;
3611         MsiCloseHandle(hrec);
3612     }
3613     ok( data_correct, "data returned in the wrong order\n");
3614
3615     ok( i == 2, "Expected 2 rows, got %d\n", i );
3616
3617     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3618
3619     MsiViewClose(hview);
3620     MsiCloseHandle(hview);
3621
3622     query = "SELECT `StdDlls`.`Binary_`, `Binary`.`Name` "
3623             "FROM `StdDlls`, `Binary` "
3624             "WHERE `StdDlls`.`File` = `Binary`.`Data` "
3625             "ORDER BY `Name`";
3626     r = MsiDatabaseOpenView(hdb, query, &hview);
3627     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3628
3629     r = MsiViewExecute(hview, 0);
3630     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3631
3632     i = 0;
3633     data_correct = TRUE;
3634     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3635     {
3636         count = MsiRecordGetFieldCount( hrec );
3637         ok( count == 2, "Expected 2 record fields, got %d\n", count );
3638
3639         size = MAX_PATH;
3640         r = MsiRecordGetString( hrec, 1, buf, &size );
3641         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3642         if( lstrcmp( buf, join_res_fourth[i].one ))
3643             data_correct = FALSE;
3644
3645         size = MAX_PATH;
3646         r = MsiRecordGetString( hrec, 2, buf, &size );
3647         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3648         if( lstrcmp( buf, join_res_fourth[i].two ))
3649             data_correct = FALSE;
3650
3651         i++;
3652         MsiCloseHandle(hrec);
3653     }
3654     ok( data_correct, "data returned in the wrong order\n");
3655
3656     ok( i == 1, "Expected 1 rows, got %d\n", i );
3657     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3658
3659     MsiViewClose(hview);
3660     MsiCloseHandle(hview);
3661
3662     query = "SELECT `Component`.`ComponentId`, `FeatureComponents`.`Feature_` "
3663             "FROM `Component`, `FeatureComponents` "
3664             "WHERE `Component`.`Component` = 'zygomatic' "
3665             "AND `FeatureComponents`.`Component_` = 'maxilla' "
3666             "ORDER BY `Feature_`";
3667     r = MsiDatabaseOpenView(hdb, query, &hview);
3668     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3669
3670     r = MsiViewExecute(hview, 0);
3671     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3672
3673     i = 0;
3674     data_correct = TRUE;
3675     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3676     {
3677         count = MsiRecordGetFieldCount( hrec );
3678         ok( count == 2, "Expected 2 record fields, got %d\n", count );
3679
3680         size = MAX_PATH;
3681         r = MsiRecordGetString( hrec, 1, buf, &size );
3682         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3683         if( lstrcmp( buf, join_res_fifth[i].one ))
3684             data_correct = FALSE;
3685
3686         size = MAX_PATH;
3687         r = MsiRecordGetString( hrec, 2, buf, &size );
3688         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3689         if( lstrcmp( buf, join_res_fifth[i].two ))
3690             data_correct = FALSE;
3691
3692         i++;
3693         MsiCloseHandle(hrec);
3694     }
3695     ok( data_correct, "data returned in the wrong order\n");
3696
3697     ok( i == 1, "Expected 1 rows, got %d\n", i );
3698     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3699
3700     MsiViewClose(hview);
3701     MsiCloseHandle(hview);
3702
3703     query = "SELECT `Component`.`ComponentId`, `FeatureComponents`.`Feature_` "
3704             "FROM `Component`, `FeatureComponents` "
3705             "WHERE `Component` = 'zygomatic' "
3706             "ORDER BY `Feature_`";
3707     r = MsiDatabaseOpenView(hdb, query, &hview);
3708     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3709
3710     r = MsiViewExecute(hview, 0);
3711     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3712
3713     i = 0;
3714     data_correct = TRUE;
3715     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3716     {
3717         count = MsiRecordGetFieldCount( hrec );
3718         ok( count == 2, "Expected 2 record fields, got %d\n", count );
3719
3720         size = MAX_PATH;
3721         r = MsiRecordGetString( hrec, 1, buf, &size );
3722         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3723         if( lstrcmp( buf, join_res_sixth[i].one ))
3724             data_correct = FALSE;
3725
3726         size = MAX_PATH;
3727         r = MsiRecordGetString( hrec, 2, buf, &size );
3728         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3729         if( lstrcmp( buf, join_res_sixth[i].two ))
3730             data_correct = FALSE;
3731
3732         i++;
3733         MsiCloseHandle(hrec);
3734     }
3735     ok( data_correct, "data returned in the wrong order\n");
3736
3737     ok( i == 6, "Expected 6 rows, got %d\n", i );
3738     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3739
3740     MsiViewClose(hview);
3741     MsiCloseHandle(hview);
3742
3743     query = "SELECT `Component`.`ComponentId`, `FeatureComponents`.`Feature_` "
3744             "FROM `Component`, `FeatureComponents` "
3745             "WHERE `Component` = 'zygomatic' "
3746             "AND `Feature_` = 'nasalis' "
3747             "ORDER BY `Feature_`";
3748     r = MsiDatabaseOpenView(hdb, query, &hview);
3749     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3750
3751     r = MsiViewExecute(hview, 0);
3752     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3753
3754     i = 0;
3755     data_correct = TRUE;
3756     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3757     {
3758         count = MsiRecordGetFieldCount( hrec );
3759         ok( count == 2, "Expected 2 record fields, got %d\n", count );
3760
3761         size = MAX_PATH;
3762         r = MsiRecordGetString( hrec, 1, buf, &size );
3763         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3764         if( lstrcmp( buf, join_res_seventh[i].one ))
3765             data_correct = FALSE;
3766
3767         size = MAX_PATH;
3768         r = MsiRecordGetString( hrec, 2, buf, &size );
3769         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3770         if( lstrcmp( buf, join_res_seventh[i].two ))
3771             data_correct = FALSE;
3772
3773         i++;
3774         MsiCloseHandle(hrec);
3775     }
3776
3777     ok( data_correct, "data returned in the wrong order\n");
3778     ok( i == 3, "Expected 3 rows, got %d\n", i );
3779     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3780
3781     MsiViewClose(hview);
3782     MsiCloseHandle(hview);
3783
3784     query = "SELECT `StdDlls`.`File`, `Binary`.`Data` "
3785             "FROM `StdDlls`, `Binary` ";
3786     r = MsiDatabaseOpenView(hdb, query, &hview);
3787     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3788
3789     r = MsiViewExecute(hview, 0);
3790     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3791
3792     i = 0;
3793     data_correct = TRUE;
3794     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3795     {
3796         count = MsiRecordGetFieldCount( hrec );
3797         ok( count == 2, "Expected 2 record fields, got %d\n", count );
3798
3799         size = MAX_PATH;
3800         r = MsiRecordGetString( hrec, 1, buf, &size );
3801         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3802         if( lstrcmp( buf, join_res_eighth[i].one ))
3803             data_correct = FALSE;
3804
3805         size = MAX_PATH;
3806         r = MsiRecordGetString( hrec, 2, buf, &size );
3807         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3808         if( lstrcmp( buf, join_res_eighth[i].four ))
3809             data_correct = FALSE;
3810
3811         i++;
3812         MsiCloseHandle(hrec);
3813     }
3814
3815     ok( data_correct, "data returned in the wrong order\n");
3816     ok( i == 6, "Expected 6 rows, got %d\n", i );
3817     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3818
3819     MsiViewClose(hview);
3820     MsiCloseHandle(hview);
3821
3822     query = "SELECT * FROM `StdDlls`, `Binary` ";
3823     r = MsiDatabaseOpenView(hdb, query, &hview);
3824     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3825
3826     r = MsiViewExecute(hview, 0);
3827     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3828
3829     i = 0;
3830     data_correct = TRUE;
3831     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3832     {
3833         count = MsiRecordGetFieldCount( hrec );
3834         ok( count == 4, "Expected 4 record fields, got %d\n", count );
3835
3836         size = MAX_PATH;
3837         r = MsiRecordGetString( hrec, 1, buf, &size );
3838         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3839         if( lstrcmp( buf, join_res_eighth[i].one ))
3840             data_correct = FALSE;
3841
3842         size = MAX_PATH;
3843         r = MsiRecordGetString( hrec, 2, buf, &size );
3844         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3845         if( lstrcmp( buf, join_res_eighth[i].two ))
3846             data_correct = FALSE;
3847
3848         size = MAX_PATH;
3849         r = MsiRecordGetString( hrec, 3, buf, &size );
3850         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3851         if( lstrcmp( buf, join_res_eighth[i].three ))
3852             data_correct = FALSE;
3853
3854         size = MAX_PATH;
3855         r = MsiRecordGetString( hrec, 4, buf, &size );
3856         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3857         if( lstrcmp( buf, join_res_eighth[i].four ))
3858             data_correct = FALSE;
3859
3860         i++;
3861         MsiCloseHandle(hrec);
3862     }
3863     ok( data_correct, "data returned in the wrong order\n");
3864
3865     ok( i == 6, "Expected 6 rows, got %d\n", i );
3866     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3867
3868     MsiViewClose(hview);
3869     MsiCloseHandle(hview);
3870
3871     query = "SELECT * FROM `One`, `Two`, `Three` ";
3872     r = MsiDatabaseOpenView(hdb, query, &hview);
3873     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3874
3875     r = MsiViewExecute(hview, 0);
3876     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3877
3878     i = 0;
3879     data_correct = TRUE;
3880     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3881     {
3882         count = MsiRecordGetFieldCount( hrec );
3883         ok( count == 6, "Expected 6 record fields, got %d\n", count );
3884
3885         r = MsiRecordGetInteger( hrec, 1 );
3886         if( r != join_res_ninth[i].one )
3887             data_correct = FALSE;
3888
3889         r = MsiRecordGetInteger( hrec, 2 );
3890         if( r != join_res_ninth[i].two )
3891             data_correct = FALSE;
3892
3893         r = MsiRecordGetInteger( hrec, 3 );
3894         if( r != join_res_ninth[i].three )
3895             data_correct = FALSE;
3896
3897         r = MsiRecordGetInteger( hrec, 4 );
3898         if( r != join_res_ninth[i].four )
3899             data_correct = FALSE;
3900
3901         r = MsiRecordGetInteger( hrec, 5 );
3902         if( r != join_res_ninth[i].five )
3903             data_correct = FALSE;
3904
3905         r = MsiRecordGetInteger( hrec, 6);
3906         if( r != join_res_ninth[i].six )
3907             data_correct = FALSE;
3908
3909         i++;
3910         MsiCloseHandle(hrec);
3911     }
3912     ok( data_correct, "data returned in the wrong order\n");
3913
3914     ok( i == 6, "Expected 6 rows, got %d\n", i );
3915     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3916
3917     MsiViewClose(hview);
3918     MsiCloseHandle(hview);
3919
3920     query = "SELECT * FROM `Four`, `Five`";
3921     r = MsiDatabaseOpenView(hdb, query, &hview);
3922     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3923
3924     r = MsiViewExecute(hview, 0);
3925     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3926
3927     r = MsiViewFetch(hview, &hrec);
3928     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
3929
3930     MsiViewClose(hview);
3931     MsiCloseHandle(hview);
3932
3933     query = "SELECT * FROM `Nonexistent`, `One`";
3934     r = MsiDatabaseOpenView(hdb, query, &hview);
3935     ok( r == ERROR_BAD_QUERY_SYNTAX,
3936         "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r );
3937
3938     /* try updating a row in a join table */
3939     query = "SELECT `Component`.`ComponentId`, `FeatureComponents`.`Feature_` "
3940             "FROM `Component`, `FeatureComponents` "
3941             "WHERE `Component`.`Component` = `FeatureComponents`.`Component_` "
3942             "ORDER BY `Feature_`";
3943     r = MsiDatabaseOpenView(hdb, query, &hview);
3944     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3945
3946     r = MsiViewExecute(hview, 0);
3947     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3948
3949     r = MsiViewFetch(hview, &hrec);
3950     ok( r == ERROR_SUCCESS, "failed to fetch view: %d\n", r );
3951
3952     r = MsiRecordSetString( hrec, 1, "epicranius" );
3953     ok( r == ERROR_SUCCESS, "failed to set string: %d\n", r );
3954
3955     r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
3956     ok( r == ERROR_SUCCESS, "failed to update row: %d\n", r );
3957
3958     /* try another valid operation for joins */
3959     r = MsiViewModify(hview, MSIMODIFY_REFRESH, hrec);
3960     todo_wine ok( r == ERROR_SUCCESS, "failed to refresh row: %d\n", r );
3961
3962     /* try an invalid operation for joins */
3963     r = MsiViewModify(hview, MSIMODIFY_DELETE, hrec);
3964     ok( r == ERROR_FUNCTION_FAILED, "unexpected result: %d\n", r );
3965
3966     r = MsiRecordSetString( hrec, 2, "epicranius" );
3967     ok( r == ERROR_SUCCESS, "failed to set string: %d\n", r );
3968
3969     /* primary key cannot be updated */
3970     r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
3971     ok( r == ERROR_FUNCTION_FAILED, "failed to update row: %d\n", r );
3972
3973     MsiCloseHandle(hrec);
3974     MsiViewClose(hview);
3975     MsiCloseHandle(hview);
3976
3977     r = MsiDatabaseOpenView(hdb, query, &hview);
3978     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
3979
3980     r = MsiViewExecute(hview, 0);
3981     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
3982
3983     r = MsiViewFetch(hview, &hrec);
3984     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
3985
3986     size = MAX_PATH;
3987     r = MsiRecordGetString( hrec, 1, buf, &size );
3988     ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3989     ok( !lstrcmp( buf, "epicranius" ), "expected 'epicranius', got %s\n", buf );
3990
3991     MsiCloseHandle(hrec);
3992     MsiViewClose(hview);
3993     MsiCloseHandle(hview);
3994
3995     MsiCloseHandle(hdb);
3996     DeleteFile(msifile);
3997 }
3998
3999 static void test_temporary_table(void)
4000 {
4001     MSICONDITION cond;
4002     MSIHANDLE hdb = 0, view = 0, rec;
4003     const char *query;
4004     UINT r;
4005     char buf[0x10];
4006     DWORD sz;
4007
4008     cond = MsiDatabaseIsTablePersistent(0, NULL);
4009     ok( cond == MSICONDITION_ERROR, "wrong return condition\n");
4010
4011     hdb = create_db();
4012     ok( hdb, "failed to create db\n");
4013
4014     cond = MsiDatabaseIsTablePersistent(hdb, NULL);
4015     ok( cond == MSICONDITION_ERROR, "wrong return condition\n");
4016
4017     cond = MsiDatabaseIsTablePersistent(hdb, "_Tables");
4018     ok( cond == MSICONDITION_NONE, "wrong return condition\n");
4019
4020     cond = MsiDatabaseIsTablePersistent(hdb, "_Columns");
4021     ok( cond == MSICONDITION_NONE, "wrong return condition\n");
4022
4023     cond = MsiDatabaseIsTablePersistent(hdb, "_Storages");
4024     ok( cond == MSICONDITION_NONE, "wrong return condition\n");
4025
4026     cond = MsiDatabaseIsTablePersistent(hdb, "_Streams");
4027     ok( cond == MSICONDITION_NONE, "wrong return condition\n");
4028
4029     query = "CREATE TABLE `P` ( `B` SHORT NOT NULL, `C` CHAR(255) PRIMARY KEY `C`)";
4030     r = run_query(hdb, 0, query);
4031     ok(r == ERROR_SUCCESS, "failed to add table\n");
4032
4033     cond = MsiDatabaseIsTablePersistent(hdb, "P");
4034     ok( cond == MSICONDITION_TRUE, "wrong return condition\n");
4035
4036     query = "CREATE TABLE `P2` ( `B` SHORT NOT NULL, `C` CHAR(255) PRIMARY KEY `C`) HOLD";
4037     r = run_query(hdb, 0, query);
4038     ok(r == ERROR_SUCCESS, "failed to add table\n");
4039
4040     cond = MsiDatabaseIsTablePersistent(hdb, "P2");
4041     ok( cond == MSICONDITION_TRUE, "wrong return condition\n");
4042
4043     query = "CREATE TABLE `T` ( `B` SHORT NOT NULL TEMPORARY, `C` CHAR(255) TEMPORARY PRIMARY KEY `C`) HOLD";
4044     r = run_query(hdb, 0, query);
4045     ok(r == ERROR_SUCCESS, "failed to add table\n");
4046
4047     cond = MsiDatabaseIsTablePersistent(hdb, "T");
4048     ok( cond == MSICONDITION_FALSE, "wrong return condition\n");
4049
4050     query = "CREATE TABLE `T2` ( `B` SHORT NOT NULL TEMPORARY, `C` CHAR(255) TEMPORARY PRIMARY KEY `C`)";
4051     r = run_query(hdb, 0, query);
4052     ok(r == ERROR_SUCCESS, "failed to add table\n");
4053
4054     query = "SELECT * FROM `T2`";
4055     r = MsiDatabaseOpenView(hdb, query, &view);
4056     ok(r == ERROR_BAD_QUERY_SYNTAX,
4057        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
4058
4059     cond = MsiDatabaseIsTablePersistent(hdb, "T2");
4060     ok( cond == MSICONDITION_NONE, "wrong return condition\n");
4061
4062     query = "CREATE TABLE `T3` ( `B` SHORT NOT NULL TEMPORARY, `C` CHAR(255) PRIMARY KEY `C`)";
4063     r = run_query(hdb, 0, query);
4064     ok(r == ERROR_SUCCESS, "failed to add table\n");
4065
4066     cond = MsiDatabaseIsTablePersistent(hdb, "T3");
4067     ok( cond == MSICONDITION_TRUE, "wrong return condition\n");
4068
4069     query = "CREATE TABLE `T4` ( `B` SHORT NOT NULL, `C` CHAR(255) TEMPORARY PRIMARY KEY `C`)";
4070     r = run_query(hdb, 0, query);
4071     ok(r == ERROR_FUNCTION_FAILED, "failed to add table\n");
4072
4073     cond = MsiDatabaseIsTablePersistent(hdb, "T4");
4074     ok( cond == MSICONDITION_NONE, "wrong return condition\n");
4075
4076     query = "CREATE TABLE `T5` ( `B` SHORT NOT NULL TEMP, `C` CHAR(255) TEMP PRIMARY KEY `C`) HOLD";
4077     r = run_query(hdb, 0, query);
4078     ok(r == ERROR_BAD_QUERY_SYNTAX, "failed to add table\n");
4079
4080     query = "select * from `T`";
4081     r = MsiDatabaseOpenView(hdb, query, &view);
4082     ok(r == ERROR_SUCCESS, "failed to query table\n");
4083     r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
4084     ok(r == ERROR_SUCCESS, "failed to get column info\n");
4085
4086     sz = sizeof buf;
4087     r = MsiRecordGetString(rec, 1, buf, &sz);
4088     ok(r == ERROR_SUCCESS, "failed to get string\n");
4089     ok( 0 == strcmp("G255", buf), "wrong column type\n");
4090
4091     sz = sizeof buf;
4092     r = MsiRecordGetString(rec, 2, buf, &sz);
4093     ok(r == ERROR_SUCCESS, "failed to get string\n");
4094     ok( 0 == strcmp("j2", buf), "wrong column type\n");
4095
4096     MsiCloseHandle( rec );
4097     MsiViewClose( view );
4098     MsiCloseHandle( view );
4099
4100     /* query the table data */
4101     rec = 0;
4102     r = do_query(hdb, "select * from `_Tables` where `Name` = 'T'", &rec);
4103     ok( r == ERROR_SUCCESS, "temporary table exists in _Tables\n");
4104     MsiCloseHandle( rec );
4105
4106     /* query the column data */
4107     rec = 0;
4108     r = do_query(hdb, "select * from `_Columns` where `Table` = 'T' AND `Name` = 'B'", &rec);
4109     ok( r == ERROR_NO_MORE_ITEMS, "temporary table exists in _Columns\n");
4110     if (rec) MsiCloseHandle( rec );
4111
4112     r = do_query(hdb, "select * from `_Columns` where `Table` = 'T' AND `Name` = 'C'", &rec);
4113     ok( r == ERROR_NO_MORE_ITEMS, "temporary table exists in _Columns\n");
4114     if (rec) MsiCloseHandle( rec );
4115
4116     MsiCloseHandle( hdb );
4117
4118     DeleteFile(msifile);
4119 }
4120
4121 static void test_alter(void)
4122 {
4123     MSICONDITION cond;
4124     MSIHANDLE hdb = 0;
4125     const char *query;
4126     UINT r;
4127
4128     hdb = create_db();
4129     ok( hdb, "failed to create db\n");
4130
4131     query = "CREATE TABLE `T` ( `B` SHORT NOT NULL TEMPORARY, `C` CHAR(255) TEMPORARY PRIMARY KEY `C`) HOLD";
4132     r = run_query(hdb, 0, query);
4133     ok(r == ERROR_SUCCESS, "failed to add table\n");
4134
4135     cond = MsiDatabaseIsTablePersistent(hdb, "T");
4136     ok( cond == MSICONDITION_FALSE, "wrong return condition\n");
4137
4138     query = "ALTER TABLE `T` HOLD";
4139     r = run_query(hdb, 0, query);
4140     ok(r == ERROR_SUCCESS, "failed to hold table %d\n", r);
4141
4142     query = "ALTER TABLE `T` FREE";
4143     r = run_query(hdb, 0, query);
4144     ok(r == ERROR_SUCCESS, "failed to free table\n");
4145
4146     query = "ALTER TABLE `T` FREE";
4147     r = run_query(hdb, 0, query);
4148     ok(r == ERROR_SUCCESS, "failed to free table\n");
4149
4150     query = "ALTER TABLE `T` FREE";
4151     r = run_query(hdb, 0, query);
4152     ok(r == ERROR_BAD_QUERY_SYNTAX, "failed to free table\n");
4153
4154     query = "ALTER TABLE `T` HOLD";
4155     r = run_query(hdb, 0, query);
4156     ok(r == ERROR_BAD_QUERY_SYNTAX, "failed to hold table %d\n", r);
4157
4158     /* table T is removed */
4159     query = "SELECT * FROM `T`";
4160     r = run_query(hdb, 0, query);
4161     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
4162
4163     /* create the table again */
4164     query = "CREATE TABLE `U` ( `A` INTEGER, `B` INTEGER PRIMARY KEY `B`)";
4165     r = run_query(hdb, 0, query);
4166     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4167
4168     /* up the ref count */
4169     query = "ALTER TABLE `U` HOLD";
4170     r = run_query(hdb, 0, query);
4171     ok(r == ERROR_SUCCESS, "failed to free table\n");
4172
4173     /* add column, no data type */
4174     query = "ALTER TABLE `U` ADD `C`";
4175     r = run_query(hdb, 0, query);
4176     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
4177
4178     query = "ALTER TABLE `U` ADD `C` INTEGER";
4179     r = run_query(hdb, 0, query);
4180     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4181
4182     /* add column C again */
4183     query = "ALTER TABLE `U` ADD `C` INTEGER";
4184     r = run_query(hdb, 0, query);
4185     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
4186
4187     query = "ALTER TABLE `U` ADD `D` INTEGER TEMPORARY";
4188     r = run_query(hdb, 0, query);
4189     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4190
4191     query = "INSERT INTO `U` ( `A`, `B`, `C`, `D` ) VALUES ( 1, 2, 3, 4 )";
4192     r = run_query(hdb, 0, query);
4193     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4194
4195     query = "ALTER TABLE `U` ADD `D` INTEGER TEMPORARY HOLD";
4196     r = run_query(hdb, 0, query);
4197     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
4198
4199     query = "INSERT INTO `U` ( `A`, `B`, `C`, `D` ) VALUES ( 5, 6, 7, 8 )";
4200     r = run_query(hdb, 0, query);
4201     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4202
4203     query = "SELECT * FROM `U` WHERE `D` = 8";
4204     r = run_query(hdb, 0, query);
4205     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4206
4207     query = "ALTER TABLE `U` ADD `D` INTEGER TEMPORARY FREE";
4208     r = run_query(hdb, 0, query);
4209     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
4210
4211     query = "ALTER COLUMN `D` FREE";
4212     r = run_query(hdb, 0, query);
4213     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
4214
4215     /* drop the ref count */
4216     query = "ALTER TABLE `U` FREE";
4217     r = run_query(hdb, 0, query);
4218     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4219
4220     /* table is not empty */
4221     query = "SELECT * FROM `U`";
4222     r = run_query(hdb, 0, query);
4223     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4224
4225     /* column D is removed */
4226     query = "SELECT * FROM `U` WHERE `D` = 8";
4227     r = run_query(hdb, 0, query);
4228     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
4229
4230     query = "INSERT INTO `U` ( `A`, `B`, `C`, `D` ) VALUES ( 9, 10, 11, 12 )";
4231     r = run_query(hdb, 0, query);
4232     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
4233
4234     /* add the column again */
4235     query = "ALTER TABLE `U` ADD `E` INTEGER TEMPORARY HOLD";
4236     r = run_query(hdb, 0, query);
4237     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4238
4239     /* up the ref count */
4240     query = "ALTER TABLE `U` HOLD";
4241     r = run_query(hdb, 0, query);
4242     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4243
4244     query = "INSERT INTO `U` ( `A`, `B`, `C`, `E` ) VALUES ( 13, 14, 15, 16 )";
4245     r = run_query(hdb, 0, query);
4246     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4247
4248     query = "SELECT * FROM `U` WHERE `E` = 16";
4249     r = run_query(hdb, 0, query);
4250     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4251
4252     /* drop the ref count */
4253     query = "ALTER TABLE `U` FREE";
4254     r = run_query(hdb, 0, query);
4255     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4256
4257     query = "INSERT INTO `U` ( `A`, `B`, `C`, `E` ) VALUES ( 17, 18, 19, 20 )";
4258     r = run_query(hdb, 0, query);
4259     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4260
4261     query = "SELECT * FROM `U` WHERE `E` = 20";
4262     r = run_query(hdb, 0, query);
4263     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4264
4265     /* drop the ref count */
4266     query = "ALTER TABLE `U` FREE";
4267     r = run_query(hdb, 0, query);
4268     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4269
4270     /* table still exists */
4271     query = "SELECT * FROM `U`";
4272     r = run_query(hdb, 0, query);
4273     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4274
4275     /* col E is removed */
4276     query = "SELECT * FROM `U` WHERE `E` = 20";
4277     r = run_query(hdb, 0, query);
4278     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
4279
4280     query = "INSERT INTO `U` ( `A`, `B`, `C`, `E` ) VALUES ( 20, 21, 22, 23 )";
4281     r = run_query(hdb, 0, query);
4282     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
4283
4284     /* drop the ref count once more */
4285     query = "ALTER TABLE `U` FREE";
4286     r = run_query(hdb, 0, query);
4287     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4288
4289     /* table still exists */
4290     query = "SELECT * FROM `U`";
4291     r = run_query(hdb, 0, query);
4292     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4293
4294     MsiCloseHandle( hdb );
4295     DeleteFile(msifile);
4296 }
4297
4298 static void test_integers(void)
4299 {
4300     MSIHANDLE hdb = 0, view = 0, rec = 0;
4301     DWORD count, i;
4302     const char *query;
4303     UINT r;
4304
4305     /* just MsiOpenDatabase should not create a file */
4306     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
4307     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
4308
4309     /* create a table */
4310     query = "CREATE TABLE `integers` ( "
4311             "`one` SHORT, `two` INT, `three` INTEGER, `four` LONG, "
4312             "`five` SHORT NOT NULL, `six` INT NOT NULL, "
4313             "`seven` INTEGER NOT NULL, `eight` LONG NOT NULL "
4314             "PRIMARY KEY `one`)";
4315     r = MsiDatabaseOpenView(hdb, query, &view);
4316     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
4317     r = MsiViewExecute(view, 0);
4318     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
4319     r = MsiViewClose(view);
4320     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4321     r = MsiCloseHandle(view);
4322     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4323
4324     query = "SELECT * FROM `integers`";
4325     r = MsiDatabaseOpenView(hdb, query, &view);
4326     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4327
4328     r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec);
4329     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4330     count = MsiRecordGetFieldCount(rec);
4331     ok(count == 8, "Expected 8, got %d\n", count);
4332     ok(check_record(rec, 1, "one"), "Expected one\n");
4333     ok(check_record(rec, 2, "two"), "Expected two\n");
4334     ok(check_record(rec, 3, "three"), "Expected three\n");
4335     ok(check_record(rec, 4, "four"), "Expected four\n");
4336     ok(check_record(rec, 5, "five"), "Expected five\n");
4337     ok(check_record(rec, 6, "six"), "Expected six\n");
4338     ok(check_record(rec, 7, "seven"), "Expected seven\n");
4339     ok(check_record(rec, 8, "eight"), "Expected eight\n");
4340     MsiCloseHandle(rec);
4341
4342     r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
4343     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4344     count = MsiRecordGetFieldCount(rec);
4345     ok(count == 8, "Expected 8, got %d\n", count);
4346     ok(check_record(rec, 1, "I2"), "Expected I2\n");
4347     ok(check_record(rec, 2, "I2"), "Expected I2\n");
4348     ok(check_record(rec, 3, "I2"), "Expected I2\n");
4349     ok(check_record(rec, 4, "I4"), "Expected I4\n");
4350     ok(check_record(rec, 5, "i2"), "Expected i2\n");
4351     ok(check_record(rec, 6, "i2"), "Expected i2\n");
4352     ok(check_record(rec, 7, "i2"), "Expected i2\n");
4353     ok(check_record(rec, 8, "i4"), "Expected i4\n");
4354     MsiCloseHandle(rec);
4355
4356     MsiViewClose(view);
4357     MsiCloseHandle(view);
4358
4359     /* insert values into it, NULL where NOT NULL is specified */
4360     query = "INSERT INTO `integers` ( `one`, `two`, `three`, `four`, `five`, `six`, `seven`, `eight` )"
4361         "VALUES('', '', '', '', '', '', '', '')";
4362     r = MsiDatabaseOpenView(hdb, query, &view);
4363     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4364     r = MsiViewExecute(view, 0);
4365     ok(r == ERROR_FUNCTION_FAILED, "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
4366
4367     MsiViewClose(view);
4368     MsiCloseHandle(view);
4369
4370     query = "SELECT * FROM `integers`";
4371     r = do_query(hdb, query, &rec);
4372     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
4373
4374     r = MsiRecordGetFieldCount(rec);
4375     ok(r == -1, "record count wrong: %d\n", r);
4376
4377     MsiCloseHandle(rec);
4378
4379     /* insert legitimate values into it */
4380     query = "INSERT INTO `integers` ( `one`, `two`, `three`, `four`, `five`, `six`, `seven`, `eight` )"
4381         "VALUES('', '2', '', '4', '5', '6', '7', '8')";
4382     r = MsiDatabaseOpenView(hdb, query, &view);
4383     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4384     r = MsiViewExecute(view, 0);
4385     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4386
4387     query = "SELECT * FROM `integers`";
4388     r = do_query(hdb, query, &rec);
4389     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4390
4391     r = MsiRecordGetFieldCount(rec);
4392     ok(r == 8, "record count wrong: %d\n", r);
4393
4394     i = MsiRecordGetInteger(rec, 1);
4395     ok(i == MSI_NULL_INTEGER, "Expected MSI_NULL_INTEGER, got %d\n", i);
4396     i = MsiRecordGetInteger(rec, 3);
4397     ok(i == MSI_NULL_INTEGER, "Expected MSI_NULL_INTEGER, got %d\n", i);
4398     i = MsiRecordGetInteger(rec, 2);
4399     ok(i == 2, "Expected 2, got %d\n", i);
4400     i = MsiRecordGetInteger(rec, 4);
4401     ok(i == 4, "Expected 4, got %d\n", i);
4402     i = MsiRecordGetInteger(rec, 5);
4403     ok(i == 5, "Expected 5, got %d\n", i);
4404     i = MsiRecordGetInteger(rec, 6);
4405     ok(i == 6, "Expected 6, got %d\n", i);
4406     i = MsiRecordGetInteger(rec, 7);
4407     ok(i == 7, "Expected 7, got %d\n", i);
4408     i = MsiRecordGetInteger(rec, 8);
4409     ok(i == 8, "Expected 8, got %d\n", i);
4410
4411     MsiCloseHandle(rec);
4412     MsiViewClose(view);
4413     MsiCloseHandle(view);
4414
4415     r = MsiDatabaseCommit(hdb);
4416     ok(r == ERROR_SUCCESS, "MsiDatabaseCommit failed\n");
4417
4418     r = MsiCloseHandle(hdb);
4419     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4420
4421     r = DeleteFile(msifile);
4422     ok(r == TRUE, "file didn't exist after commit\n");
4423 }
4424
4425 static void test_update(void)
4426 {
4427     MSIHANDLE hdb = 0, view = 0, rec = 0;
4428     CHAR result[MAX_PATH];
4429     const char *query;
4430     DWORD size;
4431     UINT r;
4432
4433     /* just MsiOpenDatabase should not create a file */
4434     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
4435     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
4436
4437     /* create the Control table */
4438     query = "CREATE TABLE `Control` ( "
4439         "`Dialog_` CHAR(72) NOT NULL, `Control` CHAR(50) NOT NULL, `Type` SHORT NOT NULL, "
4440         "`X` SHORT NOT NULL, `Y` SHORT NOT NULL, `Width` SHORT NOT NULL, `Height` SHORT NOT NULL,"
4441         "`Attributes` LONG, `Property` CHAR(50), `Text` CHAR(0) LOCALIZABLE, "
4442         "`Control_Next` CHAR(50), `Help` CHAR(50) LOCALIZABLE PRIMARY KEY `Dialog_`, `Control`)";
4443     r = MsiDatabaseOpenView(hdb, query, &view);
4444     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
4445     r = MsiViewExecute(view, 0);
4446     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
4447     r = MsiViewClose(view);
4448     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4449     r = MsiCloseHandle(view);
4450     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4451
4452     /* add a control */
4453     query = "INSERT INTO `Control` ( "
4454         "`Dialog_`, `Control`, `Type`, `X`, `Y`, `Width`, `Height`, "
4455         "`Property`, `Text`, `Control_Next`, `Help` )"
4456         "VALUES('ErrorDialog', 'ErrorText', '1', '5', '5', '5', '5', '', '', '', '')";
4457     r = MsiDatabaseOpenView(hdb, query, &view);
4458     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4459     r = MsiViewExecute(view, 0);
4460     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4461     r = MsiViewClose(view);
4462     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4463     r = MsiCloseHandle(view);
4464     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4465
4466     /* add a second control */
4467     query = "INSERT INTO `Control` ( "
4468         "`Dialog_`, `Control`, `Type`, `X`, `Y`, `Width`, `Height`, "
4469         "`Property`, `Text`, `Control_Next`, `Help` )"
4470         "VALUES('ErrorDialog', 'Button', '1', '5', '5', '5', '5', '', '', '', '')";
4471     r = MsiDatabaseOpenView(hdb, query, &view);
4472     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4473     r = MsiViewExecute(view, 0);
4474     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4475     r = MsiViewClose(view);
4476     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4477     r = MsiCloseHandle(view);
4478     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4479
4480     /* add a third control */
4481     query = "INSERT INTO `Control` ( "
4482         "`Dialog_`, `Control`, `Type`, `X`, `Y`, `Width`, `Height`, "
4483         "`Property`, `Text`, `Control_Next`, `Help` )"
4484         "VALUES('AnotherDialog', 'ErrorText', '1', '5', '5', '5', '5', '', '', '', '')";
4485     r = MsiDatabaseOpenView(hdb, query, &view);
4486     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4487     r = MsiViewExecute(view, 0);
4488     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4489     r = MsiViewClose(view);
4490     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4491     r = MsiCloseHandle(view);
4492     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4493
4494     /* bad table */
4495     query = "UPDATE `NotATable` SET `Text` = 'this is text' WHERE `Dialog_` = 'ErrorDialog'";
4496     r = MsiDatabaseOpenView(hdb, query, &view);
4497     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
4498
4499     /* bad set column */
4500     query = "UPDATE `Control` SET `NotAColumn` = 'this is text' WHERE `Dialog_` = 'ErrorDialog'";
4501     r = MsiDatabaseOpenView(hdb, query, &view);
4502     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
4503
4504     /* bad where condition */
4505     query = "UPDATE `Control` SET `Text` = 'this is text' WHERE `NotAColumn` = 'ErrorDialog'";
4506     r = MsiDatabaseOpenView(hdb, query, &view);
4507     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
4508
4509     /* just the dialog_ specified */
4510     query = "UPDATE `Control` SET `Text` = 'this is text' WHERE `Dialog_` = 'ErrorDialog'";
4511     r = MsiDatabaseOpenView(hdb, query, &view);
4512     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4513     r = MsiViewExecute(view, 0);
4514     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4515     r = MsiViewClose(view);
4516     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4517     r = MsiCloseHandle(view);
4518     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4519
4520     /* check the modified text */
4521     query = "SELECT `Text` FROM `Control` WHERE `Control` = 'ErrorText'";
4522     r = MsiDatabaseOpenView(hdb, query, &view);
4523     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4524     r = MsiViewExecute(view, 0);
4525     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4526
4527     r = MsiViewFetch(view, &rec);
4528     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4529
4530     size = MAX_PATH;
4531     r = MsiRecordGetString(rec, 1, result, &size);
4532     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4533     ok(!lstrcmp(result, "this is text"), "Expected `this is text`, got %s\n", result);
4534
4535     MsiCloseHandle(rec);
4536
4537     r = MsiViewFetch(view, &rec);
4538     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4539
4540     size = MAX_PATH;
4541     r = MsiRecordGetString(rec, 1, result, &size);
4542     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4543     ok(!lstrlen(result), "Expected an empty string, got %s\n", result);
4544
4545     MsiCloseHandle(rec);
4546
4547     r = MsiViewFetch(view, &rec);
4548     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
4549
4550     r = MsiViewClose(view);
4551     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4552     r = MsiCloseHandle(view);
4553     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4554
4555     /* dialog_ and control specified */
4556     query = "UPDATE `Control` SET `Text` = 'this is text' WHERE `Dialog_` = 'ErrorDialog' AND `Control` = 'ErrorText'";
4557     r = MsiDatabaseOpenView(hdb, query, &view);
4558     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4559     r = MsiViewExecute(view, 0);
4560     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4561     r = MsiViewClose(view);
4562     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4563     r = MsiCloseHandle(view);
4564     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4565
4566     /* check the modified text */
4567     query = "SELECT `Text` FROM `Control` WHERE `Control` = 'ErrorText'";
4568     r = MsiDatabaseOpenView(hdb, query, &view);
4569     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4570     r = MsiViewExecute(view, 0);
4571     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4572
4573     r = MsiViewFetch(view, &rec);
4574     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4575
4576     size = MAX_PATH;
4577     r = MsiRecordGetString(rec, 1, result, &size);
4578     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4579     ok(!lstrcmp(result, "this is text"), "Expected `this is text`, got %s\n", result);
4580
4581     MsiCloseHandle(rec);
4582
4583     r = MsiViewFetch(view, &rec);
4584     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4585
4586     size = MAX_PATH;
4587     r = MsiRecordGetString(rec, 1, result, &size);
4588     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4589     ok(!lstrlen(result), "Expected an empty string, got %s\n", result);
4590
4591     MsiCloseHandle(rec);
4592
4593     r = MsiViewFetch(view, &rec);
4594     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
4595
4596     r = MsiViewClose(view);
4597     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4598     r = MsiCloseHandle(view);
4599     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4600
4601     /* no where condition */
4602     query = "UPDATE `Control` SET `Text` = 'this is text'";
4603     r = MsiDatabaseOpenView(hdb, query, &view);
4604     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4605     r = MsiViewExecute(view, 0);
4606     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4607     r = MsiViewClose(view);
4608     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4609     r = MsiCloseHandle(view);
4610     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4611
4612     /* check the modified text */
4613     query = "SELECT `Text` FROM `Control`";
4614     r = MsiDatabaseOpenView(hdb, query, &view);
4615     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4616     r = MsiViewExecute(view, 0);
4617     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4618
4619     r = MsiViewFetch(view, &rec);
4620     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4621
4622     size = MAX_PATH;
4623     r = MsiRecordGetString(rec, 1, result, &size);
4624     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4625     ok(!lstrcmp(result, "this is text"), "Expected `this is text`, got %s\n", result);
4626
4627     MsiCloseHandle(rec);
4628
4629     r = MsiViewFetch(view, &rec);
4630     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4631
4632     size = MAX_PATH;
4633     r = MsiRecordGetString(rec, 1, result, &size);
4634     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4635     ok(!lstrcmp(result, "this is text"), "Expected `this is text`, got %s\n", result);
4636
4637     MsiCloseHandle(rec);
4638
4639     r = MsiViewFetch(view, &rec);
4640     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4641
4642     size = MAX_PATH;
4643     r = MsiRecordGetString(rec, 1, result, &size);
4644     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4645     ok(!lstrcmp(result, "this is text"), "Expected `this is text`, got %s\n", result);
4646
4647     MsiCloseHandle(rec);
4648
4649     r = MsiViewFetch(view, &rec);
4650     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
4651
4652     r = MsiViewClose(view);
4653     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4654     r = MsiCloseHandle(view);
4655     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4656
4657     query = "CREATE TABLE `Apple` ( `Banana` CHAR(72) NOT NULL, "
4658         "`Orange` CHAR(72),  `Pear` INT PRIMARY KEY `Banana`)";
4659     r = run_query(hdb, 0, query);
4660     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4661
4662     query = "INSERT INTO `Apple` ( `Banana`, `Orange`, `Pear` )"
4663         "VALUES('one', 'two', 3)";
4664     r = run_query(hdb, 0, query);
4665     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4666
4667     query = "INSERT INTO `Apple` ( `Banana`, `Orange`, `Pear` )"
4668         "VALUES('three', 'four', 5)";
4669     r = run_query(hdb, 0, query);
4670     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4671
4672     query = "INSERT INTO `Apple` ( `Banana`, `Orange`, `Pear` )"
4673         "VALUES('six', 'two', 7)";
4674     r = run_query(hdb, 0, query);
4675     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4676
4677     rec = MsiCreateRecord(2);
4678     MsiRecordSetInteger(rec, 1, 8);
4679     MsiRecordSetString(rec, 2, "two");
4680
4681     query = "UPDATE `Apple` SET `Pear` = ? WHERE `Orange` = ?";
4682     r = run_query(hdb, rec, query);
4683     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4684
4685     MsiCloseHandle(rec);
4686
4687     query = "SELECT `Pear` FROM `Apple` ORDER BY `Orange`";
4688     r = MsiDatabaseOpenView(hdb, query, &view);
4689     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4690     r = MsiViewExecute(view, 0);
4691     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4692
4693     r = MsiViewFetch(view, &rec);
4694     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4695
4696     r = MsiRecordGetInteger(rec, 1);
4697     ok(r == 8, "Expected 8, got %d\n", r);
4698
4699     MsiCloseHandle(rec);
4700
4701     r = MsiViewFetch(view, &rec);
4702     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4703
4704     r = MsiRecordGetInteger(rec, 1);
4705     ok(r == 8, "Expected 8, got %d\n", r);
4706
4707     MsiCloseHandle(rec);
4708
4709     r = MsiViewFetch(view, &rec);
4710     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4711
4712     r = MsiRecordGetInteger(rec, 1);
4713     ok(r == 5, "Expected 5, got %d\n", r);
4714
4715     MsiCloseHandle(rec);
4716
4717     r = MsiViewFetch(view, &rec);
4718     ok(r == ERROR_NO_MORE_ITEMS, "Expectd ERROR_NO_MORE_ITEMS, got %d\n", r);
4719
4720     MsiViewClose(view);
4721     MsiCloseHandle(view);
4722
4723     r = MsiDatabaseCommit(hdb);
4724     ok(r == ERROR_SUCCESS, "MsiDatabaseCommit failed\n");
4725     r = MsiCloseHandle(hdb);
4726     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4727
4728     DeleteFile(msifile);
4729 }
4730
4731 static void test_special_tables(void)
4732 {
4733     const char *query;
4734     MSIHANDLE hdb = 0;
4735     UINT r;
4736
4737     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
4738     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
4739
4740     query = "CREATE TABLE `_Properties` ( "
4741         "`foo` INT NOT NULL, `bar` INT LOCALIZABLE PRIMARY KEY `foo`)";
4742     r = run_query(hdb, 0, query);
4743     ok(r == ERROR_SUCCESS, "failed to create table\n");
4744
4745     query = "CREATE TABLE `_Storages` ( "
4746         "`foo` INT NOT NULL, `bar` INT LOCALIZABLE PRIMARY KEY `foo`)";
4747     r = run_query(hdb, 0, query);
4748     ok(r == ERROR_BAD_QUERY_SYNTAX, "created _Streams table\n");
4749
4750     query = "CREATE TABLE `_Streams` ( "
4751         "`foo` INT NOT NULL, `bar` INT LOCALIZABLE PRIMARY KEY `foo`)";
4752     r = run_query(hdb, 0, query);
4753     ok(r == ERROR_BAD_QUERY_SYNTAX, "created _Streams table\n");
4754
4755     query = "CREATE TABLE `_Tables` ( "
4756         "`foo` INT NOT NULL, `bar` INT LOCALIZABLE PRIMARY KEY `foo`)";
4757     r = run_query(hdb, 0, query);
4758     ok(r == ERROR_BAD_QUERY_SYNTAX, "created _Tables table\n");
4759
4760     query = "CREATE TABLE `_Columns` ( "
4761         "`foo` INT NOT NULL, `bar` INT LOCALIZABLE PRIMARY KEY `foo`)";
4762     r = run_query(hdb, 0, query);
4763     ok(r == ERROR_BAD_QUERY_SYNTAX, "created _Columns table\n");
4764
4765     r = MsiCloseHandle(hdb);
4766     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4767 }
4768
4769 static void test_tables_order(void)
4770 {
4771     const char *query;
4772     MSIHANDLE hdb = 0, hview = 0, hrec = 0;
4773     UINT r;
4774     char buffer[100];
4775     DWORD sz;
4776
4777     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
4778     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
4779
4780     query = "CREATE TABLE `foo` ( "
4781         "`baz` INT NOT NULL PRIMARY KEY `baz`)";
4782     r = run_query(hdb, 0, query);
4783     ok(r == ERROR_SUCCESS, "failed to create table\n");
4784
4785     query = "CREATE TABLE `bar` ( "
4786         "`foo` INT NOT NULL PRIMARY KEY `foo`)";
4787     r = run_query(hdb, 0, query);
4788     ok(r == ERROR_SUCCESS, "failed to create table\n");
4789
4790     query = "CREATE TABLE `baz` ( "
4791         "`bar` INT NOT NULL, "
4792         "`baz` INT NOT NULL, "
4793         "`foo` INT NOT NULL PRIMARY KEY `bar`)";
4794     r = run_query(hdb, 0, query);
4795     ok(r == ERROR_SUCCESS, "failed to create table\n");
4796
4797     /* The names of the tables in the _Tables table must
4798        be in the same order as these names are created in
4799        the strings table. */
4800     query = "SELECT * FROM `_Tables`";
4801     r = MsiDatabaseOpenView(hdb, query, &hview);
4802     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
4803     r = MsiViewExecute(hview, 0);
4804     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
4805
4806     r = MsiViewFetch(hview, &hrec);
4807     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4808     sz = sizeof(buffer);
4809     r = MsiRecordGetString(hrec, 1, buffer, &sz);
4810     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4811     ok(!lstrcmp(buffer, "foo"), "Expected foo, got %s\n", buffer);
4812     r = MsiCloseHandle(hrec);
4813     ok(r == ERROR_SUCCESS, "failed to close record\n");
4814
4815     r = MsiViewFetch(hview, &hrec);
4816     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4817     sz = sizeof(buffer);
4818     r = MsiRecordGetString(hrec, 1, buffer, &sz);
4819     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4820     ok(!lstrcmp(buffer, "baz"), "Expected baz, got %s\n", buffer);
4821     r = MsiCloseHandle(hrec);
4822     ok(r == ERROR_SUCCESS, "failed to close record\n");
4823
4824     r = MsiViewFetch(hview, &hrec);
4825     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4826     sz = sizeof(buffer);
4827     r = MsiRecordGetString(hrec, 1, buffer, &sz);
4828     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4829     ok(!lstrcmp(buffer, "bar"), "Expected bar, got %s\n", buffer);
4830     r = MsiCloseHandle(hrec);
4831     ok(r == ERROR_SUCCESS, "failed to close record\n");
4832
4833     r = MsiViewClose(hview);
4834     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4835     r = MsiCloseHandle(hview);
4836     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4837
4838     /* The names of the tables in the _Columns table must
4839        be in the same order as these names are created in
4840        the strings table. */
4841     query = "SELECT * FROM `_Columns`";
4842     r = MsiDatabaseOpenView(hdb, query, &hview);
4843     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
4844     r = MsiViewExecute(hview, 0);
4845     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
4846
4847     r = MsiViewFetch(hview, &hrec);
4848     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4849     sz = sizeof(buffer);
4850     r = MsiRecordGetString(hrec, 1, buffer, &sz);
4851     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4852     ok(!lstrcmp(buffer, "foo"), "Expected foo, got %s\n", buffer);
4853     sz = sizeof(buffer);
4854     r = MsiRecordGetString(hrec, 3, buffer, &sz);
4855     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4856     ok(!lstrcmp(buffer, "baz"), "Expected baz, got %s\n", buffer);
4857     r = MsiCloseHandle(hrec);
4858     ok(r == ERROR_SUCCESS, "failed to close record\n");
4859
4860     r = MsiViewFetch(hview, &hrec);
4861     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4862     sz = sizeof(buffer);
4863     r = MsiRecordGetString(hrec, 1, buffer, &sz);
4864     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4865     ok(!lstrcmp(buffer, "baz"), "Expected baz, got %s\n", buffer);
4866     sz = sizeof(buffer);
4867     r = MsiRecordGetString(hrec, 3, buffer, &sz);
4868     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4869     ok(!lstrcmp(buffer, "bar"), "Expected bar, got %s\n", buffer);
4870     r = MsiCloseHandle(hrec);
4871     ok(r == ERROR_SUCCESS, "failed to close record\n");
4872
4873     r = MsiViewFetch(hview, &hrec);
4874     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4875     sz = sizeof(buffer);
4876     r = MsiRecordGetString(hrec, 1, buffer, &sz);
4877     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4878     ok(!lstrcmp(buffer, "baz"), "Expected baz, got %s\n", buffer);
4879     sz = sizeof(buffer);
4880     r = MsiRecordGetString(hrec, 3, buffer, &sz);
4881     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4882     ok(!lstrcmp(buffer, "baz"), "Expected baz, got %s\n", buffer);
4883     r = MsiCloseHandle(hrec);
4884     ok(r == ERROR_SUCCESS, "failed to close record\n");
4885
4886     r = MsiViewFetch(hview, &hrec);
4887     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4888     sz = sizeof(buffer);
4889     r = MsiRecordGetString(hrec, 1, buffer, &sz);
4890     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4891     ok(!lstrcmp(buffer, "baz"), "Expected baz, got %s\n", buffer);
4892     sz = sizeof(buffer);
4893     r = MsiRecordGetString(hrec, 3, buffer, &sz);
4894     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4895     ok(!lstrcmp(buffer, "foo"), "Expected foo, got %s\n", buffer);
4896     r = MsiCloseHandle(hrec);
4897     ok(r == ERROR_SUCCESS, "failed to close record\n");
4898
4899     r = MsiViewFetch(hview, &hrec);
4900     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4901     sz = sizeof(buffer);
4902     r = MsiRecordGetString(hrec, 1, buffer, &sz);
4903     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4904     ok(!lstrcmp(buffer, "bar"), "Expected bar, got %s\n", buffer);
4905     sz = sizeof(buffer);
4906     r = MsiRecordGetString(hrec, 3, buffer, &sz);
4907     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4908     ok(!lstrcmp(buffer, "foo"), "Expected foo, got %s\n", buffer);
4909     r = MsiCloseHandle(hrec);
4910     ok(r == ERROR_SUCCESS, "failed to close record\n");
4911
4912     r = MsiViewClose(hview);
4913     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4914     r = MsiCloseHandle(hview);
4915     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4916
4917     r = MsiCloseHandle(hdb);
4918     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4919
4920     DeleteFile(msifile);
4921 }
4922
4923 static void test_rows_order(void)
4924 {
4925     const char *query;
4926     MSIHANDLE hdb = 0, hview = 0, hrec = 0;
4927     UINT r;
4928     char buffer[100];
4929     DWORD sz;
4930
4931     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
4932     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
4933
4934     query = "CREATE TABLE `foo` ( "
4935         "`bar` LONGCHAR NOT NULL PRIMARY KEY `bar`)";
4936     r = run_query(hdb, 0, query);
4937     ok(r == ERROR_SUCCESS, "failed to create table\n");
4938
4939     r = run_query(hdb, 0, "INSERT INTO `foo` "
4940             "( `bar` ) VALUES ( 'A' )");
4941     ok(r == ERROR_SUCCESS, "cannot add value to table\n");
4942
4943     r = run_query(hdb, 0, "INSERT INTO `foo` "
4944             "( `bar` ) VALUES ( 'B' )");
4945     ok(r == ERROR_SUCCESS, "cannot add value to table\n");
4946
4947     r = run_query(hdb, 0, "INSERT INTO `foo` "
4948             "( `bar` ) VALUES ( 'C' )");
4949     ok(r == ERROR_SUCCESS, "cannot add value to table\n");
4950
4951     r = run_query(hdb, 0, "INSERT INTO `foo` "
4952             "( `bar` ) VALUES ( 'D' )");
4953     ok(r == ERROR_SUCCESS, "cannot add value to table\n");
4954
4955     r = run_query(hdb, 0, "INSERT INTO `foo` "
4956             "( `bar` ) VALUES ( 'E' )");
4957     ok(r == ERROR_SUCCESS, "cannot add value to table\n");
4958
4959     r = run_query(hdb, 0, "INSERT INTO `foo` "
4960             "( `bar` ) VALUES ( 'F' )");
4961     ok(r == ERROR_SUCCESS, "cannot add value to table\n");
4962
4963     query = "CREATE TABLE `bar` ( "
4964         "`foo` LONGCHAR NOT NULL, "
4965         "`baz` LONGCHAR NOT NULL "
4966         "PRIMARY KEY `foo` )";
4967     r = run_query(hdb, 0, query);
4968     ok(r == ERROR_SUCCESS, "failed to create table\n");
4969
4970     r = run_query(hdb, 0, "INSERT INTO `bar` "
4971             "( `foo`, `baz` ) VALUES ( 'C', 'E' )");
4972     ok(r == ERROR_SUCCESS, "cannot add value to table\n");
4973
4974     r = run_query(hdb, 0, "INSERT INTO `bar` "
4975             "( `foo`, `baz` ) VALUES ( 'F', 'A' )");
4976     ok(r == ERROR_SUCCESS, "cannot add value to table\n");
4977
4978     r = run_query(hdb, 0, "INSERT INTO `bar` "
4979             "( `foo`, `baz` ) VALUES ( 'A', 'B' )");
4980     ok(r == ERROR_SUCCESS, "cannot add value to table\n");
4981
4982     r = run_query(hdb, 0, "INSERT INTO `bar` "
4983             "( `foo`, `baz` ) VALUES ( 'D', 'E' )");
4984     ok(r == ERROR_SUCCESS, "cannot add value to table\n");
4985
4986     /* The rows of the table must be ordered by the column values of
4987        each row. For strings, the column value is the string id
4988        in the string table.  */
4989
4990     query = "SELECT * FROM `bar`";
4991     r = MsiDatabaseOpenView(hdb, query, &hview);
4992     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
4993     r = MsiViewExecute(hview, 0);
4994     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
4995
4996     r = MsiViewFetch(hview, &hrec);
4997     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4998     sz = sizeof(buffer);
4999     r = MsiRecordGetString(hrec, 1, buffer, &sz);
5000     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5001     ok(!lstrcmp(buffer, "A"), "Expected A, got %s\n", buffer);
5002     sz = sizeof(buffer);
5003     r = MsiRecordGetString(hrec, 2, buffer, &sz);
5004     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5005     ok(!lstrcmp(buffer, "B"), "Expected B, got %s\n", buffer);
5006     r = MsiCloseHandle(hrec);
5007     ok(r == ERROR_SUCCESS, "failed to close record\n");
5008
5009     r = MsiViewFetch(hview, &hrec);
5010     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
5011     sz = sizeof(buffer);
5012     r = MsiRecordGetString(hrec, 1, buffer, &sz);
5013     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5014     ok(!lstrcmp(buffer, "C"), "Expected E, got %s\n", buffer);
5015     sz = sizeof(buffer);
5016     r = MsiRecordGetString(hrec, 2, buffer, &sz);
5017     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5018     ok(!lstrcmp(buffer, "E"), "Expected E, got %s\n", buffer);
5019     r = MsiCloseHandle(hrec);
5020     ok(r == ERROR_SUCCESS, "failed to close record\n");
5021
5022     r = MsiViewFetch(hview, &hrec);
5023     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
5024     sz = sizeof(buffer);
5025     r = MsiRecordGetString(hrec, 1, buffer, &sz);
5026     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5027     ok(!lstrcmp(buffer, "D"), "Expected D, got %s\n", buffer);
5028     sz = sizeof(buffer);
5029     r = MsiRecordGetString(hrec, 2, buffer, &sz);
5030     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5031     ok(!lstrcmp(buffer, "E"), "Expected E, got %s\n", buffer);
5032     r = MsiCloseHandle(hrec);
5033     ok(r == ERROR_SUCCESS, "failed to close record\n");
5034
5035     r = MsiViewFetch(hview, &hrec);
5036     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
5037     sz = sizeof(buffer);
5038     r = MsiRecordGetString(hrec, 1, buffer, &sz);
5039     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5040     ok(!lstrcmp(buffer, "F"), "Expected F, got %s\n", buffer);
5041     sz = sizeof(buffer);
5042     r = MsiRecordGetString(hrec, 2, buffer, &sz);
5043     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5044     ok(!lstrcmp(buffer, "A"), "Expected A, got %s\n", buffer);
5045     r = MsiCloseHandle(hrec);
5046     ok(r == ERROR_SUCCESS, "failed to close record\n");
5047
5048     r = MsiViewClose(hview);
5049     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
5050     r = MsiCloseHandle(hview);
5051     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
5052
5053     r = MsiCloseHandle(hdb);
5054     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
5055
5056     DeleteFile(msifile);
5057 }
5058
5059 static void test_collation(void)
5060 {
5061     static const WCHAR query1[] =
5062         {'I','N','S','E','R','T',' ','I','N','T','O',' ','`','b','a','r','`',' ',
5063          '(','`','f','o','o','`',',','`','b','a','z','`',')',' ','V','A','L','U','E','S',' ',
5064          '(','\'','a',0x30a,'\'',',','\'','C','\'',')',0};
5065     static const WCHAR query2[] =
5066         {'I','N','S','E','R','T',' ','I','N','T','O',' ','`','b','a','r','`',' ',
5067          '(','`','f','o','o','`',',','`','b','a','z','`',')',' ','V','A','L','U','E','S',' ',
5068          '(','\'',0xe5,'\'',',','\'','D','\'',')',0};
5069     static const WCHAR query3[] =
5070         {'C','R','E','A','T','E',' ','T','A','B','L','E',' ','`','b','a','z','`',' ',
5071          '(',' ','`','a',0x30a,'`',' ','L','O','N','G','C','H','A','R',' ','N','O','T',' ','N','U','L','L',',',
5072            ' ','`',0xe5,'`',' ','L','O','N','G','C','H','A','R',' ','N','O','T',' ','N','U','L','L',' ',
5073            'P','R','I','M','A','R','Y',' ','K','E','Y',' ','`','a',0x30a,'`',')',0};
5074     static const WCHAR query4[] =
5075         {'C','R','E','A','T','E',' ','T','A','B','L','E',' ','`','a',0x30a,'`',' ',
5076          '(',' ','`','f','o','o','`',' ','L','O','N','G','C','H','A','R',' ','N','O','T',' ',
5077          'N','U','L','L',' ','P','R','I','M','A','R','Y',' ','K','E','Y',' ','`','f','o','o','`',')',0};
5078     static const WCHAR query5[] =
5079         {'C','R','E','A','T','E',' ','T','A','B','L','E',' ','`',0xe5,'`',' ',
5080          '(',' ','`','f','o','o','`',' ','L','O','N','G','C','H','A','R',' ','N','O','T',' ',
5081          'N','U','L','L',' ','P','R','I','M','A','R','Y',' ','K','E','Y',' ','`','f','o','o','`',')',0};
5082     static const WCHAR query6[] =
5083         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','b','a','r','`',' ','W','H','E','R','E',
5084          ' ','`','f','o','o','`',' ','=','\'',0xe5,'\'',0};
5085     static const WCHAR letter_C[] = {'C',0};
5086     static const WCHAR letter_D[] = {'D',0};
5087     static const WCHAR letter_a_ring[] = {'a',0x30a,0};
5088     static const WCHAR letter_a_with_ring[] = {0xe5,0};
5089     const char *query;
5090     MSIHANDLE hdb = 0, hview = 0, hrec = 0;
5091     UINT r;
5092     char buffer[100];
5093     WCHAR bufferW[100];
5094     DWORD sz;
5095
5096     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
5097     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
5098
5099     query = "CREATE TABLE `bar` ( "
5100         "`foo` LONGCHAR NOT NULL, "
5101         "`baz` LONGCHAR NOT NULL "
5102         "PRIMARY KEY `foo` )";
5103     r = run_query(hdb, 0, query);
5104     ok(r == ERROR_SUCCESS, "failed to create table\n");
5105
5106     r = run_query(hdb, 0, query);
5107     ok(r == ERROR_BAD_QUERY_SYNTAX, "wrong error %u\n", r);
5108
5109     r = run_query(hdb, 0, "INSERT INTO `bar` "
5110             "( `foo`, `baz` ) VALUES ( '\2', 'A' )");
5111     ok(r == ERROR_SUCCESS, "cannot add value to table %u\n", r);
5112
5113     r = run_query(hdb, 0, "INSERT INTO `bar` "
5114             "( `foo`, `baz` ) VALUES ( '\1', 'B' )");
5115     ok(r == ERROR_SUCCESS, "cannot add value to table %u\n", r);
5116
5117     r = run_queryW(hdb, 0, query1);
5118     ok(r == ERROR_SUCCESS, "cannot add value to table %u\n", r);
5119
5120     r = run_queryW(hdb, 0, query2);
5121     ok(r == ERROR_SUCCESS, "cannot add value to table %u\n", r);
5122
5123     r = run_queryW(hdb, 0, query3);
5124     ok(r == ERROR_SUCCESS, "cannot create table %u\n", r);
5125
5126     r = run_queryW(hdb, 0, query4);
5127     ok(r == ERROR_SUCCESS, "cannot create table %u\n", r);
5128
5129     r = run_queryW(hdb, 0, query5);
5130     ok(r == ERROR_SUCCESS, "cannot create table %u\n", r);
5131
5132     query = "SELECT * FROM `bar`";
5133     r = MsiDatabaseOpenView(hdb, query, &hview);
5134     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
5135     r = MsiViewExecute(hview, 0);
5136     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
5137
5138     r = MsiViewFetch(hview, &hrec);
5139     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
5140     sz = sizeof(buffer);
5141     r = MsiRecordGetString(hrec, 1, buffer, &sz);
5142     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5143     ok(!lstrcmp(buffer, "\2"), "Expected \\2, got '%s'\n", buffer);
5144     sz = sizeof(buffer);
5145     r = MsiRecordGetString(hrec, 2, buffer, &sz);
5146     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5147     ok(!lstrcmp(buffer, "A"), "Expected A, got '%s'\n", buffer);
5148     MsiCloseHandle(hrec);
5149
5150     r = MsiViewFetch(hview, &hrec);
5151     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
5152     sz = sizeof(buffer);
5153     r = MsiRecordGetString(hrec, 1, buffer, &sz);
5154     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5155     ok(!lstrcmp(buffer, "\1"), "Expected \\1, got '%s'\n", buffer);
5156     sz = sizeof(buffer);
5157     r = MsiRecordGetString(hrec, 2, buffer, &sz);
5158     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5159     ok(!lstrcmp(buffer, "B"), "Expected B, got '%s'\n", buffer);
5160     MsiCloseHandle(hrec);
5161
5162     r = MsiViewFetch(hview, &hrec);
5163     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
5164     sz = sizeof(bufferW) / sizeof(bufferW[0]);
5165     r = MsiRecordGetStringW(hrec, 1, bufferW, &sz);
5166     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5167     ok(!memcmp(bufferW, letter_a_ring, sizeof(letter_a_ring)),
5168        "Expected %s, got %s\n", wine_dbgstr_w(letter_a_ring), wine_dbgstr_w(bufferW));
5169     sz = sizeof(bufferW) / sizeof(bufferW[0]);
5170     r = MsiRecordGetStringW(hrec, 2, bufferW, &sz);
5171     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5172     ok(!lstrcmpW(bufferW, letter_C), "Expected C, got %s\n", wine_dbgstr_w(bufferW));
5173     MsiCloseHandle(hrec);
5174
5175     r = MsiViewFetch(hview, &hrec);
5176     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
5177     sz = sizeof(bufferW) / sizeof(bufferW[0]);
5178     r = MsiRecordGetStringW(hrec, 1, bufferW, &sz);
5179     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5180     ok(!memcmp(bufferW, letter_a_with_ring, sizeof(letter_a_with_ring)),
5181        "Expected %s, got %s\n", wine_dbgstr_w(letter_a_with_ring), wine_dbgstr_w(bufferW));
5182     sz = sizeof(bufferW) / sizeof(bufferW[0]);
5183     r = MsiRecordGetStringW(hrec, 2, bufferW, &sz);
5184     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5185     ok(!lstrcmpW(bufferW, letter_D), "Expected D, got %s\n", wine_dbgstr_w(bufferW));
5186     MsiCloseHandle(hrec);
5187
5188     r = MsiViewClose(hview);
5189     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
5190     r = MsiCloseHandle(hview);
5191     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
5192
5193     r = MsiDatabaseOpenViewW(hdb, query6, &hview);
5194     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
5195     r = MsiViewExecute(hview, 0);
5196     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
5197
5198     r = MsiViewFetch(hview, &hrec);
5199     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
5200     sz = sizeof(bufferW) / sizeof(bufferW[0]);
5201     r = MsiRecordGetStringW(hrec, 1, bufferW, &sz);
5202     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5203     ok(!memcmp(bufferW, letter_a_with_ring, sizeof(letter_a_with_ring)),
5204        "Expected %s, got %s\n", wine_dbgstr_w(letter_a_with_ring), wine_dbgstr_w(bufferW));
5205     sz = sizeof(bufferW) / sizeof(bufferW[0]);
5206     r = MsiRecordGetStringW(hrec, 2, bufferW, &sz);
5207     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5208     ok(!lstrcmpW(bufferW, letter_D), "Expected D, got %s\n", wine_dbgstr_w(bufferW));
5209     MsiCloseHandle(hrec);
5210
5211     r = MsiViewFetch(hview, &hrec);
5212     ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch failed\n");
5213
5214     r = MsiViewClose(hview);
5215     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
5216     r = MsiCloseHandle(hview);
5217     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
5218
5219     r = MsiCloseHandle(hdb);
5220     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
5221
5222     DeleteFile(msifile);
5223 }
5224
5225 static void test_select_markers(void)
5226 {
5227     MSIHANDLE hdb = 0, rec, view, res;
5228     LPCSTR query;
5229     UINT r;
5230     DWORD size;
5231     CHAR buf[MAX_PATH];
5232
5233     hdb = create_db();
5234     ok( hdb, "failed to create db\n");
5235
5236     r = run_query(hdb, 0,
5237             "CREATE TABLE `Table` (`One` CHAR(72), `Two` CHAR(72), `Three` SHORT PRIMARY KEY `One`, `Two`, `Three`)");
5238     ok(r == S_OK, "cannot create table: %d\n", r);
5239
5240     r = run_query(hdb, 0, "INSERT INTO `Table` "
5241             "( `One`, `Two`, `Three` ) VALUES ( 'apple', 'one', 1 )");
5242     ok(r == S_OK, "cannot add file to the Media table: %d\n", r);
5243
5244     r = run_query(hdb, 0, "INSERT INTO `Table` "
5245             "( `One`, `Two`, `Three` ) VALUES ( 'apple', 'two', 1 )");
5246     ok(r == S_OK, "cannot add file to the Media table: %d\n", r);
5247
5248     r = run_query(hdb, 0, "INSERT INTO `Table` "
5249             "( `One`, `Two`, `Three` ) VALUES ( 'apple', 'two', 2 )");
5250     ok(r == S_OK, "cannot add file to the Media table: %d\n", r);
5251
5252     r = run_query(hdb, 0, "INSERT INTO `Table` "
5253             "( `One`, `Two`, `Three` ) VALUES ( 'banana', 'three', 3 )");
5254     ok(r == S_OK, "cannot add file to the Media table: %d\n", r);
5255
5256     rec = MsiCreateRecord(2);
5257     MsiRecordSetString(rec, 1, "apple");
5258     MsiRecordSetString(rec, 2, "two");
5259
5260     query = "SELECT * FROM `Table` WHERE `One`=? AND `Two`=? ORDER BY `Three`";
5261     r = MsiDatabaseOpenView(hdb, query, &view);
5262     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5263
5264     r = MsiViewExecute(view, rec);
5265     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5266
5267     r = MsiViewFetch(view, &res);
5268     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5269
5270     size = MAX_PATH;
5271     r = MsiRecordGetString(res, 1, buf, &size);
5272     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5273     ok(!lstrcmp(buf, "apple"), "Expected apple, got %s\n", buf);
5274
5275     size = MAX_PATH;
5276     r = MsiRecordGetString(res, 2, buf, &size);
5277     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5278     ok(!lstrcmp(buf, "two"), "Expected two, got %s\n", buf);
5279
5280     r = MsiRecordGetInteger(res, 3);
5281     ok(r == 1, "Expected 1, got %d\n", r);
5282
5283     MsiCloseHandle(res);
5284
5285     r = MsiViewFetch(view, &res);
5286     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5287
5288     size = MAX_PATH;
5289     r = MsiRecordGetString(res, 1, buf, &size);
5290     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5291     ok(!lstrcmp(buf, "apple"), "Expected apple, got %s\n", buf);
5292
5293     size = MAX_PATH;
5294     r = MsiRecordGetString(res, 2, buf, &size);
5295     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5296     ok(!lstrcmp(buf, "two"), "Expected two, got %s\n", buf);
5297
5298     r = MsiRecordGetInteger(res, 3);
5299     ok(r == 2, "Expected 2, got %d\n", r);
5300
5301     MsiCloseHandle(res);
5302
5303     r = MsiViewFetch(view, &res);
5304     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5305
5306     MsiCloseHandle(rec);
5307     MsiViewClose(view);
5308     MsiCloseHandle(view);
5309
5310     rec = MsiCreateRecord(2);
5311     MsiRecordSetString(rec, 1, "one");
5312     MsiRecordSetInteger(rec, 2, 1);
5313
5314     query = "SELECT * FROM `Table` WHERE `Two`<>? AND `Three`>? ORDER BY `Three`";
5315     r = MsiDatabaseOpenView(hdb, query, &view);
5316     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5317     r = MsiViewExecute(view, rec);
5318     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5319
5320     r = MsiViewFetch(view, &res);
5321     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5322
5323     size = MAX_PATH;
5324     r = MsiRecordGetString(res, 1, buf, &size);
5325     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5326     ok(!lstrcmp(buf, "apple"), "Expected apple, got %s\n", buf);
5327
5328     size = MAX_PATH;
5329     r = MsiRecordGetString(res, 2, buf, &size);
5330     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5331     ok(!lstrcmp(buf, "two"), "Expected two, got %s\n", buf);
5332
5333     r = MsiRecordGetInteger(res, 3);
5334     ok(r == 2, "Expected 2, got %d\n", r);
5335
5336     MsiCloseHandle(res);
5337
5338     r = MsiViewFetch(view, &res);
5339     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5340
5341     size = MAX_PATH;
5342     r = MsiRecordGetString(res, 1, buf, &size);
5343     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5344     ok(!lstrcmp(buf, "banana"), "Expected banana, got %s\n", buf);
5345
5346     size = MAX_PATH;
5347     r = MsiRecordGetString(res, 2, buf, &size);
5348     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5349     ok(!lstrcmp(buf, "three"), "Expected three, got %s\n", buf);
5350
5351     r = MsiRecordGetInteger(res, 3);
5352     ok(r == 3, "Expected 3, got %d\n", r);
5353
5354     MsiCloseHandle(res);
5355
5356     r = MsiViewFetch(view, &res);
5357     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5358
5359     MsiCloseHandle(rec);
5360     MsiViewClose(view);
5361     MsiCloseHandle(view);
5362     MsiCloseHandle(hdb);
5363     DeleteFile(msifile);
5364 }
5365
5366 static void test_viewmodify_update(void)
5367 {
5368     MSIHANDLE hdb = 0, hview = 0, hrec = 0;
5369     UINT i, test_max, offset, count;
5370     const char *query;
5371     UINT r;
5372
5373     DeleteFile(msifile);
5374
5375     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
5376     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
5377
5378     query = "CREATE TABLE `table` (`A` INT, `B` INT PRIMARY KEY `A`)";
5379     r = run_query( hdb, 0, query );
5380     ok(r == ERROR_SUCCESS, "query failed\n");
5381
5382     query = "INSERT INTO `table` (`A`, `B`) VALUES (1, 2)";
5383     r = run_query( hdb, 0, query );
5384     ok(r == ERROR_SUCCESS, "query failed\n");
5385
5386     query = "INSERT INTO `table` (`A`, `B`) VALUES (3, 4)";
5387     r = run_query( hdb, 0, query );
5388     ok(r == ERROR_SUCCESS, "query failed\n");
5389
5390     query = "INSERT INTO `table` (`A`, `B`) VALUES (5, 6)";
5391     r = run_query( hdb, 0, query );
5392     ok(r == ERROR_SUCCESS, "query failed\n");
5393
5394     query = "SELECT `B` FROM `table`";
5395     r = MsiDatabaseOpenView(hdb, query, &hview);
5396     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
5397     r = MsiViewExecute(hview, 0);
5398     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
5399     r = MsiViewFetch(hview, &hrec);
5400     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
5401
5402     r = MsiRecordSetInteger(hrec, 1, 0);
5403     ok(r == ERROR_SUCCESS, "failed to set integer\n");
5404
5405     r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
5406     ok(r == ERROR_SUCCESS, "MsiViewModify failed: %d\n", r);
5407
5408     r = MsiCloseHandle(hrec);
5409     ok(r == ERROR_SUCCESS, "failed to close record\n");
5410
5411     r = MsiViewClose(hview);
5412     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
5413     r = MsiCloseHandle(hview);
5414     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
5415
5416     query = "SELECT * FROM `table`";
5417     r = MsiDatabaseOpenView(hdb, query, &hview);
5418     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
5419     r = MsiViewExecute(hview, 0);
5420     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
5421     r = MsiViewFetch(hview, &hrec);
5422     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
5423
5424     r = MsiRecordGetInteger(hrec, 1);
5425     ok(r == 1, "Expected 1, got %d\n", r);
5426     r = MsiRecordGetInteger(hrec, 2);
5427     ok(r == 0, "Expected 0, got %d\n", r);
5428
5429     r = MsiCloseHandle(hrec);
5430     ok(r == ERROR_SUCCESS, "failed to close record\n");
5431
5432     r = MsiViewFetch(hview, &hrec);
5433     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
5434
5435     r = MsiRecordGetInteger(hrec, 1);
5436     ok(r == 3, "Expected 3, got %d\n", r);
5437     r = MsiRecordGetInteger(hrec, 2);
5438     ok(r == 4, "Expected 4, got %d\n", r);
5439
5440     r = MsiCloseHandle(hrec);
5441     ok(r == ERROR_SUCCESS, "failed to close record\n");
5442
5443     r = MsiViewFetch(hview, &hrec);
5444     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
5445
5446     r = MsiRecordGetInteger(hrec, 1);
5447     ok(r == 5, "Expected 5, got %d\n", r);
5448     r = MsiRecordGetInteger(hrec, 2);
5449     ok(r == 6, "Expected 6, got %d\n", r);
5450
5451     r = MsiCloseHandle(hrec);
5452     ok(r == ERROR_SUCCESS, "failed to close record\n");
5453
5454     r = MsiViewFetch(hview, &hrec);
5455     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5456
5457     r = MsiViewClose(hview);
5458     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
5459     r = MsiCloseHandle(hview);
5460     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
5461
5462     /* loop through all elements */
5463     query = "SELECT `B` FROM `table`";
5464     r = MsiDatabaseOpenView(hdb, query, &hview);
5465     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
5466     r = MsiViewExecute(hview, 0);
5467     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
5468
5469     while (TRUE)
5470     {
5471         r = MsiViewFetch(hview, &hrec);
5472         if (r != ERROR_SUCCESS)
5473             break;
5474
5475         r = MsiRecordSetInteger(hrec, 1, 0);
5476         ok(r == ERROR_SUCCESS, "failed to set integer\n");
5477
5478         r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
5479         ok(r == ERROR_SUCCESS, "MsiViewModify failed: %d\n", r);
5480
5481         r = MsiCloseHandle(hrec);
5482         ok(r == ERROR_SUCCESS, "failed to close record\n");
5483     }
5484
5485     r = MsiViewClose(hview);
5486     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
5487     r = MsiCloseHandle(hview);
5488     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
5489
5490     query = "SELECT * FROM `table`";
5491     r = MsiDatabaseOpenView(hdb, query, &hview);
5492     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
5493     r = MsiViewExecute(hview, 0);
5494     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
5495     r = MsiViewFetch(hview, &hrec);
5496     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
5497
5498     r = MsiRecordGetInteger(hrec, 1);
5499     ok(r == 1, "Expected 1, got %d\n", r);
5500     r = MsiRecordGetInteger(hrec, 2);
5501     ok(r == 0, "Expected 0, got %d\n", r);
5502
5503     r = MsiCloseHandle(hrec);
5504     ok(r == ERROR_SUCCESS, "failed to close record\n");
5505
5506     r = MsiViewFetch(hview, &hrec);
5507     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
5508
5509     r = MsiRecordGetInteger(hrec, 1);
5510     ok(r == 3, "Expected 3, got %d\n", r);
5511     r = MsiRecordGetInteger(hrec, 2);
5512     ok(r == 0, "Expected 0, got %d\n", r);
5513
5514     r = MsiCloseHandle(hrec);
5515     ok(r == ERROR_SUCCESS, "failed to close record\n");
5516
5517     r = MsiViewFetch(hview, &hrec);
5518     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
5519
5520     r = MsiRecordGetInteger(hrec, 1);
5521     ok(r == 5, "Expected 5, got %d\n", r);
5522     r = MsiRecordGetInteger(hrec, 2);
5523     ok(r == 0, "Expected 0, got %d\n", r);
5524
5525     r = MsiCloseHandle(hrec);
5526     ok(r == ERROR_SUCCESS, "failed to close record\n");
5527
5528     r = MsiViewFetch(hview, &hrec);
5529     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5530
5531     r = MsiViewClose(hview);
5532     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
5533     r = MsiCloseHandle(hview);
5534     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
5535
5536     query = "CREATE TABLE `table2` (`A` INT, `B` INT PRIMARY KEY `A`)";
5537     r = run_query( hdb, 0, query );
5538     ok(r == ERROR_SUCCESS, "query failed\n");
5539
5540     query = "INSERT INTO `table2` (`A`, `B`) VALUES (?, ?)";
5541     r = MsiDatabaseOpenView( hdb, query, &hview );
5542     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
5543
5544     test_max = 100;
5545     offset = 1234;
5546     for(i = 0; i < test_max; i++)
5547     {
5548
5549         hrec = MsiCreateRecord( 2 );
5550         MsiRecordSetInteger( hrec, 1, test_max - i );
5551         MsiRecordSetInteger( hrec, 2, i );
5552
5553         r = MsiViewExecute( hview, hrec );
5554         ok(r == ERROR_SUCCESS, "Got %d\n", r);
5555
5556         r = MsiCloseHandle( hrec );
5557         ok(r == ERROR_SUCCESS, "Got %d\n", r);
5558     }
5559
5560     r = MsiViewClose( hview );
5561     ok(r == ERROR_SUCCESS, "Got %d\n", r);
5562     r = MsiCloseHandle( hview );
5563     ok(r == ERROR_SUCCESS, "Got %d\n", r);
5564
5565     /* Update. */
5566     query = "SELECT * FROM `table2` ORDER BY `B`";
5567     r = MsiDatabaseOpenView( hdb, query, &hview);
5568     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
5569     r = MsiViewExecute( hview, 0 );
5570     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
5571
5572     count = 0;
5573     while (MsiViewFetch( hview, &hrec ) == ERROR_SUCCESS)
5574     {
5575         UINT b = MsiRecordGetInteger( hrec, 2 );
5576
5577         r = MsiRecordSetInteger( hrec, 2, b + offset);
5578         ok(r == ERROR_SUCCESS, "Got %d\n", r);
5579
5580         r = MsiViewModify( hview, MSIMODIFY_UPDATE, hrec );
5581         ok(r == ERROR_SUCCESS, "Got %d\n", r);
5582
5583         r = MsiCloseHandle(hrec);
5584         ok(r == ERROR_SUCCESS, "failed to close record\n");
5585         count++;
5586     }
5587     ok(count == test_max, "Got count %d\n", count);
5588
5589     r = MsiViewClose(hview);
5590     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
5591     r = MsiCloseHandle(hview);
5592     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
5593
5594     /* Recheck. */
5595     query = "SELECT * FROM `table2` ORDER BY `B`";
5596     r = MsiDatabaseOpenView( hdb, query, &hview);
5597     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
5598     r = MsiViewExecute( hview, 0 );
5599     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
5600
5601     count = 0;
5602     while (MsiViewFetch( hview, &hrec ) == ERROR_SUCCESS)
5603     {
5604         UINT a = MsiRecordGetInteger( hrec, 1 );
5605         UINT b = MsiRecordGetInteger( hrec, 2 );
5606         ok( ( test_max - a + offset) == b, "Got (%d, %d), expected (%d, %d)\n",
5607             a, b, test_max - a + offset, b);
5608
5609         r = MsiCloseHandle(hrec);
5610         ok(r == ERROR_SUCCESS, "failed to close record\n");
5611         count++;
5612     }
5613     ok(count == test_max, "Got count %d\n", count);
5614
5615     r = MsiViewClose(hview);
5616     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
5617     r = MsiCloseHandle(hview);
5618     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
5619
5620     r = MsiCloseHandle( hdb );
5621     ok(r == ERROR_SUCCESS, "MsiOpenDatabase close failed\n");
5622 }
5623
5624 static void test_viewmodify_assign(void)
5625 {
5626     MSIHANDLE hdb = 0, hview = 0, hrec = 0;
5627     const char *query;
5628     UINT r;
5629
5630     /* setup database */
5631     DeleteFile(msifile);
5632
5633     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
5634     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
5635
5636     query = "CREATE TABLE `table` (`A` INT, `B` INT PRIMARY KEY `A`)";
5637     r = run_query( hdb, 0, query );
5638     ok(r == ERROR_SUCCESS, "query failed\n");
5639
5640     /* assign to view, new primary key */
5641     query = "SELECT * FROM `table`";
5642     r = MsiDatabaseOpenView(hdb, query, &hview);
5643     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
5644     r = MsiViewExecute(hview, 0);
5645     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
5646
5647     hrec = MsiCreateRecord(2);
5648     ok(hrec != 0, "MsiCreateRecord failed\n");
5649
5650     r = MsiRecordSetInteger(hrec, 1, 1);
5651     ok(r == ERROR_SUCCESS, "failed to set integer\n");
5652     r = MsiRecordSetInteger(hrec, 2, 2);
5653     ok(r == ERROR_SUCCESS, "failed to set integer\n");
5654
5655     r = MsiViewModify(hview, MSIMODIFY_ASSIGN, hrec);
5656     ok(r == ERROR_SUCCESS, "MsiViewModify failed: %d\n", r);
5657
5658     r = MsiCloseHandle(hrec);
5659     ok(r == ERROR_SUCCESS, "failed to close record\n");
5660
5661     r = MsiViewClose(hview);
5662     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
5663     r = MsiCloseHandle(hview);
5664     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
5665
5666     query = "SELECT * FROM `table`";
5667     r = MsiDatabaseOpenView(hdb, query, &hview);
5668     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
5669     r = MsiViewExecute(hview, 0);
5670     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
5671     r = MsiViewFetch(hview, &hrec);
5672     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
5673
5674     r = MsiRecordGetInteger(hrec, 1);
5675     ok(r == 1, "Expected 1, got %d\n", r);
5676     r = MsiRecordGetInteger(hrec, 2);
5677     ok(r == 2, "Expected 2, got %d\n", r);
5678
5679     r = MsiCloseHandle(hrec);
5680     ok(r == ERROR_SUCCESS, "failed to close record\n");
5681
5682     r = MsiViewFetch(hview, &hrec);
5683     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5684
5685     r = MsiViewClose(hview);
5686     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
5687     r = MsiCloseHandle(hview);
5688     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
5689
5690     /* assign to view, primary key matches */
5691     query = "SELECT * FROM `table`";
5692     r = MsiDatabaseOpenView(hdb, query, &hview);
5693     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
5694     r = MsiViewExecute(hview, 0);
5695     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
5696
5697     hrec = MsiCreateRecord(2);
5698     ok(hrec != 0, "MsiCreateRecord failed\n");
5699
5700     r = MsiRecordSetInteger(hrec, 1, 1);
5701     ok(r == ERROR_SUCCESS, "failed to set integer\n");
5702     r = MsiRecordSetInteger(hrec, 2, 4);
5703     ok(r == ERROR_SUCCESS, "failed to set integer\n");
5704
5705     r = MsiViewModify(hview, MSIMODIFY_ASSIGN, hrec);
5706     ok(r == ERROR_SUCCESS, "MsiViewModify failed: %d\n", r);
5707
5708     r = MsiCloseHandle(hrec);
5709     ok(r == ERROR_SUCCESS, "failed to close record\n");
5710
5711     r = MsiViewClose(hview);
5712     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
5713     r = MsiCloseHandle(hview);
5714     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
5715
5716     query = "SELECT * FROM `table`";
5717     r = MsiDatabaseOpenView(hdb, query, &hview);
5718     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
5719     r = MsiViewExecute(hview, 0);
5720     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
5721     r = MsiViewFetch(hview, &hrec);
5722     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
5723
5724     r = MsiRecordGetInteger(hrec, 1);
5725     ok(r == 1, "Expected 1, got %d\n", r);
5726     r = MsiRecordGetInteger(hrec, 2);
5727     ok(r == 4, "Expected 4, got %d\n", r);
5728
5729     r = MsiCloseHandle(hrec);
5730     ok(r == ERROR_SUCCESS, "failed to close record\n");
5731
5732     r = MsiViewFetch(hview, &hrec);
5733     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5734
5735     r = MsiViewClose(hview);
5736     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
5737     r = MsiCloseHandle(hview);
5738     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
5739
5740     /* close database */
5741     r = MsiCloseHandle( hdb );
5742     ok(r == ERROR_SUCCESS, "MsiOpenDatabase close failed\n");
5743 }
5744
5745 static const WCHAR data10[] = { /* MOO */
5746     0x8001, 0x000b,
5747 };
5748 static const WCHAR data11[] = { /* AAR */
5749     0x8002, 0x8005,
5750     0x000c, 0x000f,
5751 };
5752 static const char data12[] = /* _StringData */
5753     "MOOABAARCDonetwofourfive";
5754 static const WCHAR data13[] = { /* _StringPool */
5755 /*  len, refs */
5756     0,   0,    /* string 0 ''     */
5757     0,   0,    /* string 1 ''     */
5758     0,   0,    /* string 2 ''     */
5759     0,   0,    /* string 3 ''     */
5760     0,   0,    /* string 4 ''     */
5761     3,   3,    /* string 5 'MOO'  */
5762     1,   1,    /* string 6 'A'    */
5763     1,   1,    /* string 7 'B'    */
5764     3,   3,    /* string 8 'AAR'  */
5765     1,   1,    /* string 9 'C'    */
5766     1,   1,    /* string a 'D'    */
5767     3,   1,    /* string b 'one'  */
5768     3,   1,    /* string c 'two'  */
5769     0,   0,    /* string d ''     */
5770     4,   1,    /* string e 'four' */
5771     4,   1,    /* string f 'five' */
5772 };
5773
5774 static void test_stringtable(void)
5775 {
5776     MSIHANDLE hdb = 0, hview = 0, hrec = 0;
5777     IStorage *stg = NULL;
5778     IStream *stm;
5779     WCHAR name[0x20];
5780     HRESULT hr;
5781     const char *query;
5782     char buffer[MAX_PATH];
5783     WCHAR data[MAX_PATH];
5784     DWORD sz, read;
5785     UINT r;
5786
5787     static const DWORD mode = STGM_DIRECT | STGM_READ | STGM_SHARE_DENY_WRITE;
5788     static const WCHAR stringdata[] = {0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0}; /* _StringData */
5789     static const WCHAR stringpool[] = {0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0}; /* _StringPool */
5790     static const WCHAR moo[] = {0x4840, 0x3e16, 0x4818, 0}; /* MOO */
5791     static const WCHAR aar[] = {0x4840, 0x3a8a, 0x481b, 0}; /* AAR */
5792
5793     DeleteFile(msifile);
5794
5795     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
5796     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5797
5798     query = "CREATE TABLE `MOO` (`A` INT, `B` CHAR(72) PRIMARY KEY `A`)";
5799     r = run_query(hdb, 0, query);
5800     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5801
5802     query = "CREATE TABLE `AAR` (`C` INT, `D` CHAR(72) PRIMARY KEY `C`)";
5803     r = run_query(hdb, 0, query);
5804     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5805
5806     /* insert persistent row */
5807     query = "INSERT INTO `MOO` (`A`, `B`) VALUES (1, 'one')";
5808     r = run_query(hdb, 0, query);
5809     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5810
5811     /* insert persistent row */
5812     query = "INSERT INTO `AAR` (`C`, `D`) VALUES (2, 'two')";
5813     r = run_query(hdb, 0, query);
5814     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5815
5816     /* open a view */
5817     query = "SELECT * FROM `MOO`";
5818     r = MsiDatabaseOpenView(hdb, query, &hview);
5819     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5820     r = MsiViewExecute(hview, 0);
5821     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5822
5823     hrec = MsiCreateRecord(2);
5824
5825     r = MsiRecordSetInteger(hrec, 1, 3);
5826     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5827     r = MsiRecordSetString(hrec, 2, "three");
5828     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5829
5830     /* insert a nonpersistent row */
5831     r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec);
5832     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5833
5834     r = MsiCloseHandle(hrec);
5835     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5836     r = MsiViewClose(hview);
5837     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5838     r = MsiCloseHandle(hview);
5839     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5840
5841     /* insert persistent row */
5842     query = "INSERT INTO `MOO` (`A`, `B`) VALUES (4, 'four')";
5843     r = run_query(hdb, 0, query);
5844     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5845
5846     /* insert persistent row */
5847     query = "INSERT INTO `AAR` (`C`, `D`) VALUES (5, 'five')";
5848     r = run_query(hdb, 0, query);
5849     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5850
5851     r = MsiDatabaseCommit(hdb);
5852     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5853
5854     r = MsiCloseHandle(hdb);
5855     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5856
5857     r = MsiOpenDatabase(msifile, MSIDBOPEN_READONLY, &hdb);
5858     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5859
5860     query = "SELECT * FROM `MOO`";
5861     r = MsiDatabaseOpenView(hdb, query, &hview);
5862     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5863
5864     r = MsiViewExecute(hview, 0);
5865     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5866
5867     r = MsiViewFetch(hview, &hrec);
5868     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5869
5870     r = MsiRecordGetFieldCount(hrec);
5871     ok(r == 2, "Expected 2, got %d\n", r);
5872
5873     r = MsiRecordGetInteger(hrec, 1);
5874     ok(r == 1, "Expected 1, got %d\n", r);
5875
5876     sz = sizeof(buffer);
5877     r = MsiRecordGetString(hrec, 2, buffer, &sz);
5878     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5879     ok(!lstrcmp(buffer, "one"), "Expected one, got '%s'\n", buffer);
5880
5881     r = MsiCloseHandle(hrec);
5882     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5883
5884     r = MsiViewFetch(hview, &hrec);
5885     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5886
5887     r = MsiViewClose(hview);
5888     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5889     r = MsiCloseHandle(hview);
5890     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5891     r = MsiCloseHandle(hrec);
5892     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5893
5894     query = "SELECT * FROM `AAR`";
5895     r = MsiDatabaseOpenView(hdb, query, &hview);
5896     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5897
5898     r = MsiViewExecute(hview, 0);
5899     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5900
5901     r = MsiViewFetch(hview, &hrec);
5902     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5903
5904     r = MsiRecordGetFieldCount(hrec);
5905     ok(r == 2, "Expected 2, got %d\n", r);
5906
5907     r = MsiRecordGetInteger(hrec, 1);
5908     ok(r == 2, "Expected 2, got %d\n", r);
5909
5910     sz = sizeof(buffer);
5911     r = MsiRecordGetString(hrec, 2, buffer, &sz);
5912     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5913     ok(!lstrcmp(buffer, "two"), "Expected two, got '%s'\n", buffer);
5914
5915     r = MsiCloseHandle(hrec);
5916     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5917
5918     r = MsiViewFetch(hview, &hrec);
5919     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5920
5921     r = MsiRecordGetFieldCount(hrec);
5922     ok(r == 2, "Expected 2, got %d\n", r);
5923
5924     r = MsiRecordGetInteger(hrec, 1);
5925     ok(r == 5, "Expected 5, got %d\n", r);
5926
5927     sz = sizeof(buffer);
5928     r = MsiRecordGetString(hrec, 2, buffer, &sz);
5929     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5930     ok(!lstrcmp(buffer, "five"), "Expected five, got '%s'\n", buffer);
5931
5932     r = MsiCloseHandle(hrec);
5933     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5934
5935     r = MsiViewFetch(hview, &hrec);
5936     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5937
5938     r = MsiViewClose(hview);
5939     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5940     r = MsiCloseHandle(hview);
5941     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5942     r = MsiCloseHandle(hrec);
5943     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5944     r = MsiCloseHandle(hdb);
5945     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5946
5947     MultiByteToWideChar(CP_ACP, 0, msifile, -1, name, 0x20);
5948     hr = StgOpenStorage(name, NULL, mode, NULL, 0, &stg);
5949     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5950     ok(stg != NULL, "Expected non-NULL storage\n");
5951
5952     hr = IStorage_OpenStream(stg, moo, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm);
5953     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5954     ok(stm != NULL, "Expected non-NULL stream\n");
5955
5956     hr = IStream_Read(stm, data, MAX_PATH, &read);
5957     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5958     ok(read == 4, "Expected 4, got %d\n", read);
5959     todo_wine ok(!memcmp(data, data10, read), "Unexpected data\n");
5960
5961     hr = IStream_Release(stm);
5962     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5963
5964     hr = IStorage_OpenStream(stg, aar, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm);
5965     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5966     ok(stm != NULL, "Expected non-NULL stream\n");
5967
5968     hr = IStream_Read(stm, data, MAX_PATH, &read);
5969     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5970     ok(read == 8, "Expected 8, got %d\n", read);
5971     todo_wine
5972     {
5973         ok(!memcmp(data, data11, read), "Unexpected data\n");
5974     }
5975
5976     hr = IStream_Release(stm);
5977     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5978
5979     hr = IStorage_OpenStream(stg, stringdata, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm);
5980     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5981     ok(stm != NULL, "Expected non-NULL stream\n");
5982
5983     hr = IStream_Read(stm, buffer, MAX_PATH, &read);
5984     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5985     ok(read == 24, "Expected 24, got %d\n", read);
5986     ok(!memcmp(buffer, data12, read), "Unexpected data\n");
5987
5988     hr = IStream_Release(stm);
5989     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5990
5991     hr = IStorage_OpenStream(stg, stringpool, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm);
5992     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5993     ok(stm != NULL, "Expected non-NULL stream\n");
5994
5995     hr = IStream_Read(stm, data, MAX_PATH, &read);
5996     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5997     todo_wine
5998     {
5999         ok(read == 64, "Expected 64, got %d\n", read);
6000         ok(!memcmp(data, data13, read), "Unexpected data\n");
6001     }
6002
6003     hr = IStream_Release(stm);
6004     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
6005
6006     hr = IStorage_Release(stg);
6007     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
6008
6009     DeleteFileA(msifile);
6010 }
6011
6012 static void test_viewmodify_delete(void)
6013 {
6014     MSIHANDLE hdb = 0, hview = 0, hrec = 0;
6015     UINT r;
6016     const char *query;
6017     char buffer[0x100];
6018     DWORD sz;
6019
6020     DeleteFile(msifile);
6021
6022     /* just MsiOpenDatabase should not create a file */
6023     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
6024     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6025
6026     query = "CREATE TABLE `phone` ( "
6027             "`id` INT, `name` CHAR(32), `number` CHAR(32) "
6028             "PRIMARY KEY `id`)";
6029     r = run_query(hdb, 0, query);
6030     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6031
6032     query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
6033         "VALUES('1', 'Alan', '5030581')";
6034     r = run_query(hdb, 0, query);
6035     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6036
6037     query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
6038         "VALUES('2', 'Barry', '928440')";
6039     r = run_query(hdb, 0, query);
6040     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6041
6042     query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
6043         "VALUES('3', 'Cindy', '2937550')";
6044     r = run_query(hdb, 0, query);
6045     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6046
6047     query = "SELECT * FROM `phone` WHERE `id` <= 2";
6048     r = MsiDatabaseOpenView(hdb, query, &hview);
6049     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6050     r = MsiViewExecute(hview, 0);
6051     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6052     r = MsiViewFetch(hview, &hrec);
6053     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6054
6055     /* delete 1 */
6056     r = MsiViewModify(hview, MSIMODIFY_DELETE, hrec);
6057     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6058
6059     r = MsiCloseHandle(hrec);
6060     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6061     r = MsiViewFetch(hview, &hrec);
6062     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6063
6064     /* delete 2 */
6065     r = MsiViewModify(hview, MSIMODIFY_DELETE, hrec);
6066     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6067
6068     r = MsiCloseHandle(hrec);
6069     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6070     r = MsiViewClose(hview);
6071     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6072     r = MsiCloseHandle(hview);
6073     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6074
6075     query = "SELECT * FROM `phone`";
6076     r = MsiDatabaseOpenView(hdb, query, &hview);
6077     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6078     r = MsiViewExecute(hview, 0);
6079     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6080     r = MsiViewFetch(hview, &hrec);
6081     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6082
6083     r = MsiRecordGetInteger(hrec, 1);
6084     ok(r == 3, "Expected 3, got %d\n", r);
6085
6086     sz = sizeof(buffer);
6087     r = MsiRecordGetString(hrec, 2, buffer, &sz);
6088     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6089     ok(!lstrcmp(buffer, "Cindy"), "Expected Cindy, got %s\n", buffer);
6090
6091     sz = sizeof(buffer);
6092     r = MsiRecordGetString(hrec, 3, buffer, &sz);
6093     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6094     ok(!lstrcmp(buffer, "2937550"), "Expected 2937550, got %s\n", buffer);
6095
6096     r = MsiCloseHandle(hrec);
6097     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6098
6099     r = MsiViewFetch(hview, &hrec);
6100     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6101
6102     r = MsiViewClose(hview);
6103     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6104     r = MsiCloseHandle(hview);
6105     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6106     r = MsiCloseHandle(hdb);
6107     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6108 }
6109
6110 static const WCHAR _Tables[] = {0x4840, 0x3f7f, 0x4164, 0x422f, 0x4836, 0};
6111 static const WCHAR _StringData[] = {0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0};
6112 static const WCHAR _StringPool[] = {0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0};
6113
6114 static const WCHAR data14[] = { /* _StringPool */
6115 /*  len, refs */
6116     0,   0,    /* string 0 ''    */
6117 };
6118
6119 static const struct {
6120     LPCWSTR name;
6121     const void *data;
6122     DWORD size;
6123 } database_table_data[] =
6124 {
6125     {_Tables, NULL, 0},
6126     {_StringData, NULL, 0},
6127     {_StringPool, data14, sizeof data14},
6128 };
6129
6130 static void enum_stream_names(IStorage *stg)
6131 {
6132     IEnumSTATSTG *stgenum = NULL;
6133     IStream *stm;
6134     HRESULT hr;
6135     STATSTG stat;
6136     ULONG n, count;
6137     BYTE data[MAX_PATH];
6138     BYTE check[MAX_PATH];
6139     DWORD sz;
6140
6141     memset(check, 'a', MAX_PATH);
6142
6143     hr = IStorage_EnumElements(stg, 0, NULL, 0, &stgenum);
6144     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
6145
6146     n = 0;
6147     while(TRUE)
6148     {
6149         count = 0;
6150         hr = IEnumSTATSTG_Next(stgenum, 1, &stat, &count);
6151         if(FAILED(hr) || !count)
6152             break;
6153
6154         ok(!lstrcmpW(stat.pwcsName, database_table_data[n].name),
6155            "Expected table %d name to match\n", n);
6156
6157         stm = NULL;
6158         hr = IStorage_OpenStream(stg, stat.pwcsName, NULL,
6159                                  STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm);
6160         ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
6161         ok(stm != NULL, "Expected non-NULL stream\n");
6162
6163         CoTaskMemFree(stat.pwcsName);
6164
6165         sz = MAX_PATH;
6166         memset(data, 'a', MAX_PATH);
6167         hr = IStream_Read(stm, data, sz, &count);
6168         ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
6169
6170         ok(count == database_table_data[n].size,
6171            "Expected %d, got %d\n", database_table_data[n].size, count);
6172
6173         if (!database_table_data[n].size)
6174             ok(!memcmp(data, check, MAX_PATH), "data should not be changed\n");
6175         else
6176             ok(!memcmp(data, database_table_data[n].data, database_table_data[n].size),
6177                "Expected table %d data to match\n", n);
6178
6179         IStream_Release(stm);
6180         n++;
6181     }
6182
6183     ok(n == 3, "Expected 3, got %d\n", n);
6184
6185     IEnumSTATSTG_Release(stgenum);
6186 }
6187
6188 static void test_defaultdatabase(void)
6189 {
6190     UINT r;
6191     HRESULT hr;
6192     MSIHANDLE hdb;
6193     IStorage *stg = NULL;
6194
6195     DeleteFile(msifile);
6196
6197     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
6198     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6199
6200     r = MsiDatabaseCommit(hdb);
6201     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6202
6203     MsiCloseHandle(hdb);
6204
6205     hr = StgOpenStorage(msifileW, NULL, STGM_READ | STGM_SHARE_DENY_WRITE, NULL, 0, &stg);
6206     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
6207     ok(stg != NULL, "Expected non-NULL stg\n");
6208
6209     enum_stream_names(stg);
6210
6211     IStorage_Release(stg);
6212     DeleteFileA(msifile);
6213 }
6214
6215 static void test_order(void)
6216 {
6217     MSIHANDLE hdb, hview, hrec;
6218     CHAR buffer[MAX_PATH];
6219     LPCSTR query;
6220     UINT r, sz;
6221     int val;
6222
6223     hdb = create_db();
6224     ok(hdb, "failed to create db\n");
6225
6226     query = "CREATE TABLE `Empty` ( `A` SHORT NOT NULL PRIMARY KEY `A`)";
6227     r = run_query(hdb, 0, query);
6228     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6229
6230     query = "CREATE TABLE `Mesa` ( `A` SHORT NOT NULL, `B` SHORT, `C` SHORT PRIMARY KEY `A`)";
6231     r = run_query(hdb, 0, query);
6232     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6233
6234     query = "INSERT INTO `Mesa` ( `A`, `B`, `C` ) VALUES ( 1, 2, 9 )";
6235     r = run_query(hdb, 0, query);
6236     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6237
6238     query = "INSERT INTO `Mesa` ( `A`, `B`, `C` ) VALUES ( 3, 4, 7 )";
6239     r = run_query(hdb, 0, query);
6240     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6241
6242     query = "INSERT INTO `Mesa` ( `A`, `B`, `C` ) VALUES ( 5, 6, 8 )";
6243     r = run_query(hdb, 0, query);
6244     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6245
6246     query = "CREATE TABLE `Sideboard` ( `D` SHORT NOT NULL, `E` SHORT, `F` SHORT PRIMARY KEY `D`)";
6247     r = run_query(hdb, 0, query);
6248     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6249
6250     query = "INSERT INTO `Sideboard` ( `D`, `E`, `F` ) VALUES ( 10, 11, 18 )";
6251     r = run_query(hdb, 0, query);
6252     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6253
6254     query = "INSERT INTO `Sideboard` ( `D`, `E`, `F` ) VALUES ( 12, 13, 16 )";
6255     r = run_query(hdb, 0, query);
6256     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6257
6258     query = "INSERT INTO `Sideboard` ( `D`, `E`, `F` ) VALUES ( 14, 15, 17 )";
6259     r = run_query(hdb, 0, query);
6260     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6261
6262     query = "SELECT `A`, `B` FROM `Mesa` ORDER BY `C`";
6263     r = MsiDatabaseOpenView(hdb, query, &hview);
6264     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6265     r = MsiViewExecute(hview, 0);
6266     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6267
6268     r = MsiViewFetch(hview, &hrec);
6269     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6270
6271     val = MsiRecordGetInteger(hrec, 1);
6272     ok(val == 3, "Expected 3, got %d\n", val);
6273
6274     val = MsiRecordGetInteger(hrec, 2);
6275     ok(val == 4, "Expected 3, got %d\n", val);
6276
6277     MsiCloseHandle(hrec);
6278
6279     r = MsiViewFetch(hview, &hrec);
6280     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6281
6282     val = MsiRecordGetInteger(hrec, 1);
6283     ok(val == 5, "Expected 5, got %d\n", val);
6284
6285     val = MsiRecordGetInteger(hrec, 2);
6286     ok(val == 6, "Expected 6, got %d\n", val);
6287
6288     MsiCloseHandle(hrec);
6289
6290     r = MsiViewFetch(hview, &hrec);
6291     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6292
6293     val = MsiRecordGetInteger(hrec, 1);
6294     ok(val == 1, "Expected 1, got %d\n", val);
6295
6296     val = MsiRecordGetInteger(hrec, 2);
6297     ok(val == 2, "Expected 2, got %d\n", val);
6298
6299     MsiCloseHandle(hrec);
6300
6301     r = MsiViewFetch(hview, &hrec);
6302     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6303
6304     MsiViewClose(hview);
6305     MsiCloseHandle(hview);
6306
6307     query = "SELECT `A`, `D` FROM `Mesa`, `Sideboard` ORDER BY `F`";
6308     r = MsiDatabaseOpenView(hdb, query, &hview);
6309     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6310     r = MsiViewExecute(hview, 0);
6311     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6312
6313     r = MsiViewFetch(hview, &hrec);
6314     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6315
6316     val = MsiRecordGetInteger(hrec, 1);
6317     ok(val == 1, "Expected 1, got %d\n", val);
6318
6319     val = MsiRecordGetInteger(hrec, 2);
6320     ok(val == 12, "Expected 12, got %d\n", val);
6321
6322     MsiCloseHandle(hrec);
6323
6324     r = MsiViewFetch(hview, &hrec);
6325     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6326
6327     val = MsiRecordGetInteger(hrec, 1);
6328     ok(val == 3, "Expected 3, got %d\n", val);
6329
6330     val = MsiRecordGetInteger(hrec, 2);
6331     ok(val == 12, "Expected 12, got %d\n", val);
6332
6333     MsiCloseHandle(hrec);
6334
6335     r = MsiViewFetch(hview, &hrec);
6336     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6337
6338     val = MsiRecordGetInteger(hrec, 1);
6339     ok(val == 5, "Expected 5, got %d\n", val);
6340
6341     val = MsiRecordGetInteger(hrec, 2);
6342     ok(val == 12, "Expected 12, got %d\n", val);
6343
6344     MsiCloseHandle(hrec);
6345
6346     r = MsiViewFetch(hview, &hrec);
6347     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6348
6349     val = MsiRecordGetInteger(hrec, 1);
6350     ok(val == 1, "Expected 1, got %d\n", val);
6351
6352     val = MsiRecordGetInteger(hrec, 2);
6353     ok(val == 14, "Expected 14, got %d\n", val);
6354
6355     MsiCloseHandle(hrec);
6356
6357     r = MsiViewFetch(hview, &hrec);
6358     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6359
6360     val = MsiRecordGetInteger(hrec, 1);
6361     ok(val == 3, "Expected 3, got %d\n", val);
6362
6363     val = MsiRecordGetInteger(hrec, 2);
6364     ok(val == 14, "Expected 14, got %d\n", val);
6365
6366     MsiCloseHandle(hrec);
6367
6368     r = MsiViewFetch(hview, &hrec);
6369     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6370
6371     val = MsiRecordGetInteger(hrec, 1);
6372     ok(val == 5, "Expected 5, got %d\n", val);
6373
6374     val = MsiRecordGetInteger(hrec, 2);
6375     ok(val == 14, "Expected 14, got %d\n", val);
6376
6377     MsiCloseHandle(hrec);
6378
6379     r = MsiViewFetch(hview, &hrec);
6380     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6381
6382     val = MsiRecordGetInteger(hrec, 1);
6383     ok(val == 1, "Expected 1, got %d\n", val);
6384
6385     val = MsiRecordGetInteger(hrec, 2);
6386     ok(val == 10, "Expected 10, got %d\n", val);
6387
6388     MsiCloseHandle(hrec);
6389
6390     r = MsiViewFetch(hview, &hrec);
6391     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6392
6393     val = MsiRecordGetInteger(hrec, 1);
6394     ok(val == 3, "Expected 3, got %d\n", val);
6395
6396     val = MsiRecordGetInteger(hrec, 2);
6397     ok(val == 10, "Expected 10, got %d\n", val);
6398
6399     MsiCloseHandle(hrec);
6400
6401     r = MsiViewFetch(hview, &hrec);
6402     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6403
6404     val = MsiRecordGetInteger(hrec, 1);
6405     ok(val == 5, "Expected 5, got %d\n", val);
6406
6407     val = MsiRecordGetInteger(hrec, 2);
6408     ok(val == 10, "Expected 10, got %d\n", val);
6409
6410     MsiCloseHandle(hrec);
6411
6412     r = MsiViewFetch(hview, &hrec);
6413     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6414
6415     MsiViewClose(hview);
6416     MsiCloseHandle(hview);
6417
6418     query = "SELECT * FROM `Empty` ORDER BY `A`";
6419     r = MsiDatabaseOpenView(hdb, query, &hview);
6420     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6421     r = MsiViewExecute(hview, 0);
6422     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6423
6424     r = MsiViewFetch(hview, &hrec);
6425     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6426
6427     MsiViewClose(hview);
6428     MsiCloseHandle(hview);
6429
6430     query = "CREATE TABLE `Buffet` ( `One` CHAR(72), `Two` SHORT PRIMARY KEY `One`)";
6431     r = run_query(hdb, 0, query);
6432     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6433
6434     query = "INSERT INTO `Buffet` ( `One`, `Two` ) VALUES ( 'uno',  2)";
6435     r = run_query(hdb, 0, query);
6436     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6437
6438     query = "INSERT INTO `Buffet` ( `One`, `Two` ) VALUES ( 'dos',  3)";
6439     r = run_query(hdb, 0, query);
6440     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6441
6442     query = "INSERT INTO `Buffet` ( `One`, `Two` ) VALUES ( 'tres',  1)";
6443     r = run_query(hdb, 0, query);
6444     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6445
6446     query = "SELECT * FROM `Buffet` WHERE `One` = 'dos' ORDER BY `Two`";
6447     r = MsiDatabaseOpenView(hdb, query, &hview);
6448     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6449     r = MsiViewExecute(hview, 0);
6450     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6451
6452     r = MsiViewFetch(hview, &hrec);
6453     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6454
6455     sz = sizeof(buffer);
6456     r = MsiRecordGetString(hrec, 1, buffer, &sz);
6457     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6458     ok(!lstrcmp(buffer, "dos"), "Expected \"dos\", got \"%s\"\n", buffer);
6459
6460     r = MsiRecordGetInteger(hrec, 2);
6461     ok(r == 3, "Expected 3, got %d\n", r);
6462
6463     MsiCloseHandle(hrec);
6464
6465     r = MsiViewFetch(hview, &hrec);
6466     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6467
6468     MsiViewClose(hview);
6469     MsiCloseHandle(hview);
6470     MsiCloseHandle(hdb);
6471 }
6472
6473 static void test_viewmodify_delete_temporary(void)
6474 {
6475     MSIHANDLE hdb, hview, hrec;
6476     const char *query;
6477     UINT r;
6478
6479     DeleteFile(msifile);
6480
6481     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
6482     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6483
6484     query = "CREATE TABLE `Table` ( `A` SHORT PRIMARY KEY `A` )";
6485     r = run_query(hdb, 0, query);
6486     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6487
6488     query = "SELECT * FROM `Table`";
6489     r = MsiDatabaseOpenView(hdb, query, &hview);
6490     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6491     r = MsiViewExecute(hview, 0);
6492     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6493
6494     hrec = MsiCreateRecord(1);
6495     MsiRecordSetInteger(hrec, 1, 1);
6496
6497     r = MsiViewModify(hview, MSIMODIFY_INSERT, hrec);
6498     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6499
6500     MsiCloseHandle(hrec);
6501
6502     hrec = MsiCreateRecord(1);
6503     MsiRecordSetInteger(hrec, 1, 2);
6504
6505     r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec);
6506     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6507
6508     MsiCloseHandle(hrec);
6509
6510     hrec = MsiCreateRecord(1);
6511     MsiRecordSetInteger(hrec, 1, 3);
6512
6513     r = MsiViewModify(hview, MSIMODIFY_INSERT, hrec);
6514     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6515
6516     MsiCloseHandle(hrec);
6517
6518     hrec = MsiCreateRecord(1);
6519     MsiRecordSetInteger(hrec, 1, 4);
6520
6521     r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec);
6522     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6523
6524     MsiCloseHandle(hrec);
6525     MsiViewClose(hview);
6526     MsiCloseHandle(hview);
6527
6528     query = "SELECT * FROM `Table` WHERE  `A` = 2";
6529     r = MsiDatabaseOpenView(hdb, query, &hview);
6530     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6531     r = MsiViewExecute(hview, 0);
6532     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6533     r = MsiViewFetch(hview, &hrec);
6534     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6535
6536     r = MsiViewModify(hview, MSIMODIFY_DELETE, hrec);
6537     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6538
6539     MsiCloseHandle(hrec);
6540     MsiViewClose(hview);
6541     MsiCloseHandle(hview);
6542
6543     query = "SELECT * FROM `Table` WHERE  `A` = 3";
6544     r = MsiDatabaseOpenView(hdb, query, &hview);
6545     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6546     r = MsiViewExecute(hview, 0);
6547     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6548     r = MsiViewFetch(hview, &hrec);
6549     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6550
6551     r = MsiViewModify(hview, MSIMODIFY_DELETE, hrec);
6552     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6553
6554     MsiCloseHandle(hrec);
6555     MsiViewClose(hview);
6556     MsiCloseHandle(hview);
6557
6558     query = "SELECT * FROM `Table` ORDER BY `A`";
6559     r = MsiDatabaseOpenView(hdb, query, &hview);
6560     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6561     r = MsiViewExecute(hview, 0);
6562     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6563
6564     r = MsiViewFetch(hview, &hrec);
6565     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6566
6567     r = MsiRecordGetInteger(hrec, 1);
6568     ok(r == 1, "Expected 1, got %d\n", r);
6569
6570     MsiCloseHandle(hrec);
6571
6572     r = MsiViewFetch(hview, &hrec);
6573     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6574
6575     r = MsiRecordGetInteger(hrec, 1);
6576     ok(r == 4, "Expected 4, got %d\n", r);
6577
6578     MsiCloseHandle(hrec);
6579
6580     r = MsiViewFetch(hview, &hrec);
6581     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6582
6583     MsiViewClose(hview);
6584     MsiCloseHandle(hview);
6585     MsiCloseHandle(hdb);
6586     DeleteFileA(msifile);
6587 }
6588
6589 static void test_deleterow(void)
6590 {
6591     MSIHANDLE hdb, hview, hrec;
6592     const char *query;
6593     char buf[MAX_PATH];
6594     UINT r;
6595     DWORD size;
6596
6597     DeleteFile(msifile);
6598
6599     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
6600     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6601
6602     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6603     r = run_query(hdb, 0, query);
6604     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6605
6606     query = "INSERT INTO `Table` (`A`) VALUES ('one')";
6607     r = run_query(hdb, 0, query);
6608     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6609
6610     query = "INSERT INTO `Table` (`A`) VALUES ('two')";
6611     r = run_query(hdb, 0, query);
6612     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6613
6614     query = "DELETE FROM `Table` WHERE `A` = 'one'";
6615     r = run_query(hdb, 0, query);
6616     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6617
6618     r = MsiDatabaseCommit(hdb);
6619     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6620
6621     MsiCloseHandle(hdb);
6622
6623     r = MsiOpenDatabase(msifile, MSIDBOPEN_READONLY, &hdb);
6624     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6625
6626     query = "SELECT * FROM `Table`";
6627     r = MsiDatabaseOpenView(hdb, query, &hview);
6628     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6629     r = MsiViewExecute(hview, 0);
6630     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6631
6632     r = MsiViewFetch(hview, &hrec);
6633     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6634
6635     size = MAX_PATH;
6636     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6637     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6638     ok(!lstrcmpA(buf, "two"), "Expected two, got %s\n", buf);
6639
6640     MsiCloseHandle(hrec);
6641
6642     r = MsiViewFetch(hview, &hrec);
6643     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6644
6645     MsiViewClose(hview);
6646     MsiCloseHandle(hview);
6647     MsiCloseHandle(hdb);
6648     DeleteFileA(msifile);
6649 }
6650
6651 static const CHAR import_dat[] = "A\n"
6652                                  "s72\n"
6653                                  "Table\tA\n"
6654                                  "This is a new 'string' ok\n";
6655
6656 static void test_quotes(void)
6657 {
6658     MSIHANDLE hdb, hview, hrec;
6659     const char *query;
6660     char buf[MAX_PATH];
6661     UINT r;
6662     DWORD size;
6663
6664     DeleteFile(msifile);
6665
6666     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
6667     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6668
6669     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6670     r = run_query(hdb, 0, query);
6671     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6672
6673     query = "INSERT INTO `Table` ( `A` ) VALUES ( 'This is a 'string' ok' )";
6674     r = run_query(hdb, 0, query);
6675     ok(r == ERROR_BAD_QUERY_SYNTAX,
6676        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6677
6678     query = "INSERT INTO `Table` ( `A` ) VALUES ( \"This is a 'string' ok\" )";
6679     r = run_query(hdb, 0, query);
6680     ok(r == ERROR_BAD_QUERY_SYNTAX,
6681        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6682
6683     query = "INSERT INTO `Table` ( `A` ) VALUES ( \"test\" )";
6684     r = run_query(hdb, 0, query);
6685     ok(r == ERROR_BAD_QUERY_SYNTAX,
6686        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6687
6688     query = "INSERT INTO `Table` ( `A` ) VALUES ( 'This is a ''string'' ok' )";
6689     r = run_query(hdb, 0, query);
6690     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6691
6692     query = "INSERT INTO `Table` ( `A` ) VALUES ( 'This is a '''string''' ok' )";
6693     r = run_query(hdb, 0, query);
6694     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6695
6696     query = "INSERT INTO `Table` ( `A` ) VALUES ( 'This is a \'string\' ok' )";
6697     r = run_query(hdb, 0, query);
6698     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6699
6700     query = "INSERT INTO `Table` ( `A` ) VALUES ( 'This is a \"string\" ok' )";
6701     r = run_query(hdb, 0, query);
6702     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6703
6704     query = "SELECT * FROM `Table`";
6705     r = MsiDatabaseOpenView(hdb, query, &hview);
6706     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6707
6708     r = MsiViewExecute(hview, 0);
6709     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6710
6711     r = MsiViewFetch(hview, &hrec);
6712     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6713
6714     size = MAX_PATH;
6715     r = MsiRecordGetString(hrec, 1, buf, &size);
6716     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6717     ok(!lstrcmp(buf, "This is a \"string\" ok"),
6718        "Expected \"This is a \"string\" ok\", got %s\n", buf);
6719
6720     MsiCloseHandle(hrec);
6721
6722     r = MsiViewFetch(hview, &hrec);
6723     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6724
6725     MsiViewClose(hview);
6726     MsiCloseHandle(hview);
6727
6728     write_file("import.idt", import_dat, (sizeof(import_dat) - 1) * sizeof(char));
6729
6730     r = MsiDatabaseImportA(hdb, CURR_DIR, "import.idt");
6731     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6732
6733     DeleteFileA("import.idt");
6734
6735     query = "SELECT * FROM `Table`";
6736     r = MsiDatabaseOpenView(hdb, query, &hview);
6737     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6738
6739     r = MsiViewExecute(hview, 0);
6740     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6741
6742     r = MsiViewFetch(hview, &hrec);
6743     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6744
6745     size = MAX_PATH;
6746     r = MsiRecordGetString(hrec, 1, buf, &size);
6747     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6748     ok(!lstrcmp(buf, "This is a new 'string' ok"),
6749        "Expected \"This is a new 'string' ok\", got %s\n", buf);
6750
6751     MsiCloseHandle(hrec);
6752
6753     r = MsiViewFetch(hview, &hrec);
6754     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6755
6756     MsiViewClose(hview);
6757     MsiCloseHandle(hview);
6758     MsiCloseHandle(hdb);
6759     DeleteFileA(msifile);
6760 }
6761
6762 static void test_carriagereturn(void)
6763 {
6764     MSIHANDLE hdb, hview, hrec;
6765     const char *query;
6766     char buf[MAX_PATH];
6767     UINT r;
6768     DWORD size;
6769
6770     DeleteFile(msifile);
6771
6772     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
6773     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6774
6775     query = "CREATE TABLE `Table`\r ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6776     r = run_query(hdb, 0, query);
6777     ok(r == ERROR_BAD_QUERY_SYNTAX,
6778        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6779
6780     query = "CREATE TABLE `Table` \r( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6781     r = run_query(hdb, 0, query);
6782     ok(r == ERROR_BAD_QUERY_SYNTAX,
6783        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6784
6785     query = "CREATE\r TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6786     r = run_query(hdb, 0, query);
6787     ok(r == ERROR_BAD_QUERY_SYNTAX,
6788        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6789
6790     query = "CREATE TABLE\r `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6791     r = run_query(hdb, 0, query);
6792     ok(r == ERROR_BAD_QUERY_SYNTAX,
6793        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6794
6795     query = "CREATE TABLE `Table` (\r `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6796     r = run_query(hdb, 0, query);
6797     ok(r == ERROR_BAD_QUERY_SYNTAX,
6798        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6799
6800     query = "CREATE TABLE `Table` ( `A`\r CHAR(72) NOT NULL PRIMARY KEY `A` )";
6801     r = run_query(hdb, 0, query);
6802     ok(r == ERROR_BAD_QUERY_SYNTAX,
6803        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6804
6805     query = "CREATE TABLE `Table` ( `A` CHAR(72)\r NOT NULL PRIMARY KEY `A` )";
6806     r = run_query(hdb, 0, query);
6807     ok(r == ERROR_BAD_QUERY_SYNTAX,
6808        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6809
6810     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT\r NULL PRIMARY KEY `A` )";
6811     r = run_query(hdb, 0, query);
6812     ok(r == ERROR_BAD_QUERY_SYNTAX,
6813        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6814
6815     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT \rNULL PRIMARY KEY `A` )";
6816     r = run_query(hdb, 0, query);
6817     ok(r == ERROR_BAD_QUERY_SYNTAX,
6818        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6819
6820     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL\r PRIMARY KEY `A` )";
6821     r = run_query(hdb, 0, query);
6822     ok(r == ERROR_BAD_QUERY_SYNTAX,
6823        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6824
6825     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL \rPRIMARY KEY `A` )";
6826     r = run_query(hdb, 0, query);
6827     ok(r == ERROR_BAD_QUERY_SYNTAX,
6828        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6829
6830     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY\r KEY `A` )";
6831     r = run_query(hdb, 0, query);
6832     ok(r == ERROR_BAD_QUERY_SYNTAX,
6833        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6834
6835     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY \rKEY `A` )";
6836     r = run_query(hdb, 0, query);
6837     ok(r == ERROR_BAD_QUERY_SYNTAX,
6838        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6839
6840     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY\r `A` )";
6841     r = run_query(hdb, 0, query);
6842     ok(r == ERROR_BAD_QUERY_SYNTAX,
6843        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6844
6845     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A`\r )";
6846     r = run_query(hdb, 0, query);
6847     ok(r == ERROR_BAD_QUERY_SYNTAX,
6848        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6849
6850     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )\r";
6851     r = run_query(hdb, 0, query);
6852     ok(r == ERROR_BAD_QUERY_SYNTAX,
6853        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6854
6855     query = "CREATE TABLE `\rOne` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6856     r = run_query(hdb, 0, query);
6857     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6858
6859     query = "CREATE TABLE `Tw\ro` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6860     r = run_query(hdb, 0, query);
6861     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6862
6863     query = "CREATE TABLE `Three\r` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6864     r = run_query(hdb, 0, query);
6865     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6866
6867     query = "CREATE TABLE `Four` ( `A\r` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6868     r = run_query(hdb, 0, query);
6869     ok(r == ERROR_BAD_QUERY_SYNTAX,
6870        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6871
6872     query = "CREATE TABLE `Four` ( `\rA` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6873     r = run_query(hdb, 0, query);
6874     ok(r == ERROR_BAD_QUERY_SYNTAX,
6875        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6876
6877     query = "CREATE TABLE `Four` ( `A` CHAR(72\r) NOT NULL PRIMARY KEY `A` )";
6878     r = run_query(hdb, 0, query);
6879     ok(r == ERROR_BAD_QUERY_SYNTAX,
6880        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6881
6882     query = "CREATE TABLE `Four` ( `A` CHAR(\r72) NOT NULL PRIMARY KEY `A` )";
6883     r = run_query(hdb, 0, query);
6884     ok(r == ERROR_BAD_QUERY_SYNTAX,
6885        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6886
6887     query = "CREATE TABLE `Four` ( `A` CHAR(72) NOT NULL PRIMARY KEY `\rA` )";
6888     r = run_query(hdb, 0, query);
6889     ok(r == ERROR_BAD_QUERY_SYNTAX,
6890        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6891
6892     query = "CREATE TABLE `Four` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A\r` )";
6893     r = run_query(hdb, 0, query);
6894     ok(r == ERROR_BAD_QUERY_SYNTAX,
6895        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6896
6897     query = "CREATE TABLE `Four` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A\r` )";
6898     r = run_query(hdb, 0, query);
6899     ok(r == ERROR_BAD_QUERY_SYNTAX,
6900        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6901
6902     query = "SELECT * FROM `_Tables`";
6903     r = MsiDatabaseOpenView(hdb, query, &hview);
6904     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6905     r = MsiViewExecute(hview, 0);
6906     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6907
6908     r = MsiViewFetch(hview, &hrec);
6909     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6910
6911     size = MAX_PATH;
6912     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6913     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6914     ok(!lstrcmpA(buf, "\rOne"), "Expected \"\\rOne\", got \"%s\"\n", buf);
6915
6916     MsiCloseHandle(hrec);
6917
6918     r = MsiViewFetch(hview, &hrec);
6919     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6920
6921     size = MAX_PATH;
6922     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6923     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6924     ok(!lstrcmpA(buf, "Tw\ro"), "Expected \"Tw\\ro\", got \"%s\"\n", buf);
6925
6926     MsiCloseHandle(hrec);
6927
6928     r = MsiViewFetch(hview, &hrec);
6929     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6930
6931     size = MAX_PATH;
6932     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6933     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6934     ok(!lstrcmpA(buf, "Three\r"), "Expected \"Three\r\", got \"%s\"\n", buf);
6935
6936     MsiCloseHandle(hrec);
6937
6938     r = MsiViewFetch(hview, &hrec);
6939     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6940
6941     MsiViewClose(hview);
6942     MsiCloseHandle(hview);
6943
6944     MsiCloseHandle(hdb);
6945     DeleteFileA(msifile);
6946 }
6947
6948 static void test_noquotes(void)
6949 {
6950     MSIHANDLE hdb, hview, hrec;
6951     const char *query;
6952     char buf[MAX_PATH];
6953     UINT r;
6954     DWORD size;
6955
6956     DeleteFile(msifile);
6957
6958     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
6959     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6960
6961     query = "CREATE TABLE Table ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6962     r = run_query(hdb, 0, query);
6963     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6964
6965     query = "CREATE TABLE `Table` ( A CHAR(72) NOT NULL PRIMARY KEY `A` )";
6966     r = run_query(hdb, 0, query);
6967     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6968
6969     query = "CREATE TABLE `Table2` ( `A` CHAR(72) NOT NULL PRIMARY KEY A )";
6970     r = run_query(hdb, 0, query);
6971     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6972
6973     query = "CREATE TABLE `Table3` ( A CHAR(72) NOT NULL PRIMARY KEY A )";
6974     r = run_query(hdb, 0, query);
6975     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6976
6977     query = "SELECT * FROM `_Tables`";
6978     r = MsiDatabaseOpenView(hdb, query, &hview);
6979     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6980     r = MsiViewExecute(hview, 0);
6981     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6982
6983     r = MsiViewFetch(hview, &hrec);
6984     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6985
6986     size = MAX_PATH;
6987     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6988     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6989     ok(!lstrcmpA(buf, "Table"), "Expected \"Table\", got \"%s\"\n", buf);
6990
6991     MsiCloseHandle(hrec);
6992
6993     r = MsiViewFetch(hview, &hrec);
6994     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6995
6996     size = MAX_PATH;
6997     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6998     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6999     ok(!lstrcmpA(buf, "Table2"), "Expected \"Table2\", got \"%s\"\n", buf);
7000
7001     MsiCloseHandle(hrec);
7002
7003     r = MsiViewFetch(hview, &hrec);
7004     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7005
7006     size = MAX_PATH;
7007     r = MsiRecordGetStringA(hrec, 1, buf, &size);
7008     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7009     ok(!lstrcmpA(buf, "Table3"), "Expected \"Table3\", got \"%s\"\n", buf);
7010
7011     MsiCloseHandle(hrec);
7012
7013     r = MsiViewFetch(hview, &hrec);
7014     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7015
7016     MsiViewClose(hview);
7017     MsiCloseHandle(hview);
7018
7019     query = "SELECT * FROM `_Columns`";
7020     r = MsiDatabaseOpenView(hdb, query, &hview);
7021     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7022     r = MsiViewExecute(hview, 0);
7023     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7024
7025     r = MsiViewFetch(hview, &hrec);
7026     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7027
7028     size = MAX_PATH;
7029     r = MsiRecordGetStringA(hrec, 1, buf, &size);
7030     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7031     ok(!lstrcmpA(buf, "Table"), "Expected \"Table\", got \"%s\"\n", buf);
7032
7033     r = MsiRecordGetInteger(hrec, 2);
7034     ok(r == 1, "Expected 1, got %d\n", r);
7035
7036     size = MAX_PATH;
7037     r = MsiRecordGetStringA(hrec, 3, buf, &size);
7038     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7039     ok(!lstrcmpA(buf, "A"), "Expected \"A\", got \"%s\"\n", buf);
7040
7041     MsiCloseHandle(hrec);
7042
7043     r = MsiViewFetch(hview, &hrec);
7044     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7045
7046     size = MAX_PATH;
7047     r = MsiRecordGetStringA(hrec, 1, buf, &size);
7048     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7049     ok(!lstrcmpA(buf, "Table2"), "Expected \"Table2\", got \"%s\"\n", buf);
7050
7051     r = MsiRecordGetInteger(hrec, 2);
7052     ok(r == 1, "Expected 1, got %d\n", r);
7053
7054     size = MAX_PATH;
7055     r = MsiRecordGetStringA(hrec, 3, buf, &size);
7056     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7057     ok(!lstrcmpA(buf, "A"), "Expected \"A\", got \"%s\"\n", buf);
7058
7059     MsiCloseHandle(hrec);
7060
7061     r = MsiViewFetch(hview, &hrec);
7062     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7063
7064     size = MAX_PATH;
7065     r = MsiRecordGetStringA(hrec, 1, buf, &size);
7066     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7067     ok(!lstrcmpA(buf, "Table3"), "Expected \"Table3\", got \"%s\"\n", buf);
7068
7069     r = MsiRecordGetInteger(hrec, 2);
7070     ok(r == 1, "Expected 1, got %d\n", r);
7071
7072     size = MAX_PATH;
7073     r = MsiRecordGetStringA(hrec, 3, buf, &size);
7074     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7075     ok(!lstrcmpA(buf, "A"), "Expected \"A\", got \"%s\"\n", buf);
7076
7077     MsiCloseHandle(hrec);
7078
7079     r = MsiViewFetch(hview, &hrec);
7080     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7081
7082     MsiViewClose(hview);
7083     MsiCloseHandle(hview);
7084
7085     query = "INSERT INTO Table ( `A` ) VALUES ( 'hi' )";
7086     r = run_query(hdb, 0, query);
7087     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7088
7089     query = "INSERT INTO `Table` ( A ) VALUES ( 'hi' )";
7090     r = run_query(hdb, 0, query);
7091     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7092
7093     query = "INSERT INTO `Table` ( `A` ) VALUES ( hi )";
7094     r = run_query(hdb, 0, query);
7095     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7096
7097     query = "SELECT * FROM Table WHERE `A` = 'hi'";
7098     r = run_query(hdb, 0, query);
7099     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7100
7101     query = "SELECT * FROM `Table` WHERE `A` = hi";
7102     r = run_query(hdb, 0, query);
7103     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7104
7105     query = "SELECT * FROM Table";
7106     r = run_query(hdb, 0, query);
7107     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7108
7109     query = "SELECT * FROM Table2";
7110     r = MsiDatabaseOpenView(hdb, query, &hview);
7111     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7112     r = MsiViewExecute(hview, 0);
7113     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7114
7115     r = MsiViewFetch(hview, &hrec);
7116     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7117
7118     MsiViewClose(hview);
7119     MsiCloseHandle(hview);
7120
7121     query = "SELECT * FROM `Table` WHERE A = 'hi'";
7122     r = MsiDatabaseOpenView(hdb, query, &hview);
7123     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7124     r = MsiViewExecute(hview, 0);
7125     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7126
7127     r = MsiViewFetch(hview, &hrec);
7128     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7129
7130     size = MAX_PATH;
7131     r = MsiRecordGetStringA(hrec, 1, buf, &size);
7132     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7133     ok(!lstrcmpA(buf, "hi"), "Expected \"hi\", got \"%s\"\n", buf);
7134
7135     MsiCloseHandle(hrec);
7136
7137     r = MsiViewFetch(hview, &hrec);
7138     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7139
7140     MsiViewClose(hview);
7141     MsiCloseHandle(hview);
7142     MsiCloseHandle(hdb);
7143     DeleteFileA(msifile);
7144 }
7145
7146 static void read_file_data(LPCSTR filename, LPSTR buffer)
7147 {
7148     HANDLE file;
7149     DWORD read;
7150
7151     file = CreateFileA( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
7152     ZeroMemory(buffer, MAX_PATH);
7153     ReadFile(file, buffer, MAX_PATH, &read, NULL);
7154     CloseHandle(file);
7155 }
7156
7157 static void test_forcecodepage(void)
7158 {
7159     MSIHANDLE hdb;
7160     const char *query;
7161     char buffer[MAX_PATH];
7162     UINT r;
7163
7164     DeleteFile(msifile);
7165     GetCurrentDirectoryA(MAX_PATH, CURR_DIR);
7166
7167     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
7168     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7169
7170     query = "SELECT * FROM `_ForceCodepage`";
7171     r = run_query(hdb, 0, query);
7172     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7173
7174     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
7175     r = run_query(hdb, 0, query);
7176     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7177
7178     query = "SELECT * FROM `_ForceCodepage`";
7179     r = run_query(hdb, 0, query);
7180     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7181
7182     r = MsiDatabaseCommit(hdb);
7183     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7184
7185     query = "SELECT * FROM `_ForceCodepage`";
7186     r = run_query(hdb, 0, query);
7187     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7188
7189     MsiCloseHandle(hdb);
7190
7191     r = MsiOpenDatabase(msifile, MSIDBOPEN_DIRECT, &hdb);
7192     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7193
7194     query = "SELECT * FROM `_ForceCodepage`";
7195     r = run_query(hdb, 0, query);
7196     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7197
7198     r = MsiDatabaseExport(hdb, "_ForceCodepage", CURR_DIR, "forcecodepage.idt");
7199     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7200
7201     read_file_data("forcecodepage.idt", buffer);
7202     ok(!lstrcmpA(buffer, "\r\n\r\n0\t_ForceCodepage\r\n"),
7203        "Expected \"\r\n\r\n0\t_ForceCodepage\r\n\", got \"%s\"\n", buffer);
7204
7205     create_file_data("forcecodepage.idt", "\r\n\r\n850\t_ForceCodepage\r\n", 0);
7206
7207     r = MsiDatabaseImportA(hdb, CURR_DIR, "forcecodepage.idt");
7208     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7209
7210     r = MsiDatabaseExport(hdb, "_ForceCodepage", CURR_DIR, "forcecodepage.idt");
7211     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7212
7213     read_file_data("forcecodepage.idt", buffer);
7214     ok(!lstrcmpA(buffer, "\r\n\r\n850\t_ForceCodepage\r\n"),
7215        "Expected \"\r\n\r\n850\t_ForceCodepage\r\n\", got \"%s\"\n", buffer);
7216
7217     create_file_data("forcecodepage.idt", "\r\n\r\n9999\t_ForceCodepage\r\n", 0);
7218
7219     r = MsiDatabaseImportA(hdb, CURR_DIR, "forcecodepage.idt");
7220     ok(r == ERROR_FUNCTION_FAILED, "Expected ERROR_SUCCESS, got %d\n", r);
7221
7222     MsiCloseHandle(hdb);
7223     DeleteFileA(msifile);
7224     DeleteFileA("forcecodepage.idt");
7225 }
7226
7227 static void test_viewmodify_refresh(void)
7228 {
7229     MSIHANDLE hdb, hview, hrec;
7230     const char *query;
7231     char buffer[MAX_PATH];
7232     UINT r;
7233     DWORD size;
7234
7235     DeleteFile(msifile);
7236
7237     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
7238     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7239
7240     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL, `B` INT PRIMARY KEY `A` )";
7241     r = run_query(hdb, 0, query);
7242     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7243
7244     query = "INSERT INTO `Table` ( `A`, `B` ) VALUES ( 'hi', 1 )";
7245     r = run_query(hdb, 0, query);
7246     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7247
7248     query = "SELECT * FROM `Table`";
7249     r = MsiDatabaseOpenView(hdb, query, &hview);
7250     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7251     r = MsiViewExecute(hview, 0);
7252     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7253
7254     r = MsiViewFetch(hview, &hrec);
7255     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7256
7257     query = "UPDATE `Table` SET `B` = 2 WHERE `A` = 'hi'";
7258     r = run_query(hdb, 0, query);
7259     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7260
7261     r = MsiViewModify(hview, MSIMODIFY_REFRESH, hrec);
7262     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7263
7264     size = MAX_PATH;
7265     r = MsiRecordGetStringA(hrec, 1, buffer, &size);
7266     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7267     ok(!lstrcmpA(buffer, "hi"), "Expected \"hi\", got \"%s\"\n", buffer);
7268     ok(size == 2, "Expected 2, got %d\n", size);
7269
7270     r = MsiRecordGetInteger(hrec, 2);
7271     ok(r == 2, "Expected 2, got %d\n", r);
7272
7273     MsiCloseHandle(hrec);
7274     MsiViewClose(hview);
7275     MsiCloseHandle(hview);
7276
7277     query = "INSERT INTO `Table` ( `A`, `B` ) VALUES ( 'hello', 3 )";
7278     r = run_query(hdb, 0, query);
7279     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7280
7281     query = "SELECT * FROM `Table` WHERE `B` = 3";
7282     r = MsiDatabaseOpenView(hdb, query, &hview);
7283     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7284     r = MsiViewExecute(hview, 0);
7285     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7286
7287     r = MsiViewFetch(hview, &hrec);
7288     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7289
7290     query = "UPDATE `Table` SET `B` = 2 WHERE `A` = 'hello'";
7291     r = run_query(hdb, 0, query);
7292     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7293
7294     query = "INSERT INTO `Table` ( `A`, `B` ) VALUES ( 'hithere', 3 )";
7295     r = run_query(hdb, 0, query);
7296     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7297
7298     r = MsiViewModify(hview, MSIMODIFY_REFRESH, hrec);
7299     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7300
7301     size = MAX_PATH;
7302     r = MsiRecordGetStringA(hrec, 1, buffer, &size);
7303     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7304     ok(!lstrcmpA(buffer, "hello"), "Expected \"hello\", got \"%s\"\n", buffer);
7305     ok(size == 5, "Expected 5, got %d\n", size);
7306
7307     r = MsiRecordGetInteger(hrec, 2);
7308     ok(r == 2, "Expected 2, got %d\n", r);
7309
7310     MsiCloseHandle(hrec);
7311     MsiViewClose(hview);
7312     MsiCloseHandle(hview);
7313     MsiCloseHandle(hdb);
7314     DeleteFileA(msifile);
7315 }
7316
7317 static void test_where_viewmodify(void)
7318 {
7319     MSIHANDLE hdb, hview, hrec;
7320     const char *query;
7321     UINT r;
7322
7323     DeleteFile(msifile);
7324
7325     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
7326     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7327
7328     query = "CREATE TABLE `Table` ( `A` INT, `B` INT PRIMARY KEY `A` )";
7329     r = run_query(hdb, 0, query);
7330     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7331
7332     query = "INSERT INTO `Table` ( `A`, `B` ) VALUES ( 1, 2 )";
7333     r = run_query(hdb, 0, query);
7334     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7335
7336     query = "INSERT INTO `Table` ( `A`, `B` ) VALUES ( 3, 4 )";
7337     r = run_query(hdb, 0, query);
7338     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7339
7340     query = "INSERT INTO `Table` ( `A`, `B` ) VALUES ( 5, 6 )";
7341     r = run_query(hdb, 0, query);
7342     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7343
7344     /* `B` = 3 doesn't match, but the view shouldn't be executed */
7345     query = "SELECT * FROM `Table` WHERE `B` = 3";
7346     r = MsiDatabaseOpenView(hdb, query, &hview);
7347     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7348
7349     hrec = MsiCreateRecord(2);
7350     MsiRecordSetInteger(hrec, 1, 7);
7351     MsiRecordSetInteger(hrec, 2, 8);
7352
7353     r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec);
7354     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7355
7356     MsiCloseHandle(hrec);
7357     MsiViewClose(hview);
7358     MsiCloseHandle(hview);
7359
7360     query = "SELECT * FROM `Table` WHERE `A` = 7";
7361     r = MsiDatabaseOpenView(hdb, query, &hview);
7362     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7363     r = MsiViewExecute(hview, 0);
7364     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7365
7366     r = MsiViewFetch(hview, &hrec);
7367     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7368
7369     r = MsiRecordGetInteger(hrec, 1);
7370     ok(r == 7, "Expected 7, got %d\n", r);
7371
7372     r = MsiRecordGetInteger(hrec, 2);
7373     ok(r == 8, "Expected 8, got %d\n", r);
7374
7375     MsiRecordSetInteger(hrec, 2, 9);
7376
7377     r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
7378     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7379
7380     MsiCloseHandle(hrec);
7381     MsiViewClose(hview);
7382     MsiCloseHandle(hview);
7383
7384     query = "SELECT * FROM `Table` WHERE `A` = 7";
7385     r = MsiDatabaseOpenView(hdb, query, &hview);
7386     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7387     r = MsiViewExecute(hview, 0);
7388     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7389
7390     r = MsiViewFetch(hview, &hrec);
7391     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7392
7393     r = MsiRecordGetInteger(hrec, 1);
7394     ok(r == 7, "Expected 7, got %d\n", r);
7395
7396     r = MsiRecordGetInteger(hrec, 2);
7397     ok(r == 9, "Expected 9, got %d\n", r);
7398
7399     query = "UPDATE `Table` SET `B` = 10 WHERE `A` = 7";
7400     r = run_query(hdb, 0, query);
7401     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7402
7403     r = MsiViewModify(hview, MSIMODIFY_REFRESH, hrec);
7404     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7405
7406     r = MsiRecordGetInteger(hrec, 1);
7407     ok(r == 7, "Expected 7, got %d\n", r);
7408
7409     r = MsiRecordGetInteger(hrec, 2);
7410     ok(r == 10, "Expected 10, got %d\n", r);
7411
7412     MsiCloseHandle(hrec);
7413     MsiViewClose(hview);
7414     MsiCloseHandle(hview);
7415     MsiCloseHandle(hdb);
7416 }
7417
7418 static BOOL create_storage(LPCSTR name)
7419 {
7420     WCHAR nameW[MAX_PATH];
7421     IStorage *stg;
7422     IStream *stm;
7423     HRESULT hr;
7424     DWORD count;
7425     BOOL res = FALSE;
7426
7427     MultiByteToWideChar(CP_ACP, 0, name, -1, nameW, MAX_PATH);
7428     hr = StgCreateDocfile(nameW, STGM_CREATE | STGM_READWRITE |
7429                           STGM_DIRECT | STGM_SHARE_EXCLUSIVE, 0, &stg);
7430     if (FAILED(hr))
7431         return FALSE;
7432
7433     hr = IStorage_CreateStream(stg, nameW, STGM_WRITE | STGM_SHARE_EXCLUSIVE,
7434                                0, 0, &stm);
7435     if (FAILED(hr))
7436         goto done;
7437
7438     hr = IStream_Write(stm, "stgdata", 8, &count);
7439     if (SUCCEEDED(hr))
7440         res = TRUE;
7441
7442 done:
7443     IStream_Release(stm);
7444     IStorage_Release(stg);
7445
7446     return res;
7447 }
7448
7449 static void test_storages_table(void)
7450 {
7451     MSIHANDLE hdb, hview, hrec;
7452     IStorage *stg, *inner;
7453     IStream *stm;
7454     char file[MAX_PATH];
7455     char buf[MAX_PATH];
7456     WCHAR name[MAX_PATH];
7457     LPCSTR query;
7458     HRESULT hr;
7459     DWORD size;
7460     UINT r;
7461
7462     hdb = create_db();
7463     ok(hdb, "failed to create db\n");
7464
7465     r = MsiDatabaseCommit(hdb);
7466     ok(r == ERROR_SUCCESS , "Failed to commit database\n");
7467
7468     MsiCloseHandle(hdb);
7469
7470     r = MsiOpenDatabase(msifile, MSIDBOPEN_TRANSACT, &hdb);
7471     ok(r == ERROR_SUCCESS , "Failed to open database\n");
7472
7473     /* check the column types */
7474     hrec = get_column_info(hdb, "SELECT * FROM `_Storages`", MSICOLINFO_TYPES);
7475     ok(hrec, "failed to get column info hrecord\n");
7476     ok(check_record(hrec, 1, "s62"), "wrong hrecord type\n");
7477     ok(check_record(hrec, 2, "V0"), "wrong hrecord type\n");
7478
7479     MsiCloseHandle(hrec);
7480
7481     /* now try the names */
7482     hrec = get_column_info(hdb, "SELECT * FROM `_Storages`", MSICOLINFO_NAMES);
7483     ok(hrec, "failed to get column info hrecord\n");
7484     ok(check_record(hrec, 1, "Name"), "wrong hrecord type\n");
7485     ok(check_record(hrec, 2, "Data"), "wrong hrecord type\n");
7486
7487     MsiCloseHandle(hrec);
7488
7489     create_storage("storage.bin");
7490
7491     hrec = MsiCreateRecord(2);
7492     MsiRecordSetString(hrec, 1, "stgname");
7493
7494     r = MsiRecordSetStream(hrec, 2, "storage.bin");
7495     ok(r == ERROR_SUCCESS, "Failed to add stream data to the hrecord: %d\n", r);
7496
7497     DeleteFileA("storage.bin");
7498
7499     query = "INSERT INTO `_Storages` (`Name`, `Data`) VALUES (?, ?)";
7500     r = MsiDatabaseOpenView(hdb, query, &hview);
7501     ok(r == ERROR_SUCCESS, "Failed to open database hview: %d\n", r);
7502
7503     r = MsiViewExecute(hview, hrec);
7504     ok(r == ERROR_SUCCESS, "Failed to execute hview: %d\n", r);
7505
7506     MsiCloseHandle(hrec);
7507     MsiViewClose(hview);
7508     MsiCloseHandle(hview);
7509
7510     query = "SELECT `Name`, `Data` FROM `_Storages`";
7511     r = MsiDatabaseOpenView(hdb, query, &hview);
7512     ok(r == ERROR_SUCCESS, "Failed to open database hview: %d\n", r);
7513
7514     r = MsiViewExecute(hview, 0);
7515     ok(r == ERROR_SUCCESS, "Failed to execute hview: %d\n", r);
7516
7517     r = MsiViewFetch(hview, &hrec);
7518     ok(r == ERROR_SUCCESS, "Failed to fetch hrecord: %d\n", r);
7519
7520     size = MAX_PATH;
7521     r = MsiRecordGetString(hrec, 1, file, &size);
7522     ok(r == ERROR_SUCCESS, "Failed to get string: %d\n", r);
7523     ok(!lstrcmp(file, "stgname"), "Expected \"stgname\", got \"%s\"\n", file);
7524
7525     size = MAX_PATH;
7526     lstrcpyA(buf, "apple");
7527     r = MsiRecordReadStream(hrec, 2, buf, &size);
7528     ok(r == ERROR_INVALID_DATA, "Expected ERROR_INVALID_DATA, got %d\n", r);
7529     ok(!lstrcmp(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf);
7530     ok(size == 0, "Expected 0, got %d\n", size);
7531
7532     MsiCloseHandle(hrec);
7533
7534     r = MsiViewFetch(hview, &hrec);
7535     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7536
7537     MsiViewClose(hview);
7538     MsiCloseHandle(hview);
7539
7540     MsiDatabaseCommit(hdb);
7541     MsiCloseHandle(hdb);
7542
7543     MultiByteToWideChar(CP_ACP, 0, msifile, -1, name, MAX_PATH);
7544     hr = StgOpenStorage(name, NULL, STGM_DIRECT | STGM_READ |
7545                         STGM_SHARE_DENY_WRITE, NULL, 0, &stg);
7546     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
7547     ok(stg != NULL, "Expected non-NULL storage\n");
7548
7549     MultiByteToWideChar(CP_ACP, 0, "stgname", -1, name, MAX_PATH);
7550     hr = IStorage_OpenStorage(stg, name, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE,
7551                               NULL, 0, &inner);
7552     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
7553     ok(inner != NULL, "Expected non-NULL storage\n");
7554
7555     MultiByteToWideChar(CP_ACP, 0, "storage.bin", -1, name, MAX_PATH);
7556     hr = IStorage_OpenStream(inner, name, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm);
7557     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
7558     ok(stm != NULL, "Expected non-NULL stream\n");
7559
7560     hr = IStream_Read(stm, buf, MAX_PATH, &size);
7561     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
7562     ok(size == 8, "Expected 8, got %d\n", size);
7563     ok(!lstrcmpA(buf, "stgdata"), "Expected \"stgdata\", got \"%s\"\n", buf);
7564
7565     IStream_Release(stm);
7566     IStorage_Release(inner);
7567
7568     IStorage_Release(stg);
7569     DeleteFileA(msifile);
7570 }
7571
7572 static void test_dbtopackage(void)
7573 {
7574     MSIHANDLE hdb, hpkg;
7575     CHAR package[12], buf[MAX_PATH];
7576     DWORD size;
7577     UINT r;
7578
7579     /* create an empty database, transact mode */
7580     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
7581     ok(r == ERROR_SUCCESS, "Failed to create database\n");
7582
7583     set_summary_info(hdb);
7584
7585     r = create_directory_table(hdb);
7586     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7587
7588     r = create_custom_action_table(hdb);
7589     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7590
7591     r = add_custom_action_entry(hdb, "'SetProp', 51, 'MYPROP', 'grape'");
7592     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7593
7594     sprintf(package, "#%u", hdb);
7595     r = MsiOpenPackage(package, &hpkg);
7596     if (r == ERROR_INSTALL_PACKAGE_REJECTED)
7597     {
7598         skip("Not enough rights to perform tests\n");
7599         goto error;
7600     }
7601     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7602
7603     /* property is not set yet */
7604     size = MAX_PATH;
7605     lstrcpyA(buf, "kiwi");
7606     r = MsiGetProperty(hpkg, "MYPROP", buf, &size);
7607     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7608     ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf);
7609     ok(size == 0, "Expected 0, got %d\n", size);
7610
7611     /* run the custom action to set the property */
7612     r = MsiDoAction(hpkg, "SetProp");
7613     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7614
7615     /* property is now set */
7616     size = MAX_PATH;
7617     lstrcpyA(buf, "kiwi");
7618     r = MsiGetProperty(hpkg, "MYPROP", buf, &size);
7619     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7620     ok(!lstrcmpA(buf, "grape"), "Expected \"grape\", got \"%s\"\n", buf);
7621     ok(size == 5, "Expected 5, got %d\n", size);
7622
7623     MsiCloseHandle(hpkg);
7624
7625     /* reset the package */
7626     r = MsiOpenPackage(package, &hpkg);
7627     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7628
7629     /* property is not set anymore */
7630     size = MAX_PATH;
7631     lstrcpyA(buf, "kiwi");
7632     r = MsiGetProperty(hpkg, "MYPROP", buf, &size);
7633     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7634     todo_wine
7635     {
7636         ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf);
7637         ok(size == 0, "Expected 0, got %d\n", size);
7638     }
7639
7640     MsiCloseHandle(hdb);
7641     MsiCloseHandle(hpkg);
7642
7643     /* create an empty database, direct mode */
7644     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATEDIRECT, &hdb);
7645     ok(r == ERROR_SUCCESS, "Failed to create database\n");
7646
7647     set_summary_info(hdb);
7648
7649     r = create_directory_table(hdb);
7650     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7651
7652     r = create_custom_action_table(hdb);
7653     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7654
7655     r = add_custom_action_entry(hdb, "'SetProp', 51, 'MYPROP', 'grape'");
7656     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7657
7658     sprintf(package, "#%u", hdb);
7659     r = MsiOpenPackage(package, &hpkg);
7660     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7661
7662     /* property is not set yet */
7663     size = MAX_PATH;
7664     lstrcpyA(buf, "kiwi");
7665     r = MsiGetProperty(hpkg, "MYPROP", buf, &size);
7666     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7667     ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf);
7668     ok(size == 0, "Expected 0, got %d\n", size);
7669
7670     /* run the custom action to set the property */
7671     r = MsiDoAction(hpkg, "SetProp");
7672     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7673
7674     /* property is now set */
7675     size = MAX_PATH;
7676     lstrcpyA(buf, "kiwi");
7677     r = MsiGetProperty(hpkg, "MYPROP", buf, &size);
7678     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7679     ok(!lstrcmpA(buf, "grape"), "Expected \"grape\", got \"%s\"\n", buf);
7680     ok(size == 5, "Expected 5, got %d\n", size);
7681
7682     MsiCloseHandle(hpkg);
7683
7684     /* reset the package */
7685     r = MsiOpenPackage(package, &hpkg);
7686     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7687
7688     /* property is not set anymore */
7689     size = MAX_PATH;
7690     lstrcpyA(buf, "kiwi");
7691     r = MsiGetProperty(hpkg, "MYPROP", buf, &size);
7692     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7693     todo_wine
7694     {
7695         ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf);
7696         ok(size == 0, "Expected 0, got %d\n", size);
7697     }
7698
7699     MsiCloseHandle(hpkg);
7700
7701 error:
7702     MsiCloseHandle(hdb);
7703     DeleteFileA(msifile);
7704 }
7705
7706 static void test_droptable(void)
7707 {
7708     MSIHANDLE hdb, hview, hrec;
7709     CHAR buf[MAX_PATH];
7710     LPCSTR query;
7711     DWORD size;
7712     UINT r;
7713
7714     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
7715     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7716
7717     query = "CREATE TABLE `One` ( `A` INT PRIMARY KEY `A` )";
7718     r = run_query(hdb, 0, query);
7719     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7720
7721     query = "SELECT * FROM `One`";
7722     r = do_query(hdb, query, &hrec);
7723     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7724
7725     query = "SELECT * FROM `_Tables` WHERE `Name` = 'One'";
7726     r = MsiDatabaseOpenViewA(hdb, query, &hview);
7727     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7728     r = MsiViewExecute(hview, 0);
7729     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7730
7731     r = MsiViewFetch(hview, &hrec);
7732     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7733
7734     size = MAX_PATH;
7735     r = MsiRecordGetStringA(hrec, 1, buf, &size);
7736     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7737     ok(!lstrcmpA(buf, "One"), "Expected \"One\", got \"%s\"\n", buf);
7738
7739     MsiCloseHandle(hrec);
7740     MsiViewClose(hview);
7741     MsiCloseHandle(hview);
7742
7743     query = "SELECT * FROM `_Columns` WHERE `Table` = 'One'";
7744     r = MsiDatabaseOpenViewA(hdb, query, &hview);
7745     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7746     r = MsiViewExecute(hview, 0);
7747     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7748
7749     r = MsiViewFetch(hview, &hrec);
7750     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7751
7752     size = MAX_PATH;
7753     r = MsiRecordGetStringA(hrec, 1, buf, &size);
7754     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7755     ok(!lstrcmpA(buf, "One"), "Expected \"One\", got \"%s\"\n", buf);
7756
7757     r = MsiRecordGetInteger(hrec, 2);
7758     ok(r == 1, "Expected 1, got %d\n", r);
7759
7760     size = MAX_PATH;
7761     r = MsiRecordGetStringA(hrec, 3, buf, &size);
7762     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7763     ok(!lstrcmpA(buf, "A"), "Expected \"A\", got \"%s\"\n", buf);
7764
7765     MsiCloseHandle(hrec);
7766
7767     r = MsiViewFetch(hview, &hrec);
7768     ok(r == ERROR_NO_MORE_ITEMS,
7769        "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7770
7771     MsiViewClose(hview);
7772     MsiCloseHandle(hview);
7773
7774     query = "DROP `One`";
7775     r = run_query(hdb, 0, query);
7776     ok(r == ERROR_BAD_QUERY_SYNTAX,
7777        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7778
7779     query = "DROP TABLE";
7780     r = run_query(hdb, 0, query);
7781     ok(r == ERROR_BAD_QUERY_SYNTAX,
7782        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7783
7784     query = "DROP TABLE `One`";
7785     hview = 0;
7786     r = MsiDatabaseOpenViewA(hdb, query, &hview);
7787     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7788     r = MsiViewExecute(hview, 0);
7789     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7790
7791     r = MsiViewFetch(hview, &hrec);
7792     ok(r == ERROR_FUNCTION_FAILED,
7793        "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
7794
7795     MsiViewClose(hview);
7796     MsiCloseHandle(hview);
7797
7798     query = "SELECT * FROM `IDontExist`";
7799     r = do_query(hdb, query, &hrec);
7800     ok(r == ERROR_BAD_QUERY_SYNTAX,
7801        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7802
7803     query = "SELECT * FROM `One`";
7804     r = do_query(hdb, query, &hrec);
7805     ok(r == ERROR_BAD_QUERY_SYNTAX,
7806        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7807
7808     query = "CREATE TABLE `One` ( `A` INT PRIMARY KEY `A` )";
7809     r = run_query(hdb, 0, query);
7810     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7811
7812     query = "DROP TABLE One";
7813     r = run_query(hdb, 0, query);
7814     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7815
7816     query = "SELECT * FROM `One`";
7817     r = do_query(hdb, query, &hrec);
7818     ok(r == ERROR_BAD_QUERY_SYNTAX,
7819        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7820
7821     query = "SELECT * FROM `_Tables` WHERE `Name` = 'One'";
7822     r = do_query(hdb, query, &hrec);
7823     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7824
7825     query = "SELECT * FROM `_Columns` WHERE `Table` = 'One'";
7826     r = do_query(hdb, query, &hrec);
7827     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7828
7829     query = "CREATE TABLE `One` ( `B` INT, `C` INT PRIMARY KEY `B` )";
7830     r = run_query(hdb, 0, query);
7831     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7832
7833     query = "SELECT * FROM `One`";
7834     r = do_query(hdb, query, &hrec);
7835     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7836
7837     query = "SELECT * FROM `_Tables` WHERE `Name` = 'One'";
7838     r = MsiDatabaseOpenViewA(hdb, query, &hview);
7839     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7840     r = MsiViewExecute(hview, 0);
7841     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7842
7843     r = MsiViewFetch(hview, &hrec);
7844     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7845
7846     size = MAX_PATH;
7847     r = MsiRecordGetStringA(hrec, 1, buf, &size);
7848     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7849     ok(!lstrcmpA(buf, "One"), "Expected \"One\", got \"%s\"\n", buf);
7850
7851     MsiCloseHandle(hrec);
7852     MsiViewClose(hview);
7853     MsiCloseHandle(hview);
7854
7855     query = "SELECT * FROM `_Columns` WHERE `Table` = 'One'";
7856     r = MsiDatabaseOpenViewA(hdb, query, &hview);
7857     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7858     r = MsiViewExecute(hview, 0);
7859     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7860
7861     r = MsiViewFetch(hview, &hrec);
7862     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7863
7864     size = MAX_PATH;
7865     r = MsiRecordGetStringA(hrec, 1, buf, &size);
7866     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7867     ok(!lstrcmpA(buf, "One"), "Expected \"One\", got \"%s\"\n", buf);
7868
7869     r = MsiRecordGetInteger(hrec, 2);
7870     ok(r == 1, "Expected 1, got %d\n", r);
7871
7872     size = MAX_PATH;
7873     r = MsiRecordGetStringA(hrec, 3, buf, &size);
7874     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7875     ok(!lstrcmpA(buf, "B"), "Expected \"B\", got \"%s\"\n", buf);
7876
7877     MsiCloseHandle(hrec);
7878
7879     r = MsiViewFetch(hview, &hrec);
7880     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7881
7882     size = MAX_PATH;
7883     r = MsiRecordGetStringA(hrec, 1, buf, &size);
7884     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7885     ok(!lstrcmpA(buf, "One"), "Expected \"One\", got \"%s\"\n", buf);
7886
7887     r = MsiRecordGetInteger(hrec, 2);
7888     ok(r == 2, "Expected 2, got %d\n", r);
7889
7890     size = MAX_PATH;
7891     r = MsiRecordGetStringA(hrec, 3, buf, &size);
7892     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7893     ok(!lstrcmpA(buf, "C"), "Expected \"C\", got \"%s\"\n", buf);
7894
7895     MsiCloseHandle(hrec);
7896
7897     r = MsiViewFetch(hview, &hrec);
7898     ok(r == ERROR_NO_MORE_ITEMS,
7899        "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7900
7901     MsiViewClose(hview);
7902     MsiCloseHandle(hview);
7903
7904     query = "DROP TABLE One";
7905     r = run_query(hdb, 0, query);
7906     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7907
7908     query = "SELECT * FROM `One`";
7909     r = do_query(hdb, query, &hrec);
7910     ok(r == ERROR_BAD_QUERY_SYNTAX,
7911        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7912
7913     query = "SELECT * FROM `_Tables` WHERE `Name` = 'One'";
7914     r = do_query(hdb, query, &hrec);
7915     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7916
7917     query = "SELECT * FROM `_Columns` WHERE `Table` = 'One'";
7918     r = do_query(hdb, query, &hrec);
7919     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7920
7921     MsiCloseHandle(hdb);
7922     DeleteFileA(msifile);
7923 }
7924
7925 static void test_dbmerge(void)
7926 {
7927     MSIHANDLE hdb, href, hview, hrec;
7928     CHAR buf[MAX_PATH];
7929     LPCSTR query;
7930     DWORD size;
7931     UINT r;
7932
7933     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
7934     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7935
7936     r = MsiOpenDatabase("refdb.msi", MSIDBOPEN_CREATE, &href);
7937     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7938
7939     /* hDatabase is invalid */
7940     r = MsiDatabaseMergeA(0, href, "MergeErrors");
7941     ok(r == ERROR_INVALID_HANDLE,
7942        "Expected ERROR_INVALID_HANDLE, got %d\n", r);
7943
7944     /* hDatabaseMerge is invalid */
7945     r = MsiDatabaseMergeA(hdb, 0, "MergeErrors");
7946     ok(r == ERROR_INVALID_HANDLE,
7947        "Expected ERROR_INVALID_HANDLE, got %d\n", r);
7948
7949     /* szTableName is NULL */
7950     r = MsiDatabaseMergeA(hdb, href, NULL);
7951     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7952
7953     /* szTableName is empty */
7954     r = MsiDatabaseMergeA(hdb, href, "");
7955     ok(r == ERROR_INVALID_TABLE, "Expected ERROR_INVALID_TABLE, got %d\n", r);
7956
7957     /* both DBs empty, szTableName is valid */
7958     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7959     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7960
7961     query = "CREATE TABLE `One` ( `A` INT PRIMARY KEY `A` )";
7962     r = run_query(hdb, 0, query);
7963     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7964
7965     query = "CREATE TABLE `One` ( `A` CHAR(72) PRIMARY KEY `A` )";
7966     r = run_query(href, 0, query);
7967     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7968
7969     /* column types don't match */
7970     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7971     ok(r == ERROR_DATATYPE_MISMATCH,
7972        "Expected ERROR_DATATYPE_MISMATCH, got %d\n", r);
7973
7974     /* nothing in MergeErrors */
7975     query = "SELECT * FROM `MergeErrors`";
7976     r = do_query(hdb, query, &hrec);
7977     ok(r == ERROR_BAD_QUERY_SYNTAX,
7978        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7979
7980     query = "DROP TABLE `One`";
7981     r = run_query(hdb, 0, query);
7982     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7983
7984     query = "DROP TABLE `One`";
7985     r = run_query(href, 0, query);
7986     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7987
7988     query = "CREATE TABLE `One` ( "
7989         "`A` CHAR(72), "
7990         "`B` CHAR(56), "
7991         "`C` CHAR(64) LOCALIZABLE, "
7992         "`D` LONGCHAR, "
7993         "`E` CHAR(72) NOT NULL, "
7994         "`F` CHAR(56) NOT NULL, "
7995         "`G` CHAR(64) NOT NULL LOCALIZABLE, "
7996         "`H` LONGCHAR NOT NULL "
7997         "PRIMARY KEY `A` )";
7998     r = run_query(hdb, 0, query);
7999     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8000
8001     query = "CREATE TABLE `One` ( "
8002         "`A` CHAR(64), "
8003         "`B` CHAR(64), "
8004         "`C` CHAR(64), "
8005         "`D` CHAR(64), "
8006         "`E` CHAR(64) NOT NULL, "
8007         "`F` CHAR(64) NOT NULL, "
8008         "`G` CHAR(64) NOT NULL, "
8009         "`H` CHAR(64) NOT NULL "
8010         "PRIMARY KEY `A` )";
8011     r = run_query(href, 0, query);
8012     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8013
8014     /* column sting types don't match exactly */
8015     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
8016     ok(r == ERROR_SUCCESS,
8017        "Expected ERROR_SUCCESS, got %d\n", r);
8018
8019     /* nothing in MergeErrors */
8020     query = "SELECT * FROM `MergeErrors`";
8021     r = do_query(hdb, query, &hrec);
8022     ok(r == ERROR_BAD_QUERY_SYNTAX,
8023        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
8024
8025     query = "DROP TABLE `One`";
8026     r = run_query(hdb, 0, query);
8027     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8028
8029     query = "DROP TABLE `One`";
8030     r = run_query(href, 0, query);
8031     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8032
8033     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A` )";
8034     r = run_query(hdb, 0, query);
8035     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8036
8037     query = "CREATE TABLE `One` ( `A` INT, `C` INT PRIMARY KEY `A` )";
8038     r = run_query(href, 0, query);
8039     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8040
8041     /* column names don't match */
8042     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
8043     ok(r == ERROR_DATATYPE_MISMATCH,
8044        "Expected ERROR_DATATYPE_MISMATCH, got %d\n", r);
8045
8046     /* nothing in MergeErrors */
8047     query = "SELECT * FROM `MergeErrors`";
8048     r = do_query(hdb, query, &hrec);
8049     ok(r == ERROR_BAD_QUERY_SYNTAX,
8050        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
8051
8052     query = "DROP TABLE `One`";
8053     r = run_query(hdb, 0, query);
8054     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8055
8056     query = "DROP TABLE `One`";
8057     r = run_query(href, 0, query);
8058     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8059
8060     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A` )";
8061     r = run_query(hdb, 0, query);
8062     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8063
8064     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `B` )";
8065     r = run_query(href, 0, query);
8066     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8067
8068     /* primary keys don't match */
8069     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
8070     ok(r == ERROR_DATATYPE_MISMATCH,
8071        "Expected ERROR_DATATYPE_MISMATCH, got %d\n", r);
8072
8073     /* nothing in MergeErrors */
8074     query = "SELECT * FROM `MergeErrors`";
8075     r = do_query(hdb, query, &hrec);
8076     ok(r == ERROR_BAD_QUERY_SYNTAX,
8077        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
8078
8079     query = "DROP TABLE `One`";
8080     r = run_query(hdb, 0, query);
8081     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8082
8083     query = "DROP TABLE `One`";
8084     r = run_query(href, 0, query);
8085     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8086
8087     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A` )";
8088     r = run_query(hdb, 0, query);
8089     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8090
8091     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A`, `B` )";
8092     r = run_query(href, 0, query);
8093     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8094
8095     /* number of primary keys doesn't match */
8096     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
8097     ok(r == ERROR_DATATYPE_MISMATCH,
8098        "Expected ERROR_DATATYPE_MISMATCH, got %d\n", r);
8099
8100     /* nothing in MergeErrors */
8101     query = "SELECT * FROM `MergeErrors`";
8102     r = do_query(hdb, query, &hrec);
8103     ok(r == ERROR_BAD_QUERY_SYNTAX,
8104        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
8105
8106     query = "DROP TABLE `One`";
8107     r = run_query(hdb, 0, query);
8108     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8109
8110     query = "DROP TABLE `One`";
8111     r = run_query(href, 0, query);
8112     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8113
8114     query = "CREATE TABLE `One` ( `A` INT, `B` INT, `C` INT PRIMARY KEY `A` )";
8115     r = run_query(hdb, 0, query);
8116     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8117
8118     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A` )";
8119     r = run_query(href, 0, query);
8120     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8121
8122     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 1, 2 )";
8123     r = run_query(href, 0, query);
8124     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8125
8126     /* number of columns doesn't match */
8127     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
8128     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8129
8130     query = "SELECT * FROM `One`";
8131     r = do_query(hdb, query, &hrec);
8132     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8133
8134     r = MsiRecordGetInteger(hrec, 1);
8135     ok(r == 1, "Expected 1, got %d\n", r);
8136
8137     r = MsiRecordGetInteger(hrec, 2);
8138     ok(r == 2, "Expected 2, got %d\n", r);
8139
8140     r = MsiRecordGetInteger(hrec, 3);
8141     ok(r == MSI_NULL_INTEGER, "Expected MSI_NULL_INTEGER, got %d\n", r);
8142
8143     MsiCloseHandle(hrec);
8144
8145     /* nothing in MergeErrors */
8146     query = "SELECT * FROM `MergeErrors`";
8147     r = do_query(hdb, query, &hrec);
8148     ok(r == ERROR_BAD_QUERY_SYNTAX,
8149        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
8150
8151     query = "DROP TABLE `One`";
8152     r = run_query(hdb, 0, query);
8153     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8154
8155     query = "DROP TABLE `One`";
8156     r = run_query(href, 0, query);
8157     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8158
8159     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A` )";
8160     r = run_query(hdb, 0, query);
8161     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8162
8163     query = "CREATE TABLE `One` ( `A` INT, `B` INT, `C` INT PRIMARY KEY `A` )";
8164     r = run_query(href, 0, query);
8165     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8166
8167     query = "INSERT INTO `One` ( `A`, `B`, `C` ) VALUES ( 1, 2, 3 )";
8168     r = run_query(href, 0, query);
8169     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8170
8171     /* number of columns doesn't match */
8172     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
8173     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8174
8175     query = "SELECT * FROM `One`";
8176     r = do_query(hdb, query, &hrec);
8177     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8178
8179     r = MsiRecordGetInteger(hrec, 1);
8180     ok(r == 1, "Expected 1, got %d\n", r);
8181
8182     r = MsiRecordGetInteger(hrec, 2);
8183     ok(r == 2, "Expected 2, got %d\n", r);
8184
8185     r = MsiRecordGetInteger(hrec, 3);
8186     ok(r == MSI_NULL_INTEGER, "Expected MSI_NULL_INTEGER, got %d\n", r);
8187
8188     MsiCloseHandle(hrec);
8189
8190     /* nothing in MergeErrors */
8191     query = "SELECT * FROM `MergeErrors`";
8192     r = do_query(hdb, query, &hrec);
8193     ok(r == ERROR_BAD_QUERY_SYNTAX,
8194        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
8195
8196     query = "DROP TABLE `One`";
8197     r = run_query(hdb, 0, query);
8198     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8199
8200     query = "DROP TABLE `One`";
8201     r = run_query(href, 0, query);
8202     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8203
8204     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A` )";
8205     r = run_query(hdb, 0, query);
8206     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8207
8208     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 1, 1 )";
8209     r = run_query(hdb, 0, query);
8210     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8211
8212     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 2, 2 )";
8213     r = run_query(hdb, 0, query);
8214     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8215
8216     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A` )";
8217     r = run_query(href, 0, query);
8218     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8219
8220     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 1, 2 )";
8221     r = run_query(href, 0, query);
8222     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8223
8224     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 2, 3 )";
8225     r = run_query(href, 0, query);
8226     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8227
8228     /* primary keys match, rows do not */
8229     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
8230     ok(r == ERROR_FUNCTION_FAILED,
8231        "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
8232
8233     /* nothing in MergeErrors */
8234     query = "SELECT * FROM `MergeErrors`";
8235     r = do_query(hdb, query, &hrec);
8236     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8237
8238     size = MAX_PATH;
8239     r = MsiRecordGetStringA(hrec, 1, buf, &size);
8240     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8241     ok(!lstrcmpA(buf, "One"), "Expected \"One\", got \"%s\"\n", buf);
8242
8243     r = MsiRecordGetInteger(hrec, 2);
8244     ok(r == 2, "Expected 2, got %d\n", r);
8245
8246     MsiCloseHandle(hrec);
8247
8248     r = MsiDatabaseOpenViewA(hdb, "SELECT * FROM `MergeErrors`", &hview);
8249     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8250
8251     r = MsiViewGetColumnInfo(hview, MSICOLINFO_NAMES, &hrec);
8252     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8253
8254     size = MAX_PATH;
8255     r = MsiRecordGetString(hrec, 1, buf, &size);
8256     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8257     ok(!lstrcmpA(buf, "Table"), "Expected \"Table\", got \"%s\"\n", buf);
8258
8259     size = MAX_PATH;
8260     r = MsiRecordGetString(hrec, 2, buf, &size);
8261     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8262     ok(!lstrcmpA(buf, "NumRowMergeConflicts"),
8263        "Expected \"NumRowMergeConflicts\", got \"%s\"\n", buf);
8264
8265     MsiCloseHandle(hrec);
8266
8267     r = MsiViewGetColumnInfo(hview, MSICOLINFO_TYPES, &hrec);
8268     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8269
8270     size = MAX_PATH;
8271     r = MsiRecordGetString(hrec, 1, buf, &size);
8272     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8273     ok(!lstrcmpA(buf, "s255"), "Expected \"s255\", got \"%s\"\n", buf);
8274
8275     size = MAX_PATH;
8276     r = MsiRecordGetString(hrec, 2, buf, &size);
8277     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8278     ok(!lstrcmpA(buf, "i2"), "Expected \"i2\", got \"%s\"\n", buf);
8279
8280     MsiCloseHandle(hrec);
8281     MsiViewClose(hview);
8282     MsiCloseHandle(hview);
8283
8284     query = "DROP TABLE `MergeErrors`";
8285     r = run_query(hdb, 0, query);
8286     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8287
8288     query = "DROP TABLE `One`";
8289     r = run_query(hdb, 0, query);
8290     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8291
8292     query = "DROP TABLE `One`";
8293     r = run_query(href, 0, query);
8294     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8295
8296     query = "CREATE TABLE `One` ( `A` INT, `B` CHAR(72) PRIMARY KEY `A` )";
8297     r = run_query(href, 0, query);
8298     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8299
8300     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 1, 'hi' )";
8301     r = run_query(href, 0, query);
8302     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8303
8304     /* table from merged database is not in target database */
8305     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
8306     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8307
8308     query = "SELECT * FROM `One`";
8309     r = do_query(hdb, query, &hrec);
8310     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8311
8312     r = MsiRecordGetInteger(hrec, 1);
8313     ok(r == 1, "Expected 1, got %d\n", r);
8314
8315     size = MAX_PATH;
8316     r = MsiRecordGetStringA(hrec, 2, buf, &size);
8317     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8318     ok(!lstrcmpA(buf, "hi"), "Expected \"hi\", got \"%s\"\n", buf);
8319
8320     MsiCloseHandle(hrec);
8321
8322     /* nothing in MergeErrors */
8323     query = "SELECT * FROM `MergeErrors`";
8324     r = do_query(hdb, query, &hrec);
8325     ok(r == ERROR_BAD_QUERY_SYNTAX,
8326        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
8327
8328     query = "DROP TABLE `One`";
8329     r = run_query(hdb, 0, query);
8330     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8331
8332     query = "DROP TABLE `One`";
8333     r = run_query(href, 0, query);
8334     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8335
8336     query = "CREATE TABLE `One` ( "
8337             "`A` CHAR(72), `B` INT PRIMARY KEY `A` )";
8338     r = run_query(hdb, 0, query);
8339     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8340
8341     query = "CREATE TABLE `One` ( "
8342             "`A` CHAR(72), `B` INT PRIMARY KEY `A` )";
8343     r = run_query(href, 0, query);
8344     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8345
8346     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 'hi', 1 )";
8347     r = run_query(href, 0, query);
8348     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8349
8350     /* primary key is string */
8351     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
8352     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8353
8354     query = "SELECT * FROM `One`";
8355     r = do_query(hdb, query, &hrec);
8356     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8357
8358     size = MAX_PATH;
8359     r = MsiRecordGetStringA(hrec, 1, buf, &size);
8360     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8361     ok(!lstrcmpA(buf, "hi"), "Expected \"hi\", got \"%s\"\n", buf);
8362
8363     r = MsiRecordGetInteger(hrec, 2);
8364     ok(r == 1, "Expected 1, got %d\n", r);
8365
8366     MsiCloseHandle(hrec);
8367
8368     /* nothing in MergeErrors */
8369     query = "SELECT * FROM `MergeErrors`";
8370     r = do_query(hdb, query, &hrec);
8371     ok(r == ERROR_BAD_QUERY_SYNTAX,
8372        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
8373
8374     create_file_data("codepage.idt", "\r\n\r\n850\t_ForceCodepage\r\n", 0);
8375
8376     GetCurrentDirectoryA(MAX_PATH, buf);
8377     r = MsiDatabaseImportA(hdb, buf, "codepage.idt");
8378     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8379
8380     query = "DROP TABLE `One`";
8381     r = run_query(hdb, 0, query);
8382     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8383
8384     query = "DROP TABLE `One`";
8385     r = run_query(href, 0, query);
8386     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8387
8388     query = "CREATE TABLE `One` ( "
8389             "`A` INT, `B` CHAR(72) LOCALIZABLE PRIMARY KEY `A` )";
8390     r = run_query(hdb, 0, query);
8391     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8392
8393     query = "CREATE TABLE `One` ( "
8394             "`A` INT, `B` CHAR(72) LOCALIZABLE PRIMARY KEY `A` )";
8395     r = run_query(href, 0, query);
8396     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8397
8398     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 1, 'hi' )";
8399     r = run_query(href, 0, query);
8400     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8401
8402     /* code page does not match */
8403     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
8404     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8405
8406     query = "SELECT * FROM `One`";
8407     r = do_query(hdb, query, &hrec);
8408     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8409
8410     r = MsiRecordGetInteger(hrec, 1);
8411     ok(r == 1, "Expected 1, got %d\n", r);
8412
8413     size = MAX_PATH;
8414     r = MsiRecordGetStringA(hrec, 2, buf, &size);
8415     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8416     ok(!lstrcmpA(buf, "hi"), "Expected \"hi\", got \"%s\"\n", buf);
8417
8418     MsiCloseHandle(hrec);
8419
8420     /* nothing in MergeErrors */
8421     query = "SELECT * FROM `MergeErrors`";
8422     r = do_query(hdb, query, &hrec);
8423     ok(r == ERROR_BAD_QUERY_SYNTAX,
8424        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
8425
8426     query = "DROP TABLE `One`";
8427     r = run_query(hdb, 0, query);
8428     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8429
8430     query = "DROP TABLE `One`";
8431     r = run_query(href, 0, query);
8432     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8433
8434     query = "CREATE TABLE `One` ( `A` INT, `B` OBJECT PRIMARY KEY `A` )";
8435     r = run_query(hdb, 0, query);
8436     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8437
8438     query = "CREATE TABLE `One` ( `A` INT, `B` OBJECT PRIMARY KEY `A` )";
8439     r = run_query(href, 0, query);
8440     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8441
8442     create_file("binary.dat");
8443     hrec = MsiCreateRecord(1);
8444     MsiRecordSetStreamA(hrec, 1, "binary.dat");
8445
8446     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 1, ? )";
8447     r = run_query(href, hrec, query);
8448     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8449
8450     MsiCloseHandle(hrec);
8451
8452     /* binary data to merge */
8453     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
8454     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8455
8456     query = "SELECT * FROM `One`";
8457     r = do_query(hdb, query, &hrec);
8458     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8459
8460     r = MsiRecordGetInteger(hrec, 1);
8461     ok(r == 1, "Expected 1, got %d\n", r);
8462
8463     size = MAX_PATH;
8464     ZeroMemory(buf, MAX_PATH);
8465     r = MsiRecordReadStream(hrec, 2, buf, &size);
8466     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8467     ok(!lstrcmpA(buf, "binary.dat\n"),
8468        "Expected \"binary.dat\\n\", got \"%s\"\n", buf);
8469
8470     MsiCloseHandle(hrec);
8471
8472     /* nothing in MergeErrors */
8473     query = "SELECT * FROM `MergeErrors`";
8474     r = do_query(hdb, query, &hrec);
8475     ok(r == ERROR_BAD_QUERY_SYNTAX,
8476        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
8477
8478     query = "DROP TABLE `One`";
8479     r = run_query(hdb, 0, query);
8480     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8481
8482     query = "DROP TABLE `One`";
8483     r = run_query(href, 0, query);
8484     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8485
8486     query = "CREATE TABLE `One` ( `A` INT, `B` CHAR(72) PRIMARY KEY `A` )";
8487     r = run_query(hdb, 0, query);
8488     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8489     r = run_query(href, 0, query);
8490     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8491
8492     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 1, 'foo' )";
8493     r = run_query(href, 0, query);
8494     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8495
8496     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 2, 'bar' )";
8497     r = run_query(href, 0, query);
8498     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8499
8500     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
8501     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8502
8503     query = "SELECT * FROM `One`";
8504     r = MsiDatabaseOpenViewA(hdb, query, &hview);
8505     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8506     r = MsiViewExecute(hview, 0);
8507     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8508
8509     r = MsiViewFetch(hview, &hrec);
8510     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8511
8512     r = MsiRecordGetInteger(hrec, 1);
8513     ok(r == 1, "Expected 1, got %d\n", r);
8514
8515     size = MAX_PATH;
8516     r = MsiRecordGetStringA(hrec, 2, buf, &size);
8517     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8518     ok(!lstrcmpA(buf, "foo"), "Expected \"foo\", got \"%s\"\n", buf);
8519
8520     MsiCloseHandle(hrec);
8521
8522     r = MsiViewFetch(hview, &hrec);
8523     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8524
8525     r = MsiRecordGetInteger(hrec, 1);
8526     ok(r == 2, "Expected 2, got %d\n", r);
8527
8528     size = MAX_PATH;
8529     r = MsiRecordGetStringA(hrec, 2, buf, &size);
8530     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8531     ok(!lstrcmpA(buf, "bar"), "Expected \"bar\", got \"%s\"\n", buf);
8532
8533     MsiCloseHandle(hrec);
8534
8535     r = MsiViewFetch(hview, &hrec);
8536     ok(r == ERROR_NO_MORE_ITEMS,
8537        "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
8538
8539     MsiViewClose(hview);
8540     MsiCloseHandle(hview);
8541
8542     MsiCloseHandle(hdb);
8543     MsiCloseHandle(href);
8544     DeleteFileA(msifile);
8545     DeleteFileA("refdb.msi");
8546     DeleteFileA("codepage.idt");
8547     DeleteFileA("binary.dat");
8548 }
8549
8550 static void test_select_with_tablenames(void)
8551 {
8552     MSIHANDLE hdb, view, rec;
8553     LPCSTR query;
8554     UINT r;
8555     int i;
8556
8557     int vals[4][2] = {
8558         {1,12},
8559         {4,12},
8560         {1,15},
8561         {4,15}};
8562
8563     hdb = create_db();
8564     ok(hdb, "failed to create db\n");
8565
8566     /* Build a pair of tables with the same column names, but unique data */
8567     query = "CREATE TABLE `T1` ( `A` SHORT, `B` SHORT PRIMARY KEY `A`)";
8568     r = run_query(hdb, 0, query);
8569     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8570
8571     query = "INSERT INTO `T1` ( `A`, `B` ) VALUES ( 1, 2 )";
8572     r = run_query(hdb, 0, query);
8573     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8574
8575     query = "INSERT INTO `T1` ( `A`, `B` ) VALUES ( 4, 5 )";
8576     r = run_query(hdb, 0, query);
8577     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8578
8579     query = "CREATE TABLE `T2` ( `A` SHORT, `B` SHORT PRIMARY KEY `A`)";
8580     r = run_query(hdb, 0, query);
8581     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8582
8583     query = "INSERT INTO `T2` ( `A`, `B` ) VALUES ( 11, 12 )";
8584     r = run_query(hdb, 0, query);
8585     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8586
8587     query = "INSERT INTO `T2` ( `A`, `B` ) VALUES ( 14, 15 )";
8588     r = run_query(hdb, 0, query);
8589     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8590
8591
8592     /* Test that selection based on prefixing the column with the table
8593      * actually selects the right data */
8594
8595     query = "SELECT T1.A, T2.B FROM T1,T2";
8596     r = MsiDatabaseOpenView(hdb, query, &view);
8597     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8598     r = MsiViewExecute(view, 0);
8599     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8600
8601     for (i = 0; i < 4; i++)
8602     {
8603         r = MsiViewFetch(view, &rec);
8604         ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8605
8606         r = MsiRecordGetInteger(rec, 1);
8607         ok(r == vals[i][0], "Expected %d, got %d\n", vals[i][0], r);
8608
8609         r = MsiRecordGetInteger(rec, 2);
8610         ok(r == vals[i][1], "Expected %d, got %d\n", vals[i][1], r);
8611
8612         MsiCloseHandle(rec);
8613     }
8614
8615     r = MsiViewFetch(view, &rec);
8616     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
8617
8618     MsiViewClose(view);
8619     MsiCloseHandle(view);
8620     MsiCloseHandle(hdb);
8621     DeleteFileA(msifile);
8622 }
8623
8624 static const UINT ordervals[6][3] =
8625 {
8626     { MSI_NULL_INTEGER, 12, 13 },
8627     { 1, 2, 3 },
8628     { 6, 4, 5 },
8629     { 8, 9, 7 },
8630     { 10, 11, MSI_NULL_INTEGER },
8631     { 14, MSI_NULL_INTEGER, 15 }
8632 };
8633
8634 static void test_insertorder(void)
8635 {
8636     MSIHANDLE hdb, view, rec;
8637     LPCSTR query;
8638     UINT r;
8639     int i;
8640
8641     hdb = create_db();
8642     ok(hdb, "failed to create db\n");
8643
8644     query = "CREATE TABLE `T` ( `A` SHORT, `B` SHORT, `C` SHORT PRIMARY KEY `A`)";
8645     r = run_query(hdb, 0, query);
8646     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8647
8648     query = "INSERT INTO `T` ( `A`, `B`, `C` ) VALUES ( 1, 2, 3 )";
8649     r = run_query(hdb, 0, query);
8650     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8651
8652     query = "INSERT INTO `T` ( `B`, `C`, `A` ) VALUES ( 4, 5, 6 )";
8653     r = run_query(hdb, 0, query);
8654     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8655
8656     query = "INSERT INTO `T` ( `C`, `A`, `B` ) VALUES ( 7, 8, 9 )";
8657     r = run_query(hdb, 0, query);
8658     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8659
8660     query = "INSERT INTO `T` ( `A`, `B` ) VALUES ( 10, 11 )";
8661     r = run_query(hdb, 0, query);
8662     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8663
8664     query = "INSERT INTO `T` ( `B`, `C` ) VALUES ( 12, 13 )";
8665     r = run_query(hdb, 0, query);
8666     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8667
8668     /* fails because the primary key already
8669      * has an MSI_NULL_INTEGER value set above
8670      */
8671     query = "INSERT INTO `T` ( `C` ) VALUES ( 14 )";
8672     r = run_query(hdb, 0, query);
8673     ok(r == ERROR_FUNCTION_FAILED,
8674        "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
8675
8676     /* replicate the error where primary key is set twice */
8677     query = "INSERT INTO `T` ( `A`, `C` ) VALUES ( 1, 14 )";
8678     r = run_query(hdb, 0, query);
8679     ok(r == ERROR_FUNCTION_FAILED,
8680        "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
8681
8682     query = "INSERT INTO `T` ( `A`, `C` ) VALUES ( 14, 15 )";
8683     r = run_query(hdb, 0, query);
8684     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8685
8686     query = "INSERT INTO `T` VALUES ( 16 )";
8687     r = run_query(hdb, 0, query);
8688     ok(r == ERROR_BAD_QUERY_SYNTAX,
8689        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
8690
8691     query = "INSERT INTO `T` VALUES ( 17, 18 )";
8692     r = run_query(hdb, 0, query);
8693     ok(r == ERROR_BAD_QUERY_SYNTAX,
8694        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
8695
8696     query = "INSERT INTO `T` VALUES ( 19, 20, 21 )";
8697     r = run_query(hdb, 0, query);
8698     ok(r == ERROR_BAD_QUERY_SYNTAX,
8699        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
8700
8701     query = "SELECT * FROM `T`";
8702     r = MsiDatabaseOpenView(hdb, query, &view);
8703     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8704     r = MsiViewExecute(view, 0);
8705     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8706
8707     for (i = 0; i < 6; i++)
8708     {
8709         r = MsiViewFetch(view, &rec);
8710         ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8711
8712         r = MsiRecordGetInteger(rec, 1);
8713         ok(r == ordervals[i][0], "Expected %d, got %d\n", ordervals[i][0], r);
8714
8715         r = MsiRecordGetInteger(rec, 2);
8716         ok(r == ordervals[i][1], "Expected %d, got %d\n", ordervals[i][1], r);
8717
8718         r = MsiRecordGetInteger(rec, 3);
8719         ok(r == ordervals[i][2], "Expected %d, got %d\n", ordervals[i][2], r);
8720
8721         MsiCloseHandle(rec);
8722     }
8723
8724     r = MsiViewFetch(view, &rec);
8725     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
8726
8727     MsiViewClose(view);
8728     MsiCloseHandle(view);
8729
8730     query = "DELETE FROM `T` WHERE `A` IS NULL";
8731     r = run_query(hdb, 0, query);
8732     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8733
8734     query = "INSERT INTO `T` ( `B`, `C` ) VALUES ( 12, 13 ) TEMPORARY";
8735     r = run_query(hdb, 0, query);
8736     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8737
8738     query = "SELECT * FROM `T`";
8739     r = MsiDatabaseOpenView(hdb, query, &view);
8740     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8741     r = MsiViewExecute(view, 0);
8742     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8743
8744     for (i = 0; i < 6; i++)
8745     {
8746         r = MsiViewFetch(view, &rec);
8747         ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8748
8749         r = MsiRecordGetInteger(rec, 1);
8750         ok(r == ordervals[i][0], "Expected %d, got %d\n", ordervals[i][0], r);
8751
8752         r = MsiRecordGetInteger(rec, 2);
8753         ok(r == ordervals[i][1], "Expected %d, got %d\n", ordervals[i][1], r);
8754
8755         r = MsiRecordGetInteger(rec, 3);
8756         ok(r == ordervals[i][2], "Expected %d, got %d\n", ordervals[i][2], r);
8757
8758         MsiCloseHandle(rec);
8759     }
8760
8761     r = MsiViewFetch(view, &rec);
8762     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
8763
8764     MsiViewClose(view);
8765     MsiCloseHandle(view);
8766     MsiCloseHandle(hdb);
8767     DeleteFileA(msifile);
8768 }
8769
8770 static void test_columnorder(void)
8771 {
8772     MSIHANDLE hdb, view, rec;
8773     char buf[MAX_PATH];
8774     LPCSTR query;
8775     DWORD sz;
8776     UINT r;
8777
8778     hdb = create_db();
8779     ok(hdb, "failed to create db\n");
8780
8781     /* Each column is a slot:
8782      * ---------------------
8783      * | B | C | A | E | D |
8784      * ---------------------
8785      *
8786      * When a column is selected as a primary key,
8787      * the column occupying the nth primary key slot is swapped
8788      * with the current position of the primary key in question:
8789      *
8790      * set primary key `D`
8791      * ---------------------    ---------------------
8792      * | B | C | A | E | D | -> | D | C | A | E | B |
8793      * ---------------------    ---------------------
8794      *
8795      * set primary key `E`
8796      * ---------------------    ---------------------
8797      * | D | C | A | E | B | -> | D | E | A | C | B |
8798      * ---------------------    ---------------------
8799      */
8800
8801     query = "CREATE TABLE `T` ( `B` SHORT NOT NULL, `C` SHORT NOT NULL, "
8802             "`A` CHAR(255), `E` INT, `D` CHAR(255) NOT NULL "
8803             "PRIMARY KEY `D`, `E`)";
8804     r = run_query(hdb, 0, query);
8805     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8806
8807     query = "SELECT * FROM `T`";
8808     r = MsiDatabaseOpenView(hdb, query, &view);
8809     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8810
8811     r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
8812     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8813
8814     sz = MAX_PATH;
8815     lstrcpyA(buf, "kiwi");
8816     r = MsiRecordGetString(rec, 1, buf, &sz);
8817     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8818     ok(!lstrcmpA("s255", buf), "Expected \"s255\", got \"%s\"\n", buf);
8819
8820     sz = MAX_PATH;
8821     lstrcpyA(buf, "kiwi");
8822     r = MsiRecordGetString(rec, 2, buf, &sz);
8823     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8824     ok(!lstrcmpA("I2", buf), "Expected \"I2\", got \"%s\"\n", buf);
8825
8826     sz = MAX_PATH;
8827     lstrcpyA(buf, "kiwi");
8828     r = MsiRecordGetString(rec, 3, buf, &sz);
8829     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8830     ok(!lstrcmpA("S255", buf), "Expected \"S255\", got \"%s\"\n", buf);
8831
8832     sz = MAX_PATH;
8833     lstrcpyA(buf, "kiwi");
8834     r = MsiRecordGetString(rec, 4, buf, &sz);
8835     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8836     ok(!lstrcmpA("i2", buf), "Expected \"i2\", got \"%s\"\n", buf);
8837
8838     sz = MAX_PATH;
8839     lstrcpyA(buf, "kiwi");
8840     r = MsiRecordGetString(rec, 5, buf, &sz);
8841     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8842     ok(!lstrcmpA("i2", buf), "Expected \"i2\", got \"%s\"\n", buf);
8843
8844     MsiCloseHandle(rec);
8845
8846     r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec);
8847     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8848
8849     sz = MAX_PATH;
8850     lstrcpyA(buf, "kiwi");
8851     r = MsiRecordGetString(rec, 1, buf, &sz);
8852     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8853     ok(!lstrcmpA("D", buf), "Expected \"D\", got \"%s\"\n", buf);
8854
8855     sz = MAX_PATH;
8856     lstrcpyA(buf, "kiwi");
8857     r = MsiRecordGetString(rec, 2, buf, &sz);
8858     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8859     ok(!lstrcmpA("E", buf), "Expected \"E\", got \"%s\"\n", buf);
8860
8861     sz = MAX_PATH;
8862     lstrcpyA(buf, "kiwi");
8863     r = MsiRecordGetString(rec, 3, buf, &sz);
8864     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8865     ok(!lstrcmpA("A", buf), "Expected \"A\", got \"%s\"\n", buf);
8866
8867     sz = MAX_PATH;
8868     lstrcpyA(buf, "kiwi");
8869     r = MsiRecordGetString(rec, 4, buf, &sz);
8870     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8871     ok(!lstrcmpA("C", buf), "Expected \"C\", got \"%s\"\n", buf);
8872
8873     sz = MAX_PATH;
8874     lstrcpyA(buf, "kiwi");
8875     r = MsiRecordGetString(rec, 5, buf, &sz);
8876     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8877     ok(!lstrcmpA("B", buf), "Expected \"B\", got \"%s\"\n", buf);
8878
8879     MsiCloseHandle(rec);
8880     MsiViewClose(view);
8881     MsiCloseHandle(view);
8882
8883     query = "INSERT INTO `T` ( `B`, `C`, `A`, `E`, `D` ) "
8884             "VALUES ( 1, 2, 'a', 3, 'bc' )";
8885     r = run_query(hdb, 0, query);
8886     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8887
8888     query = "SELECT * FROM `T`";
8889     r = do_query(hdb, query, &rec);
8890     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8891
8892     sz = MAX_PATH;
8893     lstrcpyA(buf, "kiwi");
8894     r = MsiRecordGetString(rec, 1, buf, &sz);
8895     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8896     ok(!lstrcmpA("bc", buf), "Expected \"bc\", got \"%s\"\n", buf);
8897
8898     r = MsiRecordGetInteger(rec, 2);
8899     ok(r == 3, "Expected 3, got %d\n", r);
8900
8901     sz = MAX_PATH;
8902     lstrcpyA(buf, "kiwi");
8903     r = MsiRecordGetString(rec, 3, buf, &sz);
8904     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8905     ok(!lstrcmpA("a", buf), "Expected \"a\", got \"%s\"\n", buf);
8906
8907     r = MsiRecordGetInteger(rec, 4);
8908     ok(r == 2, "Expected 2, got %d\n", r);
8909
8910     r = MsiRecordGetInteger(rec, 5);
8911     ok(r == 1, "Expected 1, got %d\n", r);
8912
8913     MsiCloseHandle(rec);
8914
8915     query = "SELECT * FROM `_Columns` WHERE `Table` = 'T'";
8916     r = MsiDatabaseOpenView(hdb, query, &view);
8917     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8918     r = MsiViewExecute(view, 0);
8919     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8920
8921     r = MsiViewFetch(view, &rec);
8922     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8923
8924     sz = MAX_PATH;
8925     lstrcpyA(buf, "kiwi");
8926     r = MsiRecordGetString(rec, 1, buf, &sz);
8927     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8928     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
8929
8930     r = MsiRecordGetInteger(rec, 2);
8931     ok(r == 1, "Expected 1, got %d\n", r);
8932
8933     sz = MAX_PATH;
8934     lstrcpyA(buf, "kiwi");
8935     r = MsiRecordGetString(rec, 3, buf, &sz);
8936     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8937     ok(!lstrcmpA("D", buf), "Expected \"D\", got \"%s\"\n", buf);
8938
8939     MsiCloseHandle(rec);
8940
8941     r = MsiViewFetch(view, &rec);
8942     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8943
8944     sz = MAX_PATH;
8945     lstrcpyA(buf, "kiwi");
8946     r = MsiRecordGetString(rec, 1, buf, &sz);
8947     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8948     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
8949
8950     r = MsiRecordGetInteger(rec, 2);
8951     ok(r == 2, "Expected 2, got %d\n", r);
8952
8953     sz = MAX_PATH;
8954     lstrcpyA(buf, "kiwi");
8955     r = MsiRecordGetString(rec, 3, buf, &sz);
8956     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8957     ok(!lstrcmpA("E", buf), "Expected \"E\", got \"%s\"\n", buf);
8958
8959     MsiCloseHandle(rec);
8960
8961     r = MsiViewFetch(view, &rec);
8962     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8963
8964     sz = MAX_PATH;
8965     lstrcpyA(buf, "kiwi");
8966     r = MsiRecordGetString(rec, 1, buf, &sz);
8967     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8968     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
8969
8970     r = MsiRecordGetInteger(rec, 2);
8971     ok(r == 3, "Expected 3, got %d\n", r);
8972
8973     sz = MAX_PATH;
8974     lstrcpyA(buf, "kiwi");
8975     r = MsiRecordGetString(rec, 3, buf, &sz);
8976     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8977     ok(!lstrcmpA("A", buf), "Expected \"A\", got \"%s\"\n", buf);
8978
8979     MsiCloseHandle(rec);
8980
8981     r = MsiViewFetch(view, &rec);
8982     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8983
8984     sz = MAX_PATH;
8985     lstrcpyA(buf, "kiwi");
8986     r = MsiRecordGetString(rec, 1, buf, &sz);
8987     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8988     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
8989
8990     r = MsiRecordGetInteger(rec, 2);
8991     ok(r == 4, "Expected 4, got %d\n", r);
8992
8993     sz = MAX_PATH;
8994     lstrcpyA(buf, "kiwi");
8995     r = MsiRecordGetString(rec, 3, buf, &sz);
8996     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8997     ok(!lstrcmpA("C", buf), "Expected \"C\", got \"%s\"\n", buf);
8998
8999     MsiCloseHandle(rec);
9000
9001     r = MsiViewFetch(view, &rec);
9002     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
9003
9004     sz = MAX_PATH;
9005     lstrcpyA(buf, "kiwi");
9006     r = MsiRecordGetString(rec, 1, buf, &sz);
9007     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
9008     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
9009
9010     r = MsiRecordGetInteger(rec, 2);
9011     ok(r == 5, "Expected 5, got %d\n", r);
9012
9013     sz = MAX_PATH;
9014     lstrcpyA(buf, "kiwi");
9015     r = MsiRecordGetString(rec, 3, buf, &sz);
9016     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
9017     ok(!lstrcmpA("B", buf), "Expected \"B\", got \"%s\"\n", buf);
9018
9019     MsiCloseHandle(rec);
9020
9021     r = MsiViewFetch(view, &rec);
9022     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
9023
9024     MsiViewClose(view);
9025     MsiCloseHandle(view);
9026
9027     query = "CREATE TABLE `Z` ( `B` SHORT NOT NULL, `C` SHORT NOT NULL, "
9028             "`A` CHAR(255), `E` INT, `D` CHAR(255) NOT NULL "
9029             "PRIMARY KEY `C`, `A`, `D`)";
9030     r = run_query(hdb, 0, query);
9031     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
9032
9033     query = "SELECT * FROM `Z`";
9034     r = MsiDatabaseOpenView(hdb, query, &view);
9035     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
9036
9037     r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
9038     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
9039
9040     sz = MAX_PATH;
9041     lstrcpyA(buf, "kiwi");
9042     r = MsiRecordGetString(rec, 1, buf, &sz);
9043     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
9044     ok(!lstrcmpA("i2", buf), "Expected \"i2\", got \"%s\"\n", buf);
9045
9046     sz = MAX_PATH;
9047     lstrcpyA(buf, "kiwi");
9048     r = MsiRecordGetString(rec, 2, buf, &sz);
9049     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
9050     ok(!lstrcmpA("S255", buf), "Expected \"S255\", got \"%s\"\n", buf);
9051
9052     sz = MAX_PATH;
9053     lstrcpyA(buf, "kiwi");
9054     r = MsiRecordGetString(rec, 3, buf, &sz);
9055     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
9056     ok(!lstrcmpA("s255", buf), "Expected \"s255\", got \"%s\"\n", buf);
9057
9058     sz = MAX_PATH;
9059     lstrcpyA(buf, "kiwi");
9060     r = MsiRecordGetString(rec, 4, buf, &sz);
9061     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
9062     ok(!lstrcmpA("I2", buf), "Expected \"I2\", got \"%s\"\n", buf);
9063
9064     sz = MAX_PATH;
9065     lstrcpyA(buf, "kiwi");
9066     r = MsiRecordGetString(rec, 5, buf, &sz);
9067     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
9068     ok(!lstrcmpA("i2", buf), "Expected \"i2\", got \"%s\"\n", buf);
9069
9070     MsiCloseHandle(rec);
9071
9072     r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec);
9073     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
9074
9075     sz = MAX_PATH;
9076     lstrcpyA(buf, "kiwi");
9077     r = MsiRecordGetString(rec, 1, buf, &sz);
9078     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
9079     ok(!lstrcmpA("C", buf), "Expected \"C\", got \"%s\"\n", buf);
9080
9081     sz = MAX_PATH;
9082     lstrcpyA(buf, "kiwi");
9083     r = MsiRecordGetString(rec, 2, buf, &sz);
9084     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
9085     ok(!lstrcmpA("A", buf), "Expected \"A\", got \"%s\"\n", buf);
9086
9087     sz = MAX_PATH;
9088     lstrcpyA(buf, "kiwi");
9089     r = MsiRecordGetString(rec, 3, buf, &sz);
9090     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
9091     ok(!lstrcmpA("D", buf), "Expected \"D\", got \"%s\"\n", buf);
9092
9093     sz = MAX_PATH;
9094     lstrcpyA(buf, "kiwi");
9095     r = MsiRecordGetString(rec, 4, buf, &sz);
9096     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
9097     ok(!lstrcmpA("E", buf), "Expected \"E\", got \"%s\"\n", buf);
9098
9099     sz = MAX_PATH;
9100     lstrcpyA(buf, "kiwi");
9101     r = MsiRecordGetString(rec, 5, buf, &sz);
9102     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
9103     ok(!lstrcmpA("B", buf), "Expected \"B\", got \"%s\"\n", buf);
9104
9105     MsiCloseHandle(rec);
9106     MsiViewClose(view);
9107     MsiCloseHandle(view);
9108
9109     query = "INSERT INTO `Z` ( `B`, `C`, `A`, `E`, `D` ) "
9110             "VALUES ( 1, 2, 'a', 3, 'bc' )";
9111     r = run_query(hdb, 0, query);
9112     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
9113
9114     query = "SELECT * FROM `Z`";
9115     r = do_query(hdb, query, &rec);
9116     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
9117
9118     r = MsiRecordGetInteger(rec, 1);
9119     ok(r == 2, "Expected 2, got %d\n", r);
9120
9121     sz = MAX_PATH;
9122     lstrcpyA(buf, "kiwi");
9123     r = MsiRecordGetString(rec, 2, buf, &sz);
9124     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
9125     ok(!lstrcmpA("a", buf), "Expected \"a\", got \"%s\"\n", buf);
9126
9127     sz = MAX_PATH;
9128     lstrcpyA(buf, "kiwi");
9129     r = MsiRecordGetString(rec, 3, buf, &sz);
9130     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
9131     ok(!lstrcmpA("bc", buf), "Expected \"bc\", got \"%s\"\n", buf);
9132
9133     r = MsiRecordGetInteger(rec, 4);
9134     ok(r == 3, "Expected 3, got %d\n", r);
9135
9136     r = MsiRecordGetInteger(rec, 5);
9137     ok(r == 1, "Expected 1, got %d\n", r);
9138
9139     MsiCloseHandle(rec);
9140
9141     query = "SELECT * FROM `_Columns` WHERE `Table` = 'T'";
9142     r = MsiDatabaseOpenView(hdb, query, &view);
9143     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
9144     r = MsiViewExecute(view, 0);
9145     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
9146
9147     r = MsiViewFetch(view, &rec);
9148     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
9149
9150     sz = MAX_PATH;
9151     lstrcpyA(buf, "kiwi");
9152     r = MsiRecordGetString(rec, 1, buf, &sz);
9153     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
9154     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
9155
9156     r = MsiRecordGetInteger(rec, 2);
9157     ok(r == 1, "Expected 1, got %d\n", r);
9158
9159     sz = MAX_PATH;
9160     lstrcpyA(buf, "kiwi");
9161     r = MsiRecordGetString(rec, 3, buf, &sz);
9162     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
9163     ok(!lstrcmpA("D", buf), "Expected \"D\", got \"%s\"\n", buf);
9164
9165     MsiCloseHandle(rec);
9166
9167     r = MsiViewFetch(view, &rec);
9168     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
9169
9170     sz = MAX_PATH;
9171     lstrcpyA(buf, "kiwi");
9172     r = MsiRecordGetString(rec, 1, buf, &sz);
9173     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
9174     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
9175
9176     r = MsiRecordGetInteger(rec, 2);
9177     ok(r == 2, "Expected 2, got %d\n", r);
9178
9179     sz = MAX_PATH;
9180     lstrcpyA(buf, "kiwi");
9181     r = MsiRecordGetString(rec, 3, buf, &sz);
9182     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
9183     ok(!lstrcmpA("E", buf), "Expected \"E\", got \"%s\"\n", buf);
9184
9185     MsiCloseHandle(rec);
9186
9187     r = MsiViewFetch(view, &rec);
9188     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
9189
9190     sz = MAX_PATH;
9191     lstrcpyA(buf, "kiwi");
9192     r = MsiRecordGetString(rec, 1, buf, &sz);
9193     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
9194     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
9195
9196     r = MsiRecordGetInteger(rec, 2);
9197     ok(r == 3, "Expected 3, got %d\n", r);
9198
9199     sz = MAX_PATH;
9200     lstrcpyA(buf, "kiwi");
9201     r = MsiRecordGetString(rec, 3, buf, &sz);
9202     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
9203     ok(!lstrcmpA("A", buf), "Expected \"A\", got \"%s\"\n", buf);
9204
9205     MsiCloseHandle(rec);
9206
9207     r = MsiViewFetch(view, &rec);
9208     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
9209
9210     sz = MAX_PATH;
9211     lstrcpyA(buf, "kiwi");
9212     r = MsiRecordGetString(rec, 1, buf, &sz);
9213     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
9214     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
9215
9216     r = MsiRecordGetInteger(rec, 2);
9217     ok(r == 4, "Expected 4, got %d\n", r);
9218
9219     sz = MAX_PATH;
9220     lstrcpyA(buf, "kiwi");
9221     r = MsiRecordGetString(rec, 3, buf, &sz);
9222     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
9223     ok(!lstrcmpA("C", buf), "Expected \"C\", got \"%s\"\n", buf);
9224
9225     MsiCloseHandle(rec);
9226
9227     r = MsiViewFetch(view, &rec);
9228     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
9229
9230     sz = MAX_PATH;
9231     lstrcpyA(buf, "kiwi");
9232     r = MsiRecordGetString(rec, 1, buf, &sz);
9233     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
9234     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
9235
9236     r = MsiRecordGetInteger(rec, 2);
9237     ok(r == 5, "Expected 5, got %d\n", r);
9238
9239     sz = MAX_PATH;
9240     lstrcpyA(buf, "kiwi");
9241     r = MsiRecordGetString(rec, 3, buf, &sz);
9242     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
9243     ok(!lstrcmpA("B", buf), "Expected \"B\", got \"%s\"\n", buf);
9244
9245     MsiCloseHandle(rec);
9246
9247     r = MsiViewFetch(view, &rec);
9248     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
9249
9250     MsiViewClose(view);
9251     MsiCloseHandle(view);
9252
9253     MsiCloseHandle(hdb);
9254     DeleteFileA(msifile);
9255 }
9256
9257 static void test_createtable(void)
9258 {
9259     MSIHANDLE hdb, htab = 0, hrec = 0;
9260     LPCSTR query;
9261     UINT res;
9262     DWORD size;
9263     char buffer[0x20];
9264
9265     hdb = create_db();
9266     ok(hdb, "failed to create db\n");
9267
9268     query = "CREATE TABLE `blah` (`foo` CHAR(72) NOT NULL PRIMARY KEY `foo`)";
9269     res = MsiDatabaseOpenView( hdb, query, &htab );
9270     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
9271     if(res == ERROR_SUCCESS )
9272     {
9273         res = MsiViewExecute( htab, hrec );
9274         ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
9275
9276         res = MsiViewGetColumnInfo( htab, MSICOLINFO_NAMES, &hrec );
9277         todo_wine ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
9278
9279         size = sizeof(buffer);
9280         res = MsiRecordGetString(hrec, 1, buffer, &size );
9281         todo_wine ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
9282         MsiCloseHandle( hrec );
9283
9284         res = MsiViewClose( htab );
9285         ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
9286
9287         res = MsiCloseHandle( htab );
9288         ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
9289     }
9290
9291     query = "CREATE TABLE `a` (`b` INT PRIMARY KEY `b`)";
9292     res = MsiDatabaseOpenView( hdb, query, &htab );
9293     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
9294     if(res == ERROR_SUCCESS )
9295     {
9296         res = MsiViewExecute( htab, 0 );
9297         ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
9298
9299         res = MsiViewClose( htab );
9300         ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
9301
9302         res = MsiCloseHandle( htab );
9303         ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
9304
9305         query = "SELECT * FROM `a`";
9306         res = MsiDatabaseOpenView( hdb, query, &htab );
9307         ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
9308
9309         res = MsiViewGetColumnInfo( htab, MSICOLINFO_NAMES, &hrec );
9310         ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
9311
9312         buffer[0] = 0;
9313         size = sizeof(buffer);
9314         res = MsiRecordGetString(hrec, 1, buffer, &size );
9315         ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
9316         ok(!strcmp(buffer,"b"), "b != %s\n", buffer);
9317         MsiCloseHandle( hrec );
9318
9319         res = MsiViewClose( htab );
9320         ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
9321
9322         res = MsiCloseHandle( htab );
9323         ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
9324
9325         res = MsiDatabaseCommit(hdb);
9326         ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
9327
9328         res = MsiCloseHandle(hdb);
9329         ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
9330
9331         res = MsiOpenDatabase(msifile, MSIDBOPEN_TRANSACT, &hdb );
9332         ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
9333
9334         query = "SELECT * FROM `a`";
9335         res = MsiDatabaseOpenView( hdb, query, &htab );
9336         ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
9337
9338         res = MsiViewGetColumnInfo( htab, MSICOLINFO_NAMES, &hrec );
9339         ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
9340
9341         buffer[0] = 0;
9342         size = sizeof(buffer);
9343         res = MsiRecordGetString(hrec, 1, buffer, &size );
9344         ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
9345         ok(!strcmp(buffer,"b"), "b != %s\n", buffer);
9346
9347         res = MsiCloseHandle( hrec );
9348         ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
9349
9350         res = MsiViewClose( htab );
9351         ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
9352
9353         res = MsiCloseHandle( htab );
9354         ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
9355     }
9356
9357     res = MsiDatabaseCommit(hdb);
9358     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
9359
9360     res = MsiCloseHandle(hdb);
9361     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
9362
9363     DeleteFileA(msifile);
9364 }
9365
9366 static void test_embedded_nulls(void)
9367 {
9368     static const char control_table[] =
9369         "Dialog\tText\n"
9370         "s72\tL0\n"
9371         "Control\tDialog\n"
9372         "LicenseAgreementDlg\ttext\x11\x19text\0text";
9373     UINT r, sz;
9374     MSIHANDLE hdb, hrec;
9375     char buffer[32];
9376
9377     r = MsiOpenDatabaseA( msifile, MSIDBOPEN_CREATE, &hdb );
9378     ok( r == ERROR_SUCCESS, "failed to open database %u\n", r );
9379
9380     GetCurrentDirectoryA( MAX_PATH, CURR_DIR );
9381     write_file( "temp_file", control_table, sizeof(control_table) );
9382     r = MsiDatabaseImportA( hdb, CURR_DIR, "temp_file" );
9383     ok( r == ERROR_SUCCESS, "failed to import table %u\n", r );
9384     DeleteFileA( "temp_file" );
9385
9386     r = do_query( hdb, "SELECT `Text` FROM `Control` WHERE `Dialog` = 'LicenseAgreementDlg'", &hrec );
9387     ok( r == ERROR_SUCCESS, "query failed %u\n", r );
9388
9389     buffer[0] = 0;
9390     sz = sizeof(buffer);
9391     r = MsiRecordGetStringA( hrec, 1, buffer, &sz );
9392     ok( r == ERROR_SUCCESS, "failed to get string %u\n", r );
9393     ok( !memcmp( "text\r\ntext\ntext", buffer, sizeof("text\r\ntext\ntext") - 1 ), "wrong buffer contents \"%s\"\n", buffer );
9394
9395     MsiCloseHandle( hrec );
9396     MsiCloseHandle( hdb );
9397     DeleteFileA( msifile );
9398 }
9399
9400 static void test_select_column_names(void)
9401 {
9402     MSIHANDLE hdb = 0, rec, rec2, view;
9403     char buffer[32];
9404     UINT r, size;
9405
9406     DeleteFile(msifile);
9407
9408     r = MsiOpenDatabase( msifile, MSIDBOPEN_CREATE, &hdb );
9409     ok( r == ERROR_SUCCESS , "failed to open database: %u\n", r );
9410
9411     r = try_query( hdb, "CREATE TABLE `t` (`a` CHAR NOT NULL, `b` CHAR PRIMARY KEY `a`)");
9412     ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
9413
9414     r = try_query( hdb, "SELECT `t`.`b` FROM `t` WHERE `t`.`b` = `x`" );
9415     ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %u\n", r );
9416
9417     r = try_query( hdb, "SELECT '', `t`.`b` FROM `t` WHERE `t`.`b` = 'x'" );
9418     ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
9419
9420     r = try_query( hdb, "SELECT *, `t`.`b` FROM `t` WHERE `t`.`b` = 'x'" );
9421     todo_wine ok( r == ERROR_SUCCESS, "query failed: %u\n", r );
9422
9423     r = try_query( hdb, "SELECT 'b', `t`.`b` FROM `t` WHERE `t`.`b` = 'x'" );
9424     ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
9425
9426     r = try_query( hdb, "SELECT `t`.`b`, '' FROM `t` WHERE `t`.`b` = 'x'" );
9427     ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
9428
9429     r = try_query( hdb, "SELECT `t`.`b`, '' FROM `t` WHERE `t`.`b` = 'x' ORDER BY `b`" );
9430     ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
9431
9432     r = try_query( hdb, "SELECT `t`.`b`, '' FROM `t` WHERE `t`.`b` = 'x' ORDER BY 'b'" );
9433     ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %u\n", r );
9434
9435     r = try_query( hdb, "SELECT 't'.'b' FROM `t` WHERE `t`.`b` = 'x'" );
9436     ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %u\n", r );
9437
9438     r = try_query( hdb, "SELECT 'b' FROM `t` WHERE `t`.`b` = 'x'" );
9439     ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
9440
9441     r = try_query( hdb, "INSERT INTO `t` ( `a`, `b` ) VALUES( '1', '2' )" );
9442     ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
9443
9444     r = try_query( hdb, "INSERT INTO `t` ( `a`, `b` ) VALUES( '3', '4' )" );
9445     ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
9446
9447     r = MsiDatabaseOpenView( hdb, "SELECT '' FROM `t`", &view );
9448     ok( r == ERROR_SUCCESS, "failed to open database view: %u\n", r );
9449
9450     r = MsiViewExecute( view, 0 );
9451     ok( r == ERROR_SUCCESS, "failed to execute view: %u\n", r );
9452
9453     r = MsiViewFetch( view, &rec );
9454     ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r );
9455     r = MsiRecordGetFieldCount( rec );
9456     ok( r == 1, "got %u\n",  r );
9457     r = MsiViewGetColumnInfo( view, MSICOLINFO_NAMES, &rec2 );
9458     ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r );
9459     r = MsiRecordGetFieldCount( rec2 );
9460     ok( r == 1, "got %u\n",  r );
9461     size = sizeof(buffer);
9462     memset( buffer, 0x55, sizeof(buffer) );
9463     r = MsiRecordGetStringA( rec2, 1, buffer, &size );
9464     ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r );
9465     ok( !buffer[0], "got \"%s\"\n", buffer );
9466     MsiCloseHandle( rec2 );
9467     r = MsiViewGetColumnInfo( view, MSICOLINFO_TYPES, &rec2 );
9468     ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r );
9469     r = MsiRecordGetFieldCount( rec2 );
9470     ok( r == 1, "got %u\n",  r );
9471     size = sizeof(buffer);
9472     memset( buffer, 0x55, sizeof(buffer) );
9473     r = MsiRecordGetStringA( rec2, 1, buffer, &size );
9474     ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r );
9475     ok( !lstrcmpA( buffer, "f0" ), "got \"%s\"\n", buffer );
9476     MsiCloseHandle( rec2 );
9477
9478     size = sizeof(buffer);
9479     memset( buffer, 0x55, sizeof(buffer) );
9480     r = MsiRecordGetStringA( rec, 1, buffer, &size );
9481     ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r );
9482     ok( !buffer[0], "got \"%s\"\n", buffer );
9483     MsiCloseHandle( rec );
9484
9485     r = MsiViewFetch( view, &rec );
9486     ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r );
9487     size = sizeof(buffer);
9488     memset( buffer, 0x55, sizeof(buffer) );
9489     r = MsiRecordGetStringA( rec, 1, buffer, &size );
9490     ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r );
9491     ok( !buffer[0], "got \"%s\"\n", buffer );
9492     MsiCloseHandle( rec );
9493
9494     r = MsiViewFetch( view, &rec );
9495     ok( r == ERROR_NO_MORE_ITEMS, "unexpected result: %u\n", r );
9496     MsiCloseHandle( rec );
9497
9498     MsiViewClose( view );
9499     MsiCloseHandle( view );
9500
9501     r = MsiDatabaseOpenView( hdb, "SELECT `a`, '' FROM `t`", &view );
9502     ok( r == ERROR_SUCCESS, "failed to open database view: %u\n", r );
9503
9504     r = MsiViewExecute( view, 0 );
9505     ok( r == ERROR_SUCCESS, "failed to execute view: %u\n", r );
9506
9507     r = MsiViewFetch( view, &rec );
9508     ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r );
9509     r = MsiRecordGetFieldCount( rec );
9510     ok( r == 2, "got %u\n",  r );
9511     size = sizeof(buffer);
9512     memset( buffer, 0x55, sizeof(buffer) );
9513     r = MsiRecordGetStringA( rec, 1, buffer, &size );
9514     ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r );
9515     ok( !lstrcmpA( buffer, "1" ), "got \"%s\"\n", buffer );
9516     MsiCloseHandle( rec );
9517
9518     r = MsiViewFetch( view, &rec );
9519     ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r );
9520     size = sizeof(buffer);
9521     memset( buffer, 0x55, sizeof(buffer) );
9522     r = MsiRecordGetStringA( rec, 2, buffer, &size );
9523     ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r );
9524     ok( !buffer[0], "got \"%s\"\n", buffer );
9525     MsiCloseHandle( rec );
9526
9527     r = MsiViewFetch( view, &rec );
9528     ok( r == ERROR_NO_MORE_ITEMS, "unexpected result: %u\n", r );
9529     MsiCloseHandle( rec );
9530
9531     MsiViewClose( view );
9532     MsiCloseHandle( view );
9533
9534     r = MsiDatabaseOpenView( hdb, "SELECT '', `a` FROM `t`", &view );
9535     ok( r == ERROR_SUCCESS, "failed to open database view: %u\n", r );
9536
9537     r = MsiViewExecute( view, 0 );
9538     ok( r == ERROR_SUCCESS, "failed to execute view: %u\n", r );
9539
9540     r = MsiViewFetch( view, &rec );
9541     ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r );
9542     r = MsiRecordGetFieldCount( rec );
9543     ok( r == 2, "got %u\n",  r );
9544     size = sizeof(buffer);
9545     memset( buffer, 0x55, sizeof(buffer) );
9546     r = MsiRecordGetStringA( rec, 1, buffer, &size );
9547     ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r );
9548     ok( !buffer[0], "got \"%s\"\n", buffer );
9549     size = sizeof(buffer);
9550     memset( buffer, 0x55, sizeof(buffer) );
9551     r = MsiRecordGetStringA( rec, 2, buffer, &size );
9552     ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r );
9553     ok( !lstrcmpA( buffer, "1" ), "got \"%s\"\n", buffer );
9554     MsiCloseHandle( rec );
9555
9556     r = MsiViewFetch( view, &rec );
9557     ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r );
9558     size = sizeof(buffer);
9559     memset( buffer, 0x55, sizeof(buffer) );
9560     r = MsiRecordGetStringA( rec, 1, buffer, &size );
9561     ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r );
9562     ok( !buffer[0], "got \"%s\"\n", buffer );
9563     size = sizeof(buffer);
9564     memset( buffer, 0x55, sizeof(buffer) );
9565     r = MsiRecordGetStringA( rec, 2, buffer, &size );
9566     ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r );
9567     ok( !lstrcmpA( buffer, "3" ), "got \"%s\"\n", buffer );
9568     MsiCloseHandle( rec );
9569
9570     r = MsiViewFetch( view, &rec );
9571     ok( r == ERROR_NO_MORE_ITEMS, "unexpected result: %u\n", r );
9572     MsiCloseHandle( rec );
9573
9574     MsiViewClose( view );
9575     MsiCloseHandle( view );
9576
9577     r = MsiDatabaseOpenView( hdb, "SELECT `a`, '', `b` FROM `t`", &view );
9578     ok( r == ERROR_SUCCESS, "failed to open database view: %u\n", r );
9579
9580     r = MsiViewExecute( view, 0 );
9581     ok( r == ERROR_SUCCESS, "failed to execute view: %u\n", r );
9582
9583     r = MsiViewFetch( view, &rec );
9584     ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r );
9585     r = MsiRecordGetFieldCount( rec );
9586     ok( r == 3, "got %u\n",  r );
9587     size = sizeof(buffer);
9588     memset( buffer, 0x55, sizeof(buffer) );
9589     r = MsiRecordGetStringA( rec, 1, buffer, &size );
9590     ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r );
9591     ok( !lstrcmpA( buffer, "1" ), "got \"%s\"\n", buffer );
9592     size = sizeof(buffer);
9593     memset( buffer, 0x55, sizeof(buffer) );
9594     r = MsiRecordGetStringA( rec, 2, buffer, &size );
9595     ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r );
9596     ok( !buffer[0], "got \"%s\"\n", buffer );
9597     size = sizeof(buffer);
9598     memset( buffer, 0x55, sizeof(buffer) );
9599     r = MsiRecordGetStringA( rec, 3, buffer, &size );
9600     ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r );
9601     ok( !lstrcmpA( buffer, "2" ), "got \"%s\"\n", buffer );
9602     MsiCloseHandle( rec );
9603
9604     r = MsiViewFetch( view, &rec );
9605     ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r );
9606     size = sizeof(buffer);
9607     memset( buffer, 0x55, sizeof(buffer) );
9608     r = MsiRecordGetStringA( rec, 1, buffer, &size );
9609     ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r );
9610     ok( !lstrcmpA( buffer, "3" ), "got \"%s\"\n", buffer );
9611     size = sizeof(buffer);
9612     memset( buffer, 0x55, sizeof(buffer) );
9613     r = MsiRecordGetStringA( rec, 2, buffer, &size );
9614     ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r );
9615     ok( !buffer[0], "got \"%s\"\n", buffer );
9616     size = sizeof(buffer);
9617     memset( buffer, 0x55, sizeof(buffer) );
9618     r = MsiRecordGetStringA( rec, 3, buffer, &size );
9619     ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r );
9620     ok( !lstrcmpA( buffer, "4" ), "got \"%s\"\n", buffer );
9621     MsiCloseHandle( rec );
9622
9623     r = MsiViewFetch( view, &rec );
9624     ok( r == ERROR_NO_MORE_ITEMS, "unexpected result: %u\n", r );
9625     MsiCloseHandle( rec );
9626
9627     MsiViewClose( view );
9628     MsiCloseHandle( view );
9629
9630     r = try_query( hdb, "SELECT '' FROM `t` WHERE `t`.`b` = 'x'" );
9631     ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
9632
9633     r = try_query( hdb, "SELECT `` FROM `t` WHERE `t`.`b` = 'x'" );
9634     todo_wine ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %u\n", r );
9635
9636     r = try_query( hdb, "SELECT `b` FROM 't' WHERE `t`.`b` = 'x'" );
9637     ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %u\n", r );
9638
9639     r = try_query( hdb, "SELECT `b` FROM `t` WHERE 'b' = 'x'" );
9640     ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %u\n", r );
9641
9642     r = try_query( hdb, "SELECT `t`.`b`, `` FROM `t` WHERE `t`.`b` = 'x'" );
9643     todo_wine ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %u\n", r );
9644
9645     r = MsiCloseHandle( hdb );
9646     ok(r == ERROR_SUCCESS , "failed to close database: %u\n", r);
9647 }
9648
9649 START_TEST(db)
9650 {
9651     test_msidatabase();
9652     test_msiinsert();
9653     test_msidecomposedesc();
9654     test_msibadqueries();
9655     test_viewmodify();
9656     test_viewgetcolumninfo();
9657     test_getcolinfo();
9658     test_msiexport();
9659     test_longstrings();
9660     test_streamtable();
9661     test_binary();
9662     test_where_not_in_selected();
9663     test_where();
9664     test_msiimport();
9665     test_binary_import();
9666     test_markers();
9667     test_handle_limit();
9668     test_try_transform();
9669     test_join();
9670     test_temporary_table();
9671     test_alter();
9672     test_integers();
9673     test_update();
9674     test_special_tables();
9675     test_tables_order();
9676     test_rows_order();
9677     test_select_markers();
9678     test_viewmodify_update();
9679     test_viewmodify_assign();
9680     test_stringtable();
9681     test_viewmodify_delete();
9682     test_defaultdatabase();
9683     test_order();
9684     test_viewmodify_delete_temporary();
9685     test_deleterow();
9686     test_quotes();
9687     test_carriagereturn();
9688     test_noquotes();
9689     test_forcecodepage();
9690     test_viewmodify_refresh();
9691     test_where_viewmodify();
9692     test_storages_table();
9693     test_dbtopackage();
9694     test_droptable();
9695     test_dbmerge();
9696     test_select_with_tablenames();
9697     test_insertorder();
9698     test_columnorder();
9699     test_suminfo_import();
9700     test_createtable();
9701     test_collation();
9702     test_embedded_nulls();
9703     test_select_column_names();
9704 }