fltlib: Add a stub dll.
[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.msi";
35 static const char *msifile2 = "winetst2.msi";
36 static const char *mstfile = "winetst.mst";
37
38 static void test_msidatabase(void)
39 {
40     MSIHANDLE hdb = 0, hdb2 = 0;
41     UINT res;
42
43     DeleteFile(msifile);
44
45     res = MsiOpenDatabase( msifile, msifile2, &hdb );
46     ok( res == ERROR_OPEN_FAILED, "expected failure\n");
47
48     res = MsiOpenDatabase( msifile, (LPSTR) 0xff, &hdb );
49     ok( res == ERROR_INVALID_PARAMETER, "expected failure\n");
50
51     res = MsiCloseHandle( hdb );
52     ok( res == ERROR_SUCCESS , "Failed to close database\n" );
53
54     /* create an empty database */
55     res = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb );
56     ok( res == ERROR_SUCCESS , "Failed to create database\n" );
57
58     res = MsiDatabaseCommit( hdb );
59     ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
60
61     ok( INVALID_FILE_ATTRIBUTES != GetFileAttributes( msifile ), "database should exist\n");
62
63     res = MsiCloseHandle( hdb );
64     ok( res == ERROR_SUCCESS , "Failed to close database\n" );
65     res = MsiOpenDatabase( msifile, msifile2, &hdb2 );
66     ok( res == ERROR_SUCCESS , "Failed to open database\n" );
67
68     ok( INVALID_FILE_ATTRIBUTES != GetFileAttributes( msifile2 ), "database should exist\n");
69
70     res = MsiDatabaseCommit( hdb2 );
71     ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
72
73     res = MsiCloseHandle( hdb2 );
74     ok( res == ERROR_SUCCESS , "Failed to close database\n" );
75
76     res = MsiOpenDatabase( msifile, msifile2, &hdb2 );
77     ok( res == ERROR_SUCCESS , "Failed to open database\n" );
78
79     res = MsiCloseHandle( hdb2 );
80     ok( res == ERROR_SUCCESS , "Failed to close database\n" );
81
82     ok( INVALID_FILE_ATTRIBUTES == GetFileAttributes( msifile2 ), "uncommitted database should not exist\n");
83
84     res = MsiOpenDatabase( msifile, msifile2, &hdb2 );
85     ok( res == ERROR_SUCCESS , "Failed to close database\n" );
86
87     res = MsiDatabaseCommit( hdb2 );
88     ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
89
90     res = MsiCloseHandle( hdb2 );
91     ok( res == ERROR_SUCCESS , "Failed to close database\n" );
92
93     ok( INVALID_FILE_ATTRIBUTES != GetFileAttributes( msifile2 ), "committed database should exist\n");
94
95     res = MsiOpenDatabase( msifile, MSIDBOPEN_READONLY, &hdb );
96     ok( res == ERROR_SUCCESS , "Failed to open database\n" );
97
98     res = MsiCloseHandle( hdb );
99     ok( res == ERROR_SUCCESS , "Failed to close database\n" );
100
101     res = MsiOpenDatabase( msifile, MSIDBOPEN_DIRECT, &hdb );
102     ok( res == ERROR_SUCCESS , "Failed to open database\n" );
103
104     res = MsiCloseHandle( hdb );
105     ok( res == ERROR_SUCCESS , "Failed to close database\n" );
106
107     res = MsiOpenDatabase( msifile, MSIDBOPEN_TRANSACT, &hdb );
108     ok( res == ERROR_SUCCESS , "Failed to open database\n" );
109
110     res = MsiCloseHandle( hdb );
111     ok( res == ERROR_SUCCESS , "Failed to close database\n" );
112     ok( INVALID_FILE_ATTRIBUTES != GetFileAttributes( msifile ), "database should exist\n");
113
114     /* MSIDBOPEN_CREATE deletes the database if MsiCommitDatabase isn't called */
115     res = MsiOpenDatabase( msifile, MSIDBOPEN_CREATE, &hdb );
116     ok( res == ERROR_SUCCESS , "Failed to open database\n" );
117
118     ok( INVALID_FILE_ATTRIBUTES != GetFileAttributes( msifile ), "database should exist\n");
119
120     res = MsiCloseHandle( hdb );
121     ok( res == ERROR_SUCCESS , "Failed to close database\n" );
122
123     ok( INVALID_FILE_ATTRIBUTES == GetFileAttributes( msifile ), "database should exist\n");
124
125     res = MsiOpenDatabase( msifile, MSIDBOPEN_CREATE, &hdb );
126     ok( res == ERROR_SUCCESS , "Failed to open database\n" );
127
128     res = MsiDatabaseCommit( hdb );
129     ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
130
131     ok( INVALID_FILE_ATTRIBUTES != GetFileAttributes( msifile ), "database should exist\n");
132
133     res = MsiCloseHandle( hdb );
134     ok( res == ERROR_SUCCESS , "Failed to close database\n" );
135
136     res = DeleteFile( msifile2 );
137     ok( res == TRUE, "Failed to delete database\n" );
138
139     res = DeleteFile( msifile );
140     ok( res == TRUE, "Failed to delete database\n" );
141 }
142
143 static UINT do_query(MSIHANDLE hdb, const char *query, MSIHANDLE *phrec)
144 {
145     MSIHANDLE hview = 0;
146     UINT r, ret;
147
148     if (phrec)
149         *phrec = 0;
150
151     /* open a select query */
152     r = MsiDatabaseOpenView(hdb, query, &hview);
153     if (r != ERROR_SUCCESS)
154         return r;
155     r = MsiViewExecute(hview, 0);
156     if (r != ERROR_SUCCESS)
157         return r;
158     ret = MsiViewFetch(hview, phrec);
159     r = MsiViewClose(hview);
160     if (r != ERROR_SUCCESS)
161         return r;
162     r = MsiCloseHandle(hview);
163     if (r != ERROR_SUCCESS)
164         return r;
165     return ret;
166 }
167
168 static UINT run_query( MSIHANDLE hdb, MSIHANDLE hrec, const char *query )
169 {
170     MSIHANDLE hview = 0;
171     UINT r;
172
173     r = MsiDatabaseOpenView(hdb, query, &hview);
174     if( r != ERROR_SUCCESS )
175         return r;
176
177     r = MsiViewExecute(hview, hrec);
178     if( r == ERROR_SUCCESS )
179         r = MsiViewClose(hview);
180     MsiCloseHandle(hview);
181     return r;
182 }
183
184 static UINT create_component_table( MSIHANDLE hdb )
185 {
186     return run_query( hdb, 0,
187             "CREATE TABLE `Component` ( "
188             "`Component` CHAR(72) NOT NULL, "
189             "`ComponentId` CHAR(38), "
190             "`Directory_` CHAR(72) NOT NULL, "
191             "`Attributes` SHORT NOT NULL, "
192             "`Condition` CHAR(255), "
193             "`KeyPath` CHAR(72) "
194             "PRIMARY KEY `Component`)" );
195 }
196
197 static UINT create_custom_action_table( MSIHANDLE hdb )
198 {
199     return run_query( hdb, 0,
200             "CREATE TABLE `CustomAction` ( "
201             "`Action` CHAR(72) NOT NULL, "
202             "`Type` SHORT NOT NULL, "
203             "`Source` CHAR(72), "
204             "`Target` CHAR(255) "
205             "PRIMARY KEY `Action`)" );
206 }
207
208 static UINT create_directory_table( MSIHANDLE hdb )
209 {
210     return run_query( hdb, 0,
211             "CREATE TABLE `Directory` ( "
212             "`Directory` CHAR(255) NOT NULL, "
213             "`Directory_Parent` CHAR(255), "
214             "`DefaultDir` CHAR(255) NOT NULL "
215             "PRIMARY KEY `Directory`)" );
216 }
217
218 static UINT create_feature_components_table( MSIHANDLE hdb )
219 {
220     return run_query( hdb, 0,
221             "CREATE TABLE `FeatureComponents` ( "
222             "`Feature_` CHAR(38) NOT NULL, "
223             "`Component_` CHAR(72) NOT NULL "
224             "PRIMARY KEY `Feature_`, `Component_` )" );
225 }
226
227 static UINT create_std_dlls_table( MSIHANDLE hdb )
228 {
229     return run_query( hdb, 0,
230             "CREATE TABLE `StdDlls` ( "
231             "`File` CHAR(255) NOT NULL, "
232             "`Binary_` CHAR(72) NOT NULL "
233             "PRIMARY KEY `File` )" );
234 }
235
236 static UINT create_binary_table( MSIHANDLE hdb )
237 {
238     return run_query( hdb, 0,
239             "CREATE TABLE `Binary` ( "
240             "`Name` CHAR(72) NOT NULL, "
241             "`Data` CHAR(72) NOT NULL "
242             "PRIMARY KEY `Name` )" );
243 }
244
245 #define make_add_entry(type, qtext) \
246     static UINT add##_##type##_##entry( MSIHANDLE hdb, const char *values ) \
247     { \
248         char insert[] = qtext; \
249         char *query; \
250         UINT sz, r; \
251         sz = strlen(values) + sizeof insert; \
252         query = HeapAlloc(GetProcessHeap(),0,sz); \
253         sprintf(query,insert,values); \
254         r = run_query( hdb, 0, query ); \
255         HeapFree(GetProcessHeap(), 0, query); \
256         return r; \
257     }
258
259 make_add_entry(component,
260                "INSERT INTO `Component`  "
261                "(`Component`, `ComponentId`, `Directory_`, "
262                "`Attributes`, `Condition`, `KeyPath`) VALUES( %s )")
263
264 make_add_entry(custom_action,
265                "INSERT INTO `CustomAction`  "
266                "(`Action`, `Type`, `Source`, `Target`) VALUES( %s )")
267
268 make_add_entry(feature_components,
269                "INSERT INTO `FeatureComponents` "
270                "(`Feature_`, `Component_`) VALUES( %s )")
271
272 make_add_entry(std_dlls,
273                "INSERT INTO `StdDlls` (`File`, `Binary_`) VALUES( %s )")
274
275 make_add_entry(binary,
276                "INSERT INTO `Binary` (`Name`, `Data`) VALUES( %s )")
277
278 static void test_msiinsert(void)
279 {
280     MSIHANDLE hdb = 0, hview = 0, hrec = 0;
281     UINT r;
282     const char *query;
283     char buf[80];
284     DWORD sz;
285
286     DeleteFile(msifile);
287
288     /* just MsiOpenDatabase should not create a file */
289     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
290     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
291
292     /* create a table */
293     query = "CREATE TABLE `phone` ( "
294             "`id` INT, `name` CHAR(32), `number` CHAR(32) "
295             "PRIMARY KEY `id`)";
296     r = MsiDatabaseOpenView(hdb, query, &hview);
297     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
298     r = MsiViewExecute(hview, 0);
299     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
300     r = MsiViewClose(hview);
301     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
302     r = MsiCloseHandle(hview);
303     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
304
305     /* insert a value into it */
306     query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
307         "VALUES('1', 'Abe', '8675309')";
308     r = MsiDatabaseOpenView(hdb, query, &hview);
309     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
310     r = MsiViewExecute(hview, 0);
311     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
312     r = MsiViewClose(hview);
313     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
314     r = MsiCloseHandle(hview);
315     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
316
317     query = "SELECT * FROM `phone` WHERE `id` = 1";
318     r = do_query(hdb, query, &hrec);
319     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
320
321     /* check the record contains what we put in it */
322     r = MsiRecordGetFieldCount(hrec);
323     ok(r == 3, "record count wrong\n");
324
325     r = MsiRecordIsNull(hrec, 0);
326     ok(r == FALSE, "field 0 not null\n");
327
328     r = MsiRecordGetInteger(hrec, 1);
329     ok(r == 1, "field 1 contents wrong\n");
330     sz = sizeof buf;
331     r = MsiRecordGetString(hrec, 2, buf, &sz);
332     ok(r == ERROR_SUCCESS, "field 2 content fetch failed\n");
333     ok(!strcmp(buf,"Abe"), "field 2 content incorrect\n");
334     sz = sizeof buf;
335     r = MsiRecordGetString(hrec, 3, buf, &sz);
336     ok(r == ERROR_SUCCESS, "field 3 content fetch failed\n");
337     ok(!strcmp(buf,"8675309"), "field 3 content incorrect\n");
338
339     r = MsiCloseHandle(hrec);
340     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
341
342     /* open a select query */
343     hrec = 100;
344     query = "SELECT * FROM `phone` WHERE `id` >= 10";
345     r = do_query(hdb, query, &hrec);
346     ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch failed\n");
347     ok(hrec == 0, "hrec should be null\n");
348
349     r = MsiCloseHandle(hrec);
350     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
351
352     query = "SELECT * FROM `phone` WHERE `id` < 0";
353     r = do_query(hdb, query, &hrec);
354     ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch failed\n");
355
356     query = "SELECT * FROM `phone` WHERE `id` <= 0";
357     r = do_query(hdb, query, &hrec);
358     ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch failed\n");
359
360     query = "SELECT * FROM `phone` WHERE `id` <> 1";
361     r = do_query(hdb, query, &hrec);
362     ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch failed\n");
363
364     query = "SELECT * FROM `phone` WHERE `id` > 10";
365     r = do_query(hdb, query, &hrec);
366     ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch failed\n");
367
368     /* now try a few bad INSERT xqueries */
369     query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
370         "VALUES(?, ?)";
371     r = MsiDatabaseOpenView(hdb, query, &hview);
372     ok(r == ERROR_BAD_QUERY_SYNTAX, "MsiDatabaseOpenView failed\n");
373
374     /* construct a record to insert */
375     hrec = MsiCreateRecord(4);
376     r = MsiRecordSetInteger(hrec, 1, 2);
377     ok(r == ERROR_SUCCESS, "MsiRecordSetInteger failed\n");
378     r = MsiRecordSetString(hrec, 2, "Adam");
379     ok(r == ERROR_SUCCESS, "MsiRecordSetString failed\n");
380     r = MsiRecordSetString(hrec, 3, "96905305");
381     ok(r == ERROR_SUCCESS, "MsiRecordSetString failed\n");
382
383     /* insert another value, using a record and wildcards */
384     query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
385         "VALUES(?, ?, ?)";
386     r = MsiDatabaseOpenView(hdb, query, &hview);
387     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
388
389     if (r == ERROR_SUCCESS)
390     {
391         r = MsiViewExecute(hview, hrec);
392         ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
393         r = MsiViewClose(hview);
394         ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
395         r = MsiCloseHandle(hview);
396         ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
397     }
398     r = MsiCloseHandle(hrec);
399     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
400
401     r = MsiViewFetch(0, NULL);
402     ok(r == ERROR_INVALID_PARAMETER, "MsiViewFetch failed\n");
403
404     r = MsiDatabaseCommit(hdb);
405     ok(r == ERROR_SUCCESS, "MsiDatabaseCommit failed\n");
406
407     r = MsiCloseHandle(hdb);
408     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
409
410     r = DeleteFile(msifile);
411     ok(r == TRUE, "file didn't exist after commit\n");
412 }
413
414 typedef UINT (WINAPI *fnMsiDecomposeDescriptorA)(LPCSTR, LPCSTR, LPSTR, LPSTR, DWORD *);
415 static fnMsiDecomposeDescriptorA pMsiDecomposeDescriptorA;
416
417 static void test_msidecomposedesc(void)
418 {
419     char prod[MAX_FEATURE_CHARS+1], comp[MAX_FEATURE_CHARS+1], feature[MAX_FEATURE_CHARS+1];
420     const char *desc;
421     UINT r;
422     DWORD len;
423     HMODULE hmod;
424
425     hmod = GetModuleHandle("msi.dll");
426     pMsiDecomposeDescriptorA = (fnMsiDecomposeDescriptorA)
427         GetProcAddress(hmod, "MsiDecomposeDescriptorA");
428     if (!pMsiDecomposeDescriptorA)
429         return;
430
431     /* test a valid feature descriptor */
432     desc = "']gAVn-}f(ZXfeAR6.jiFollowTheWhiteRabbit>3w2x^IGfe?CxI5heAvk.";
433     len = 0;
434     r = pMsiDecomposeDescriptorA(desc, prod, feature, comp, &len);
435     ok(r == ERROR_SUCCESS, "returned an error\n");
436     ok(len == strlen(desc), "length was wrong\n");
437     ok(strcmp(prod,"{90110409-6000-11D3-8CFE-0150048383C9}")==0, "product wrong\n");
438     ok(strcmp(feature,"FollowTheWhiteRabbit")==0, "feature wrong\n");
439     ok(strcmp(comp,"{A7CD68DB-EF74-49C8-FBB2-A7C463B2AC24}")==0,"component wrong\n");
440
441     /* test an invalid feature descriptor with too many characters */
442     desc = "']gAVn-}f(ZXfeAR6.ji"
443            "ThisWillFailIfTheresMoreThanAGuidsChars>"
444            "3w2x^IGfe?CxI5heAvk.";
445     len = 0;
446     r = pMsiDecomposeDescriptorA(desc, prod, feature, comp, &len);
447     ok(r == ERROR_INVALID_PARAMETER, "returned wrong error\n");
448
449     /*
450      * Test a valid feature descriptor with the
451      * maximum number of characters and some trailing characters.
452      */
453     desc = "']gAVn-}f(ZXfeAR6.ji"
454            "ThisWillWorkIfTheresLTEThanAGuidsChars>"
455            "3w2x^IGfe?CxI5heAvk."
456            "extra";
457     len = 0;
458     r = pMsiDecomposeDescriptorA(desc, prod, feature, comp, &len);
459     ok(r == ERROR_SUCCESS, "returned wrong error\n");
460     ok(len == (strlen(desc) - strlen("extra")), "length wrong\n");
461
462     len = 0;
463     r = pMsiDecomposeDescriptorA(desc, prod, feature, NULL, &len);
464     ok(r == ERROR_SUCCESS, "returned wrong error\n");
465     ok(len == (strlen(desc) - strlen("extra")), "length wrong\n");
466
467     len = 0;
468     r = pMsiDecomposeDescriptorA(desc, prod, NULL, NULL, &len);
469     ok(r == ERROR_SUCCESS, "returned wrong error\n");
470     ok(len == (strlen(desc) - strlen("extra")), "length wrong\n");
471
472     len = 0;
473     r = pMsiDecomposeDescriptorA(desc, NULL, NULL, NULL, &len);
474     ok(r == ERROR_SUCCESS, "returned wrong error\n");
475     ok(len == (strlen(desc) - strlen("extra")), "length wrong\n");
476
477     len = 0;
478     r = pMsiDecomposeDescriptorA(NULL, NULL, NULL, NULL, &len);
479     ok(r == ERROR_INVALID_PARAMETER, "returned wrong error\n");
480     ok(len == 0, "length wrong\n");
481 }
482
483 static UINT try_query_param( MSIHANDLE hdb, LPCSTR szQuery, MSIHANDLE hrec )
484 {
485     MSIHANDLE htab = 0;
486     UINT res;
487
488     res = MsiDatabaseOpenView( hdb, szQuery, &htab );
489     if(res == ERROR_SUCCESS )
490     {
491         UINT r;
492
493         r = MsiViewExecute( htab, hrec );
494         if(r != ERROR_SUCCESS )
495             res = r;
496
497         r = MsiViewClose( htab );
498         if(r != ERROR_SUCCESS )
499             res = r;
500
501         r = MsiCloseHandle( htab );
502         if(r != ERROR_SUCCESS )
503             res = r;
504     }
505     return res;
506 }
507
508 static UINT try_query( MSIHANDLE hdb, LPCSTR szQuery )
509 {
510     return try_query_param( hdb, szQuery, 0 );
511 }
512
513 static UINT try_insert_query( MSIHANDLE hdb, LPCSTR szQuery )
514 {
515     MSIHANDLE hrec = 0;
516     UINT r;
517
518     hrec = MsiCreateRecord( 1 );
519     MsiRecordSetString( hrec, 1, "Hello");
520
521     r = try_query_param( hdb, szQuery, hrec );
522
523     MsiCloseHandle( hrec );
524     return r;
525 }
526
527 static void test_msibadqueries(void)
528 {
529     MSIHANDLE hdb = 0;
530     UINT r;
531
532     DeleteFile(msifile);
533
534     /* just MsiOpenDatabase should not create a file */
535     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
536     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
537
538     r = MsiDatabaseCommit( hdb );
539     ok(r == ERROR_SUCCESS , "Failed to commit database\n");
540
541     r = MsiCloseHandle( hdb );
542     ok(r == ERROR_SUCCESS , "Failed to close database\n");
543
544     /* open it readonly */
545     r = MsiOpenDatabase(msifile, MSIDBOPEN_READONLY, &hdb );
546     ok(r == ERROR_SUCCESS , "Failed to open database r/o\n");
547
548     /* add a table to it */
549     r = try_query( hdb, "select * from _Tables");
550     ok(r == ERROR_SUCCESS , "query 1 failed\n");
551
552     r = MsiCloseHandle( hdb );
553     ok(r == ERROR_SUCCESS , "Failed to close database r/o\n");
554
555     /* open it read/write */
556     r = MsiOpenDatabase(msifile, MSIDBOPEN_TRANSACT, &hdb );
557     ok(r == ERROR_SUCCESS , "Failed to open database r/w\n");
558
559     /* a bunch of test queries that fail with the native MSI */
560
561     r = try_query( hdb, "CREATE TABLE");
562     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2a return code\n");
563
564     r = try_query( hdb, "CREATE TABLE `a`");
565     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2b return code\n");
566
567     r = try_query( hdb, "CREATE TABLE `a` ()");
568     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2c return code\n");
569
570     r = try_query( hdb, "CREATE TABLE `a` (`b`)");
571     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2d return code\n");
572
573     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) )");
574     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2e return code\n");
575
576     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL)");
577     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2f return code\n");
578
579     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY)");
580     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2g return code\n");
581
582     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY)");
583     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2h return code\n");
584
585     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY)");
586     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2i return code\n");
587
588     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY 'b')");
589     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2j return code\n");
590
591     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY `b')");
592     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2k return code\n");
593
594     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY `b')");
595     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2l return code\n");
596
597     r = try_query( hdb, "CREATE TABLE `a` (`b` CHA(72) NOT NULL PRIMARY KEY `b`)");
598     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2m return code\n");
599
600     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(-1) NOT NULL PRIMARY KEY `b`)");
601     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2n return code\n");
602
603     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(720) NOT NULL PRIMARY KEY `b`)");
604     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2o return code\n");
605
606     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL KEY `b`)");
607     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2p return code\n");
608
609     r = try_query( hdb, "CREATE TABLE `a` (`` CHAR(72) NOT NULL PRIMARY KEY `b`)");
610     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2p return code\n");
611
612     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY `b`)");
613     ok(r == ERROR_SUCCESS , "valid query 2z failed\n");
614
615     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY `b`)");
616     ok(r == ERROR_BAD_QUERY_SYNTAX , "created same table again\n");
617
618     r = try_query( hdb, "CREATE TABLE `aa` (`b` CHAR(72) NOT NULL, `c` "
619           "CHAR(72), `d` CHAR(255) NOT NULL LOCALIZABLE PRIMARY KEY `b`)");
620     ok(r == ERROR_SUCCESS , "query 4 failed\n");
621
622     r = MsiDatabaseCommit( hdb );
623     ok(r == ERROR_SUCCESS , "Failed to commit database after write\n");
624
625     r = try_query( hdb, "CREATE TABLE `blah` (`foo` CHAR(72) NOT NULL "
626                           "PRIMARY KEY `foo`)");
627     ok(r == ERROR_SUCCESS , "query 4 failed\n");
628
629     r = try_insert_query( hdb, "insert into a  ( `b` ) VALUES ( ? )");
630     ok(r == ERROR_SUCCESS , "failed to insert record in db\n");
631
632     r = MsiDatabaseCommit( hdb );
633     ok(r == ERROR_SUCCESS , "Failed to commit database after write\n");
634
635     r = try_query( hdb, "CREATE TABLE `boo` (`foo` CHAR(72) NOT NULL "
636                           "PRIMARY KEY `ba`)");
637     ok(r != ERROR_SUCCESS , "query 5 succeeded\n");
638
639     r = try_query( hdb,"CREATE TABLE `bee` (`foo` CHAR(72) NOT NULL )");
640     ok(r != ERROR_SUCCESS , "query 6 succeeded\n");
641
642     r = try_query( hdb, "CREATE TABLE `temp` (`t` CHAR(72) NOT NULL "
643                           "PRIMARY KEY `t`)");
644     ok(r == ERROR_SUCCESS , "query 7 failed\n");
645
646     r = try_query( hdb, "CREATE TABLE `c` (`b` CHAR NOT NULL PRIMARY KEY `b`)");
647     ok(r == ERROR_SUCCESS , "query 8 failed\n");
648
649     r = try_query( hdb, "select * from c");
650     ok(r == ERROR_SUCCESS , "query failed\n");
651
652     r = try_query( hdb, "select * from c where b = 'x");
653     ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
654
655     r = try_query( hdb, "select * from c where b = 'x'");
656     ok(r == ERROR_SUCCESS, "query failed\n");
657
658     r = try_query( hdb, "select * from 'c'");
659     ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
660
661     r = try_query( hdb, "select * from ''");
662     ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
663
664     r = try_query( hdb, "select * from c where b = x");
665     ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
666
667     r = try_query( hdb, "select * from c where b = \"x\"");
668     ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
669
670     r = try_query( hdb, "select * from c where b = 'x'");
671     ok(r == ERROR_SUCCESS, "query failed\n");
672
673     r = try_query( hdb, "select * from c where b = '\"x'");
674     ok(r == ERROR_SUCCESS, "query failed\n");
675
676     if (0)  /* FIXME: this query causes trouble with other tests */
677     {
678         r = try_query( hdb, "select * from c where b = '\\\'x'");
679         ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
680     }
681
682     r = try_query( hdb, "select * from 'c'");
683     ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
684
685     r = MsiCloseHandle( hdb );
686     ok(r == ERROR_SUCCESS , "Failed to close database transact\n");
687
688     r = DeleteFile( msifile );
689     ok(r == TRUE, "file didn't exist after commit\n");
690 }
691
692 static void test_viewmodify(void)
693 {
694     MSIHANDLE hdb = 0, hview = 0, hrec = 0;
695     UINT r;
696     MSIDBERROR err;
697     const char *query;
698     char buffer[0x100];
699     DWORD sz;
700
701     DeleteFile(msifile);
702
703     /* just MsiOpenDatabase should not create a file */
704     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
705     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
706
707     query = "CREATE TABLE `phone` ( "
708             "`id` INT, `name` CHAR(32), `number` CHAR(32) "
709             "PRIMARY KEY `id`)";
710     r = run_query( hdb, 0, query );
711     ok(r == ERROR_SUCCESS, "query failed\n");
712
713     /* check what the error function reports without doing anything */
714     sz = 0;
715     /* passing NULL as the 3rd param make function to crash on older platforms */
716     err = MsiViewGetError( 0, NULL, &sz );
717     ok(err == MSIDBERROR_INVALIDARG, "MsiViewGetError return\n");
718
719     /* open a view */
720     query = "SELECT * FROM `phone`";
721     r = MsiDatabaseOpenView(hdb, query, &hview);
722     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
723
724     /* see what happens with a good hview and bad args */
725     err = MsiViewGetError( hview, NULL, NULL );
726     ok(err == MSIDBERROR_INVALIDARG || err == MSIDBERROR_NOERROR,
727        "MsiViewGetError returns %u (expected -3)\n", err);
728     err = MsiViewGetError( hview, buffer, NULL );
729     ok(err == MSIDBERROR_INVALIDARG, "MsiViewGetError return\n");
730
731     /* see what happens with a zero length buffer */
732     sz = 0;
733     buffer[0] = 'x';
734     err = MsiViewGetError( hview, buffer, &sz );
735     ok(err == MSIDBERROR_MOREDATA, "MsiViewGetError return\n");
736     ok(buffer[0] == 'x', "buffer cleared\n");
737     ok(sz == 0, "size not zero\n");
738
739     /* ok this one is strange */
740     sz = 0;
741     err = MsiViewGetError( hview, NULL, &sz );
742     ok(err == MSIDBERROR_NOERROR, "MsiViewGetError return\n");
743     ok(sz == 0, "size not zero\n");
744
745     /* see if it really has an error */
746     sz = sizeof buffer;
747     buffer[0] = 'x';
748     err = MsiViewGetError( hview, buffer, &sz );
749     ok(err == MSIDBERROR_NOERROR, "MsiViewGetError return\n");
750     ok(buffer[0] == 0, "buffer not cleared\n");
751     ok(sz == 0, "size not zero\n");
752
753     r = MsiViewExecute(hview, 0);
754     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
755
756     /* try some invalid records */
757     r = MsiViewModify(hview, MSIMODIFY_INSERT, 0 );
758     ok(r == ERROR_INVALID_HANDLE, "MsiViewModify failed\n");
759     r = MsiViewModify(hview, -1, 0 );
760     ok(r == ERROR_INVALID_HANDLE, "MsiViewModify failed\n");
761
762     /* try an small record */
763     hrec = MsiCreateRecord(1);
764     r = MsiViewModify(hview, -1, hrec );
765     ok(r == ERROR_INVALID_DATA, "MsiViewModify failed\n");
766
767     r = MsiCloseHandle(hrec);
768     ok(r == ERROR_SUCCESS, "failed to close record\n");
769
770     /* insert a valid record */
771     hrec = MsiCreateRecord(3);
772
773     r = MsiRecordSetInteger(hrec, 1, 1);
774     ok(r == ERROR_SUCCESS, "failed to set integer\n");
775     r = MsiRecordSetString(hrec, 2, "bob");
776     ok(r == ERROR_SUCCESS, "failed to set string\n");
777     r = MsiRecordSetString(hrec, 3, "7654321");
778     ok(r == ERROR_SUCCESS, "failed to set string\n");
779
780     r = MsiViewExecute(hview, 0);
781     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
782     r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec );
783     ok(r == ERROR_SUCCESS, "MsiViewModify failed\n");
784
785     /* insert the same thing again */
786     r = MsiViewExecute(hview, 0);
787     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
788
789     /* should fail ... */
790     r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec );
791     ok(r == ERROR_FUNCTION_FAILED, "MsiViewModify failed\n");
792
793     r = MsiCloseHandle(hrec);
794     ok(r == ERROR_SUCCESS, "failed to close record\n");
795
796     r = MsiViewClose(hview);
797     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
798     r = MsiCloseHandle(hview);
799     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
800
801     query = "SELECT * FROM `phone`";
802     r = MsiDatabaseOpenView(hdb, query, &hview);
803     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
804
805     r = MsiViewExecute(hview, 0);
806     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
807
808     r = MsiViewFetch(hview, &hrec);
809     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
810
811     r = MsiRecordGetInteger(hrec, 1);
812     ok(r == 1, "Expected 1, got %d\n", r);
813
814     sz = sizeof(buffer);
815     r = MsiRecordGetString(hrec, 2, buffer, &sz);
816     ok(r == ERROR_SUCCESS, "MsiRecordGetString failed\n");
817     ok(!lstrcmp(buffer, "bob"), "Expected bob, got %s\n", buffer);
818
819     sz = sizeof(buffer);
820     r = MsiRecordGetString(hrec, 3, buffer, &sz);
821     ok(r == ERROR_SUCCESS, "MsiRecordGetString failed\n");
822     ok(!lstrcmp(buffer, "7654321"), "Expected 7654321, got %s\n", buffer);
823
824     /* update the view, non-primary key */
825     r = MsiRecordSetString(hrec, 3, "3141592");
826     ok(r == ERROR_SUCCESS, "MsiRecordSetString failed\n");
827
828     r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
829     ok(r == ERROR_SUCCESS, "MsiViewModify failed\n");
830
831     /* do it again */
832     r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
833     ok(r == ERROR_SUCCESS, "MsiViewModify failed: %d\n", r);
834
835     /* update the view, primary key */
836     r = MsiRecordSetInteger(hrec, 1, 5);
837     ok(r == ERROR_SUCCESS, "MsiRecordSetInteger failed\n");
838
839     r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
840     ok(r == ERROR_FUNCTION_FAILED, "MsiViewModify failed\n");
841
842     r = MsiCloseHandle(hrec);
843     ok(r == ERROR_SUCCESS, "failed to close record\n");
844
845     r = MsiViewClose(hview);
846     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
847     r = MsiCloseHandle(hview);
848     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
849
850     query = "SELECT * FROM `phone`";
851     r = MsiDatabaseOpenView(hdb, query, &hview);
852     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
853
854     r = MsiViewExecute(hview, 0);
855     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
856
857     r = MsiViewFetch(hview, &hrec);
858     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
859
860     r = MsiRecordGetInteger(hrec, 1);
861     ok(r == 1, "Expected 1, got %d\n", r);
862
863     sz = sizeof(buffer);
864     r = MsiRecordGetString(hrec, 2, buffer, &sz);
865     ok(r == ERROR_SUCCESS, "MsiRecordGetString failed\n");
866     ok(!lstrcmp(buffer, "bob"), "Expected bob, got %s\n", buffer);
867
868     sz = sizeof(buffer);
869     r = MsiRecordGetString(hrec, 3, buffer, &sz);
870     ok(r == ERROR_SUCCESS, "MsiRecordGetString failed\n");
871     ok(!lstrcmp(buffer, "3141592"), "Expected 3141592, got %s\n", buffer);
872
873     r = MsiCloseHandle(hrec);
874     ok(r == ERROR_SUCCESS, "failed to close record\n");
875
876     /* use a record that doesn't come from a view fetch */
877     hrec = MsiCreateRecord(3);
878     ok(hrec != 0, "MsiCreateRecord failed\n");
879
880     r = MsiRecordSetInteger(hrec, 1, 3);
881     ok(r == ERROR_SUCCESS, "failed to set integer\n");
882     r = MsiRecordSetString(hrec, 2, "jane");
883     ok(r == ERROR_SUCCESS, "failed to set string\n");
884     r = MsiRecordSetString(hrec, 3, "112358");
885     ok(r == ERROR_SUCCESS, "failed to set string\n");
886
887     r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
888     ok(r == ERROR_FUNCTION_FAILED, "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
889
890     r = MsiCloseHandle(hrec);
891     ok(r == ERROR_SUCCESS, "failed to close record\n");
892
893     /* use a record that doesn't come from a view fetch, primary key matches */
894     hrec = MsiCreateRecord(3);
895     ok(hrec != 0, "MsiCreateRecord failed\n");
896
897     r = MsiRecordSetInteger(hrec, 1, 1);
898     ok(r == ERROR_SUCCESS, "failed to set integer\n");
899     r = MsiRecordSetString(hrec, 2, "jane");
900     ok(r == ERROR_SUCCESS, "failed to set string\n");
901     r = MsiRecordSetString(hrec, 3, "112358");
902     ok(r == ERROR_SUCCESS, "failed to set string\n");
903
904     r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
905     ok(r == ERROR_FUNCTION_FAILED, "MsiViewModify failed\n");
906
907     r = MsiCloseHandle(hrec);
908     ok(r == ERROR_SUCCESS, "failed to close record\n");
909
910     hrec = MsiCreateRecord(3);
911
912     r = MsiRecordSetInteger(hrec, 1, 2);
913     ok(r == ERROR_SUCCESS, "failed to set integer\n");
914     r = MsiRecordSetString(hrec, 2, "nick");
915     ok(r == ERROR_SUCCESS, "failed to set string\n");
916     r = MsiRecordSetString(hrec, 3, "141421");
917     ok(r == ERROR_SUCCESS, "failed to set string\n");
918
919     r = MsiViewExecute(hview, 0);
920     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
921     r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec );
922     ok(r == ERROR_SUCCESS, "MsiViewModify failed\n");
923
924     r = MsiViewClose(hview);
925     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
926     r = MsiCloseHandle(hview);
927     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
928
929     query = "SELECT * FROM `phone` WHERE `id` = 1";
930     r = MsiDatabaseOpenView(hdb, query, &hview);
931     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
932     r = MsiViewExecute(hview, 0);
933     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
934     r = MsiViewFetch(hview, &hrec);
935     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
936
937     /* change the id to match the second row */
938     r = MsiRecordSetInteger(hrec, 1, 2);
939     ok(r == ERROR_SUCCESS, "failed to set integer\n");
940     r = MsiRecordSetString(hrec, 2, "jerry");
941     ok(r == ERROR_SUCCESS, "failed to set string\n");
942
943     r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
944     ok(r == ERROR_FUNCTION_FAILED, "MsiViewModify failed\n");
945
946     r = MsiCloseHandle(hrec);
947     ok(r == ERROR_SUCCESS, "failed to close record\n");
948     r = MsiViewClose(hview);
949     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
950     r = MsiCloseHandle(hview);
951     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
952
953     /* broader search */
954     query = "SELECT * FROM `phone` ORDER BY `id`";
955     r = MsiDatabaseOpenView(hdb, query, &hview);
956     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
957     r = MsiViewExecute(hview, 0);
958     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
959     r = MsiViewFetch(hview, &hrec);
960     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
961
962     /* change the id to match the second row */
963     r = MsiRecordSetInteger(hrec, 1, 2);
964     ok(r == ERROR_SUCCESS, "failed to set integer\n");
965     r = MsiRecordSetString(hrec, 2, "jerry");
966     ok(r == ERROR_SUCCESS, "failed to set string\n");
967
968     r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
969     ok(r == ERROR_FUNCTION_FAILED, "MsiViewModify failed\n");
970
971     r = MsiCloseHandle(hrec);
972     ok(r == ERROR_SUCCESS, "failed to close record\n");
973     r = MsiViewClose(hview);
974     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
975     r = MsiCloseHandle(hview);
976     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
977
978     r = MsiCloseHandle( hdb );
979     ok(r == ERROR_SUCCESS, "MsiOpenDatabase close failed\n");
980 }
981
982 static MSIHANDLE create_db(void)
983 {
984     MSIHANDLE hdb = 0;
985     UINT res;
986
987     DeleteFile(msifile);
988
989     /* create an empty database */
990     res = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb );
991     ok( res == ERROR_SUCCESS , "Failed to create database\n" );
992     if( res != ERROR_SUCCESS )
993         return hdb;
994
995     res = MsiDatabaseCommit( hdb );
996     ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
997
998     return hdb;
999 }
1000
1001 static void test_getcolinfo(void)
1002 {
1003     MSIHANDLE hdb, hview = 0, rec = 0;
1004     UINT r;
1005     DWORD sz;
1006     char buffer[0x20];
1007
1008     /* create an empty db */
1009     hdb = create_db();
1010     ok( hdb, "failed to create db\n");
1011
1012     /* tables should be present */
1013     r = MsiDatabaseOpenView(hdb, "select * from _Tables", &hview);
1014     ok( r == ERROR_SUCCESS, "failed to open query\n");
1015
1016     r = MsiViewExecute(hview, 0);
1017     ok( r == ERROR_SUCCESS, "failed to execute query\n");
1018
1019     /* check that NAMES works */
1020     rec = 0;
1021     r = MsiViewGetColumnInfo( hview, MSICOLINFO_NAMES, &rec );
1022     ok( r == ERROR_SUCCESS, "failed to get names\n");
1023     sz = sizeof buffer;
1024     r = MsiRecordGetString(rec, 1, buffer, &sz );
1025     ok( r == ERROR_SUCCESS, "failed to get string\n");
1026     ok( !strcmp(buffer,"Name"), "_Tables has wrong column name\n");
1027     r = MsiCloseHandle( rec );
1028     ok( r == ERROR_SUCCESS, "failed to close record handle\n");
1029
1030     /* check that TYPES works */
1031     rec = 0;
1032     r = MsiViewGetColumnInfo( hview, MSICOLINFO_TYPES, &rec );
1033     ok( r == ERROR_SUCCESS, "failed to get names\n");
1034     sz = sizeof buffer;
1035     r = MsiRecordGetString(rec, 1, buffer, &sz );
1036     ok( r == ERROR_SUCCESS, "failed to get string\n");
1037     ok( !strcmp(buffer,"s64"), "_Tables has wrong column type\n");
1038     r = MsiCloseHandle( rec );
1039     ok( r == ERROR_SUCCESS, "failed to close record handle\n");
1040
1041     /* check that invalid values fail */
1042     rec = 0;
1043     r = MsiViewGetColumnInfo( hview, 100, &rec );
1044     ok( r == ERROR_INVALID_PARAMETER, "wrong error code\n");
1045     ok( rec == 0, "returned a record\n");
1046
1047     r = MsiViewGetColumnInfo( hview, MSICOLINFO_TYPES, NULL );
1048     ok( r == ERROR_INVALID_PARAMETER, "wrong error code\n");
1049
1050     r = MsiViewGetColumnInfo( 0, MSICOLINFO_TYPES, &rec );
1051     ok( r == ERROR_INVALID_HANDLE, "wrong error code\n");
1052
1053     r = MsiViewClose(hview);
1054     ok( r == ERROR_SUCCESS, "failed to close view\n");
1055     r = MsiCloseHandle(hview);
1056     ok( r == ERROR_SUCCESS, "failed to close view handle\n");
1057     r = MsiCloseHandle(hdb);
1058     ok( r == ERROR_SUCCESS, "failed to close database\n");
1059 }
1060
1061 static MSIHANDLE get_column_info(MSIHANDLE hdb, const char *query, MSICOLINFO type)
1062 {
1063     MSIHANDLE hview = 0, rec = 0;
1064     UINT r;
1065
1066     r = MsiDatabaseOpenView(hdb, query, &hview);
1067     if( r != ERROR_SUCCESS )
1068         return r;
1069
1070     r = MsiViewExecute(hview, 0);
1071     if( r == ERROR_SUCCESS )
1072     {
1073         MsiViewGetColumnInfo( hview, type, &rec );
1074     }
1075     MsiViewClose(hview);
1076     MsiCloseHandle(hview);
1077     return rec;
1078 }
1079
1080 static UINT get_columns_table_type(MSIHANDLE hdb, const char *table, UINT field)
1081 {
1082     MSIHANDLE hview = 0, rec = 0;
1083     UINT r, type = 0;
1084     char query[0x100];
1085
1086     sprintf(query, "select * from `_Columns` where  `Table` = '%s'", table );
1087
1088     r = MsiDatabaseOpenView(hdb, query, &hview);
1089     if( r != ERROR_SUCCESS )
1090         return r;
1091
1092     r = MsiViewExecute(hview, 0);
1093     if( r == ERROR_SUCCESS )
1094     {
1095         while (1)
1096         {
1097             r = MsiViewFetch( hview, &rec );
1098             if( r != ERROR_SUCCESS)
1099                 break;
1100             r = MsiRecordGetInteger( rec, 2 );
1101             if (r == field)
1102                 type = MsiRecordGetInteger( rec, 4 );
1103             MsiCloseHandle( rec );
1104         }
1105     }
1106     MsiViewClose(hview);
1107     MsiCloseHandle(hview);
1108     return type;
1109 }
1110
1111 static BOOL check_record( MSIHANDLE rec, UINT field, LPCSTR val )
1112 {
1113     CHAR buffer[0x20];
1114     UINT r;
1115     DWORD sz;
1116
1117     sz = sizeof buffer;
1118     r = MsiRecordGetString( rec, field, buffer, &sz );
1119     return (r == ERROR_SUCCESS ) && !strcmp(val, buffer);
1120 }
1121
1122 static void test_viewgetcolumninfo(void)
1123 {
1124     MSIHANDLE hdb = 0, rec;
1125     UINT r;
1126
1127     hdb = create_db();
1128     ok( hdb, "failed to create db\n");
1129
1130     r = run_query( hdb, 0,
1131             "CREATE TABLE `Properties` "
1132             "( `Property` CHAR(255), "
1133             "  `Value` CHAR(1), "
1134             "  `Intvalue` INT, "
1135             "  `Integervalue` INTEGER, "
1136             "  `Shortvalue` SHORT, "
1137             "  `Longvalue` LONG, "
1138             "  `Longcharvalue` LONGCHAR "
1139             "  PRIMARY KEY `Property`)" );
1140     ok( r == ERROR_SUCCESS , "Failed to create table\n" );
1141
1142     /* check the column types */
1143     rec = get_column_info( hdb, "select * from `Properties`", MSICOLINFO_TYPES );
1144     ok( rec, "failed to get column info record\n" );
1145
1146     ok( check_record( rec, 1, "S255"), "wrong record type\n");
1147     ok( check_record( rec, 2, "S1"), "wrong record type\n");
1148     ok( check_record( rec, 3, "I2"), "wrong record type\n");
1149     ok( check_record( rec, 4, "I2"), "wrong record type\n");
1150     ok( check_record( rec, 5, "I2"), "wrong record type\n");
1151     ok( check_record( rec, 6, "I4"), "wrong record type\n");
1152     ok( check_record( rec, 7, "S0"), "wrong record type\n");
1153
1154     MsiCloseHandle( rec );
1155
1156     /* check the type in _Columns */
1157     ok( 0x3dff == get_columns_table_type(hdb, "Properties", 1 ), "_columns table wrong\n");
1158     ok( 0x1d01 == get_columns_table_type(hdb, "Properties", 2 ), "_columns table wrong\n");
1159     ok( 0x1502 == get_columns_table_type(hdb, "Properties", 3 ), "_columns table wrong\n");
1160     ok( 0x1502 == get_columns_table_type(hdb, "Properties", 4 ), "_columns table wrong\n");
1161     ok( 0x1502 == get_columns_table_type(hdb, "Properties", 5 ), "_columns table wrong\n");
1162     ok( 0x1104 == get_columns_table_type(hdb, "Properties", 6 ), "_columns table wrong\n");
1163     ok( 0x1d00 == get_columns_table_type(hdb, "Properties", 7 ), "_columns table wrong\n");
1164
1165     /* now try the names */
1166     rec = get_column_info( hdb, "select * from `Properties`", MSICOLINFO_NAMES );
1167     ok( rec, "failed to get column info record\n" );
1168
1169     ok( check_record( rec, 1, "Property"), "wrong record type\n");
1170     ok( check_record( rec, 2, "Value"), "wrong record type\n");
1171     ok( check_record( rec, 3, "Intvalue"), "wrong record type\n");
1172     ok( check_record( rec, 4, "Integervalue"), "wrong record type\n");
1173     ok( check_record( rec, 5, "Shortvalue"), "wrong record type\n");
1174     ok( check_record( rec, 6, "Longvalue"), "wrong record type\n");
1175     ok( check_record( rec, 7, "Longcharvalue"), "wrong record type\n");
1176
1177     MsiCloseHandle( rec );
1178
1179     r = run_query( hdb, 0,
1180             "CREATE TABLE `Binary` "
1181             "( `Name` CHAR(255), `Data` OBJECT  PRIMARY KEY `Name`)" );
1182     ok( r == ERROR_SUCCESS , "Failed to create table\n" );
1183
1184     /* check the column types */
1185     rec = get_column_info( hdb, "select * from `Binary`", MSICOLINFO_TYPES );
1186     ok( rec, "failed to get column info record\n" );
1187
1188     ok( check_record( rec, 1, "S255"), "wrong record type\n");
1189     ok( check_record( rec, 2, "V0"), "wrong record type\n");
1190
1191     MsiCloseHandle( rec );
1192
1193     /* check the type in _Columns */
1194     ok( 0x3dff == get_columns_table_type(hdb, "Binary", 1 ), "_columns table wrong\n");
1195     ok( 0x1900 == get_columns_table_type(hdb, "Binary", 2 ), "_columns table wrong\n");
1196
1197     /* now try the names */
1198     rec = get_column_info( hdb, "select * from `Binary`", MSICOLINFO_NAMES );
1199     ok( rec, "failed to get column info record\n" );
1200
1201     ok( check_record( rec, 1, "Name"), "wrong record type\n");
1202     ok( check_record( rec, 2, "Data"), "wrong record type\n");
1203     MsiCloseHandle( rec );
1204
1205     r = run_query( hdb, 0,
1206             "CREATE TABLE `UIText` "
1207             "( `Key` CHAR(72) NOT NULL, `Text` CHAR(255) LOCALIZABLE PRIMARY KEY `Key`)" );
1208     ok( r == ERROR_SUCCESS , "Failed to create table\n" );
1209
1210     ok( 0x2d48 == get_columns_table_type(hdb, "UIText", 1 ), "_columns table wrong\n");
1211     ok( 0x1fff == get_columns_table_type(hdb, "UIText", 2 ), "_columns table wrong\n");
1212
1213     rec = get_column_info( hdb, "select * from `UIText`", MSICOLINFO_NAMES );
1214     ok( rec, "failed to get column info record\n" );
1215     ok( check_record( rec, 1, "Key"), "wrong record type\n");
1216     ok( check_record( rec, 2, "Text"), "wrong record type\n");
1217     MsiCloseHandle( rec );
1218
1219     rec = get_column_info( hdb, "select * from `UIText`", MSICOLINFO_TYPES );
1220     ok( rec, "failed to get column info record\n" );
1221     ok( check_record( rec, 1, "s72"), "wrong record type\n");
1222     ok( check_record( rec, 2, "L255"), "wrong record type\n");
1223     MsiCloseHandle( rec );
1224
1225     MsiCloseHandle( hdb );
1226 }
1227
1228 static void test_msiexport(void)
1229 {
1230     MSIHANDLE hdb = 0, hview = 0;
1231     UINT r;
1232     const char *query;
1233     char path[MAX_PATH];
1234     const char file[] = "phone.txt";
1235     HANDLE handle;
1236     char buffer[0x100];
1237     DWORD length;
1238     const char expected[] =
1239         "id\tname\tnumber\r\n"
1240         "I2\tS32\tS32\r\n"
1241         "phone\tid\r\n"
1242         "1\tAbe\t8675309\r\n";
1243
1244     DeleteFile(msifile);
1245
1246     /* just MsiOpenDatabase should not create a file */
1247     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
1248     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
1249
1250     /* create a table */
1251     query = "CREATE TABLE `phone` ( "
1252             "`id` INT, `name` CHAR(32), `number` CHAR(32) "
1253             "PRIMARY KEY `id`)";
1254     r = MsiDatabaseOpenView(hdb, query, &hview);
1255     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
1256     r = MsiViewExecute(hview, 0);
1257     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
1258     r = MsiViewClose(hview);
1259     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
1260     r = MsiCloseHandle(hview);
1261     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
1262
1263     /* insert a value into it */
1264     query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
1265         "VALUES('1', 'Abe', '8675309')";
1266     r = MsiDatabaseOpenView(hdb, query, &hview);
1267     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
1268     r = MsiViewExecute(hview, 0);
1269     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
1270     r = MsiViewClose(hview);
1271     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
1272     r = MsiCloseHandle(hview);
1273     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
1274
1275     GetCurrentDirectory(MAX_PATH, path);
1276
1277     r = MsiDatabaseExport(hdb, "phone", path, file);
1278     ok(r == ERROR_SUCCESS, "MsiDatabaseExport failed\n");
1279
1280     MsiCloseHandle(hdb);
1281
1282     lstrcat(path, "\\");
1283     lstrcat(path, file);
1284
1285     /* check the data that was written */
1286     length = 0;
1287     memset(buffer, 0, sizeof buffer);
1288     handle = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
1289     if (handle != INVALID_HANDLE_VALUE)
1290     {
1291         ReadFile(handle, buffer, sizeof buffer, &length, NULL);
1292         CloseHandle(handle);
1293         DeleteFile(path);
1294     }
1295     else
1296         ok(0, "failed to open file %s\n", path);
1297
1298     ok( length == strlen(expected), "length of data wrong\n");
1299     ok( !lstrcmp(buffer, expected), "data doesn't match\n");
1300     DeleteFile(msifile);
1301 }
1302
1303 static void test_longstrings(void)
1304 {
1305     const char insert_query[] = 
1306         "INSERT INTO `strings` ( `id`, `val` ) VALUES('1', 'Z')";
1307     char *str;
1308     MSIHANDLE hdb = 0, hview = 0, hrec = 0;
1309     DWORD len;
1310     UINT r;
1311     const DWORD STRING_LENGTH = 0x10005;
1312
1313     DeleteFile(msifile);
1314     /* just MsiOpenDatabase should not create a file */
1315     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
1316     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
1317
1318     /* create a table */
1319     r = try_query( hdb, 
1320         "CREATE TABLE `strings` ( `id` INT, `val` CHAR(0) PRIMARY KEY `id`)");
1321     ok(r == ERROR_SUCCESS, "query failed\n");
1322
1323     /* try a insert a very long string */
1324     str = HeapAlloc(GetProcessHeap(), 0, STRING_LENGTH+sizeof insert_query);
1325     len = strchr(insert_query, 'Z') - insert_query;
1326     strcpy(str, insert_query);
1327     memset(str+len, 'Z', STRING_LENGTH);
1328     strcpy(str+len+STRING_LENGTH, insert_query+len+1);
1329     r = try_query( hdb, str );
1330     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
1331
1332     HeapFree(GetProcessHeap(), 0, str);
1333
1334     MsiDatabaseCommit(hdb);
1335     ok(r == ERROR_SUCCESS, "MsiDatabaseCommit failed\n");
1336     MsiCloseHandle(hdb);
1337
1338     r = MsiOpenDatabase(msifile, MSIDBOPEN_READONLY, &hdb);
1339     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
1340
1341     r = MsiDatabaseOpenView(hdb, "select * from `strings` where `id` = 1", &hview);
1342     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
1343
1344     r = MsiViewExecute(hview, 0);
1345     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
1346
1347     r = MsiViewFetch(hview, &hrec);
1348     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
1349
1350     MsiViewClose(hview);
1351     MsiCloseHandle(hview);
1352
1353     r = MsiRecordGetString(hrec, 2, NULL, &len);
1354     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
1355     ok(len == STRING_LENGTH, "string length wrong\n");
1356
1357     MsiCloseHandle(hrec);
1358     MsiCloseHandle(hdb);
1359     DeleteFile(msifile);
1360 }
1361
1362 static void create_file_data(LPCSTR name, LPCSTR data, DWORD size)
1363 {
1364     HANDLE file;
1365     DWORD written;
1366
1367     file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
1368     if (file == INVALID_HANDLE_VALUE)
1369         return;
1370
1371     WriteFile(file, data, strlen(data), &written, NULL);
1372     WriteFile(file, "\n", strlen("\n"), &written, NULL);
1373
1374     if (size)
1375     {
1376         SetFilePointer(file, size, NULL, FILE_BEGIN);
1377         SetEndOfFile(file);
1378     }
1379
1380     CloseHandle(file);
1381 }
1382
1383 #define create_file(name) create_file_data(name, name, 0)
1384  
1385 static void test_streamtable(void)
1386 {
1387     MSIHANDLE hdb = 0, rec, view;
1388     char file[MAX_PATH];
1389     char buf[MAX_PATH];
1390     DWORD size;
1391     UINT r;
1392
1393     hdb = create_db();
1394     ok( hdb, "failed to create db\n");
1395
1396     r = run_query( hdb, 0,
1397             "CREATE TABLE `Properties` "
1398             "( `Property` CHAR(255), `Value` CHAR(1)  PRIMARY KEY `Property`)" );
1399     ok( r == ERROR_SUCCESS , "Failed to create table\n" );
1400
1401     r = run_query( hdb, 0,
1402             "INSERT INTO `Properties` "
1403             "( `Value`, `Property` ) VALUES ( 'Prop', 'value' )" );
1404     ok( r == ERROR_SUCCESS, "Failed to add to table\n" );
1405
1406     r = MsiDatabaseCommit( hdb );
1407     ok( r == ERROR_SUCCESS , "Failed to commit database\n" );
1408
1409     MsiCloseHandle( hdb );
1410
1411     r = MsiOpenDatabase(msifile, MSIDBOPEN_TRANSACT, &hdb );
1412     ok( r == ERROR_SUCCESS , "Failed to open database\n" );
1413
1414     /* check the column types */
1415     rec = get_column_info( hdb, "select * from `_Streams`", MSICOLINFO_TYPES );
1416     ok( rec, "failed to get column info record\n" );
1417
1418     ok( check_record( rec, 1, "s62"), "wrong record type\n");
1419     ok( check_record( rec, 2, "V0"), "wrong record type\n");
1420
1421     MsiCloseHandle( rec );
1422
1423     /* now try the names */
1424     rec = get_column_info( hdb, "select * from `_Streams`", MSICOLINFO_NAMES );
1425     ok( rec, "failed to get column info record\n" );
1426
1427     ok( check_record( rec, 1, "Name"), "wrong record type\n");
1428     ok( check_record( rec, 2, "Data"), "wrong record type\n");
1429
1430     MsiCloseHandle( rec );
1431
1432     /* insert a file into the _Streams table */
1433     create_file( "test.txt" );
1434
1435     rec = MsiCreateRecord( 2 );
1436     MsiRecordSetString( rec, 1, "data" );
1437
1438     r = MsiRecordSetStream( rec, 2, "test.txt" );
1439     ok( r == ERROR_SUCCESS, "Failed to add stream data to the record: %d\n", r);
1440
1441     DeleteFile("test.txt");
1442
1443     r = MsiDatabaseOpenView( hdb,
1444             "INSERT INTO `_Streams` ( `Name`, `Data` ) VALUES ( ?, ? )", &view );
1445     ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r);
1446
1447     r = MsiViewExecute( view, rec );
1448     ok( r == ERROR_SUCCESS, "Failed to execute view: %d\n", r);
1449
1450     MsiCloseHandle( rec );
1451     MsiViewClose( view );
1452     MsiCloseHandle( view );
1453
1454     r = MsiDatabaseOpenView( hdb,
1455             "SELECT `Name`, `Data` FROM `_Streams`", &view );
1456     ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r);
1457
1458     r = MsiViewExecute( view, 0 );
1459     ok( r == ERROR_SUCCESS, "Failed to execute view: %d\n", r);
1460
1461     r = MsiViewFetch( view, &rec );
1462     ok( r == ERROR_SUCCESS, "Failed to fetch record: %d\n", r);
1463
1464     size = MAX_PATH;
1465     r = MsiRecordGetString( rec, 1, file, &size );
1466     ok( r == ERROR_SUCCESS, "Failed to get string: %d\n", r);
1467     ok( !lstrcmp(file, "data"), "Expected 'data', got %s\n", file);
1468
1469     size = MAX_PATH;
1470     memset(buf, 0, MAX_PATH);
1471     r = MsiRecordReadStream( rec, 2, buf, &size );
1472     ok( r == ERROR_SUCCESS, "Failed to get stream: %d\n", r);
1473     ok( !lstrcmp(buf, "test.txt\n"), "Expected 'test.txt\\n', got %s\n", buf);
1474
1475     MsiCloseHandle( rec );
1476
1477     r = MsiViewFetch( view, &rec );
1478     ok( r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
1479
1480     MsiViewClose( view );
1481     MsiCloseHandle( view );
1482     MsiCloseHandle( hdb );
1483     DeleteFile(msifile);
1484 }
1485
1486 static void test_binary(void)
1487 {
1488     MSIHANDLE hdb = 0, rec;
1489     char file[MAX_PATH];
1490     char buf[MAX_PATH];
1491     DWORD size;
1492     LPCSTR query;
1493     UINT r;
1494
1495     /* insert a file into the Binary table */
1496     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb );
1497     ok( r == ERROR_SUCCESS , "Failed to open database\n" );
1498
1499     query = "CREATE TABLE `Binary` ( `Name` CHAR(72) NOT NULL, `ID` INT NOT NULL, `Data` OBJECT  PRIMARY KEY `Name`, `ID`)";
1500     r = run_query( hdb, 0, query );
1501     ok( r == ERROR_SUCCESS, "Cannot create Binary table: %d\n", r );
1502
1503     create_file( "test.txt" );
1504     rec = MsiCreateRecord( 1 );
1505     r = MsiRecordSetStream( rec, 1, "test.txt" );
1506     ok( r == ERROR_SUCCESS, "Failed to add stream data to the record: %d\n", r);
1507     DeleteFile( "test.txt" );
1508
1509     query = "INSERT INTO `Binary` ( `Name`, `ID`, `Data` ) VALUES ( 'filename1', 1, ? )";
1510     r = run_query( hdb, rec, query );
1511     ok( r == ERROR_SUCCESS, "Insert into Binary table failed: %d\n", r );
1512
1513     r = MsiCloseHandle( rec );
1514     ok( r == ERROR_SUCCESS , "Failed to close record handle\n" );
1515
1516     r = MsiDatabaseCommit( hdb );
1517     ok( r == ERROR_SUCCESS , "Failed to commit database\n" );
1518
1519     r = MsiCloseHandle( hdb );
1520     ok( r == ERROR_SUCCESS , "Failed to close database\n" );
1521
1522     /* read file from the Stream table */
1523     r = MsiOpenDatabase( msifile, MSIDBOPEN_READONLY, &hdb );
1524     ok( r == ERROR_SUCCESS , "Failed to open database\n" );
1525
1526     query = "SELECT * FROM `_Streams`";
1527     r = do_query( hdb, query, &rec );
1528     ok( r == ERROR_SUCCESS, "SELECT query failed: %d\n", r );
1529
1530     size = MAX_PATH;
1531     r = MsiRecordGetString( rec, 1, file, &size );
1532     ok( r == ERROR_SUCCESS, "Failed to get string: %d\n", r );
1533     ok( !lstrcmp(file, "Binary.filename1.1"), "Expected 'Binary.filename1.1', got %s\n", file );
1534
1535     size = MAX_PATH;
1536     memset( buf, 0, MAX_PATH );
1537     r = MsiRecordReadStream( rec, 2, buf, &size );
1538     ok( r == ERROR_SUCCESS, "Failed to get stream: %d\n", r );
1539     ok( !lstrcmp(buf, "test.txt\n"), "Expected 'test.txt\\n', got %s\n", buf );
1540
1541     r = MsiCloseHandle( rec );
1542     ok( r == ERROR_SUCCESS , "Failed to close record handle\n" );
1543
1544     /* read file from the Binary table */
1545     query = "SELECT * FROM `Binary`";
1546     r = do_query( hdb, query, &rec );
1547     ok( r == ERROR_SUCCESS, "SELECT query failed: %d\n", r );
1548
1549     size = MAX_PATH;
1550     r = MsiRecordGetString( rec, 1, file, &size );
1551     ok( r == ERROR_SUCCESS, "Failed to get string: %d\n", r );
1552     ok( !lstrcmp(file, "filename1"), "Expected 'filename1', got %s\n", file );
1553
1554     size = MAX_PATH;
1555     memset( buf, 0, MAX_PATH );
1556     r = MsiRecordReadStream( rec, 3, buf, &size );
1557     ok( r == ERROR_SUCCESS, "Failed to get stream: %d\n", r );
1558     ok( !lstrcmp(buf, "test.txt\n"), "Expected 'test.txt\\n', got %s\n", buf );
1559
1560     r = MsiCloseHandle( rec );
1561     ok( r == ERROR_SUCCESS , "Failed to close record handle\n" );
1562
1563     r = MsiCloseHandle( hdb );
1564     ok( r == ERROR_SUCCESS , "Failed to close database\n" );
1565
1566     DeleteFile( msifile );
1567 }
1568
1569 static void test_where(void)
1570 {
1571     MSIHANDLE hdb = 0, rec, view;
1572     LPCSTR query;
1573     UINT r;
1574     DWORD size;
1575     CHAR buf[MAX_PATH];
1576     UINT count;
1577
1578     hdb = create_db();
1579     ok( hdb, "failed to create db\n");
1580
1581     r = run_query( hdb, 0,
1582             "CREATE TABLE `Media` ("
1583             "`DiskId` SHORT NOT NULL, "
1584             "`LastSequence` LONG, "
1585             "`DiskPrompt` CHAR(64) LOCALIZABLE, "
1586             "`Cabinet` CHAR(255), "
1587             "`VolumeLabel` CHAR(32), "
1588             "`Source` CHAR(72) "
1589             "PRIMARY KEY `DiskId`)" );
1590     ok( r == S_OK, "cannot create Media table: %d\n", r );
1591
1592     r = run_query( hdb, 0, "INSERT INTO `Media` "
1593             "( `DiskId`, `LastSequence`, `DiskPrompt`, `Cabinet`, `VolumeLabel`, `Source` ) "
1594             "VALUES ( 1, 0, '', 'zero.cab', '', '' )" );
1595     ok( r == S_OK, "cannot add file to the Media table: %d\n", r );
1596
1597     r = run_query( hdb, 0, "INSERT INTO `Media` "
1598             "( `DiskId`, `LastSequence`, `DiskPrompt`, `Cabinet`, `VolumeLabel`, `Source` ) "
1599             "VALUES ( 2, 1, '', 'one.cab', '', '' )" );
1600     ok( r == S_OK, "cannot add file to the Media table: %d\n", r );
1601
1602     r = run_query( hdb, 0, "INSERT INTO `Media` "
1603             "( `DiskId`, `LastSequence`, `DiskPrompt`, `Cabinet`, `VolumeLabel`, `Source` ) "
1604             "VALUES ( 3, 2, '', 'two.cab', '', '' )" );
1605     ok( r == S_OK, "cannot add file to the Media table: %d\n", r );
1606
1607     query = "SELECT * FROM `Media`";
1608     r = do_query(hdb, query, &rec);
1609     ok(r == ERROR_SUCCESS, "MsiViewFetch failed: %d\n", r);
1610     ok( check_record( rec, 4, "zero.cab"), "wrong cabinet\n");
1611     MsiCloseHandle( rec );
1612
1613     query = "SELECT * FROM `Media` WHERE `LastSequence` >= 1";
1614     r = do_query(hdb, query, &rec);
1615     ok(r == ERROR_SUCCESS, "MsiViewFetch failed: %d\n", r);
1616     ok( check_record( rec, 4, "one.cab"), "wrong cabinet\n");
1617
1618     r = MsiRecordGetInteger(rec, 1);
1619     ok( 2 == r, "field wrong\n");
1620     r = MsiRecordGetInteger(rec, 2);
1621     ok( 1 == r, "field wrong\n");
1622     MsiCloseHandle( rec );
1623
1624     query = "SELECT `DiskId` FROM `Media` WHERE `LastSequence` >= 1 AND DiskId >= 0";
1625     r = MsiDatabaseOpenView(hdb, query, &view);
1626     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
1627
1628     r = MsiViewExecute(view, 0);
1629     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
1630
1631     r = MsiViewFetch(view, &rec);
1632     ok( r == ERROR_SUCCESS, "failed to fetch view: %d\n", r );
1633
1634     count = MsiRecordGetFieldCount( rec );
1635     ok( count == 1, "Expected 1 record fields, got %d\n", count );
1636
1637     size = MAX_PATH;
1638     r = MsiRecordGetString( rec, 1, buf, &size );
1639     ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
1640     ok( !lstrcmp( buf, "2" ),
1641         "For (row %d, column 1) expected '%d', got %s\n", 0, 2, buf );
1642     MsiCloseHandle( rec );
1643
1644     r = MsiViewFetch(view, &rec);
1645     ok( r == ERROR_SUCCESS, "failed to fetch view: %d\n", r );
1646
1647     size = MAX_PATH;
1648     r = MsiRecordGetString( rec, 1, buf, &size );
1649     ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
1650     ok( !lstrcmp( buf, "3" ),
1651         "For (row %d, column 1) expected '%d', got %s\n", 1, 3, buf );
1652     MsiCloseHandle( rec );
1653
1654     r = MsiViewFetch(view, &rec);
1655     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
1656
1657     MsiViewClose(view);
1658     MsiCloseHandle(view);
1659
1660     MsiCloseHandle( rec );
1661
1662     rec = 0;
1663     query = "SELECT * FROM `Media` WHERE `DiskPrompt` IS NULL";
1664     r = do_query(hdb, query, &rec);
1665     ok( r == ERROR_SUCCESS, "query failed: %d\n", r );
1666     MsiCloseHandle( rec );
1667
1668     rec = MsiCreateRecord(1);
1669     MsiRecordSetString(rec, 1, "");
1670
1671     query = "SELECT * FROM `Media` WHERE `DiskPrompt` = ?";
1672     r = MsiDatabaseOpenView(hdb, query, &view);
1673     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1674     r = MsiViewExecute(view, rec);
1675     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1676
1677     MsiCloseHandle(rec);
1678
1679     r = MsiViewFetch(view, &rec);
1680     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1681
1682     MsiCloseHandle(rec);
1683     MsiViewClose(view);
1684     MsiCloseHandle(view);
1685
1686     MsiCloseHandle( hdb );
1687     DeleteFile(msifile);
1688 }
1689
1690 static CHAR CURR_DIR[MAX_PATH];
1691
1692 static const CHAR test_data[] = "FirstPrimaryColumn\tSecondPrimaryColumn\tShortInt\tShortIntNullable\tLongInt\tLongIntNullable\tString\tLocalizableString\tLocalizableStringNullable\n"
1693                                 "s255\ti2\ti2\tI2\ti4\tI4\tS255\tS0\ts0\n"
1694                                 "TestTable\tFirstPrimaryColumn\n"
1695                                 "stringage\t5\t2\t\t2147483640\t-2147483640\tanother string\tlocalizable\tduh\n";
1696
1697 static const CHAR two_primary[] = "PrimaryOne\tPrimaryTwo\n"
1698                                   "s255\ts255\n"
1699                                   "TwoPrimary\tPrimaryOne\tPrimaryTwo\n"
1700                                   "papaya\tleaf\n"
1701                                   "papaya\tflower\n";
1702
1703 static const CHAR endlines1[] = "A\tB\tC\tD\tE\tF\r\n"
1704                                 "s72\ts72\ts72\ts72\ts72\ts72\n"
1705                                 "Table\tA\r\n"
1706                                 "a\tb\tc\td\te\tf\n"
1707                                 "g\th\ti\t\rj\tk\tl\r\n";
1708
1709 static const CHAR endlines2[] = "A\tB\tC\tD\tE\tF\r"
1710                                 "s72\ts72\ts72\ts72\ts72\ts72\n"
1711                                 "Table2\tA\r\n"
1712                                 "a\tb\tc\td\te\tf\n"
1713                                 "g\th\ti\tj\tk\tl\r\n";
1714
1715 static const CHAR suminfo[] = "PropertyId\tValue\n"
1716                               "i2\tl255\n"
1717                               "_SummaryInformation\tPropertyId\n"
1718                               "1\t1252\n"
1719                               "2\tInstaller Database\n"
1720                               "3\tInstaller description\n"
1721                               "4\tWineHQ\n"
1722                               "5\tInstaller\n"
1723                               "6\tInstaller comments\n"
1724                               "7\tIntel;1033\n"
1725                               "9\t{12345678-1234-1234-1234-123456789012}\n"
1726                               "12\t2009/04/12 15:46:11\n"
1727                               "13\t2009/04/12 15:46:11\n"
1728                               "14\t200\n"
1729                               "15\t2\n"
1730                               "18\tVim\n"
1731                               "19\t2\n";
1732
1733 static void write_file(const CHAR *filename, const char *data, int data_size)
1734 {
1735     DWORD size;
1736
1737     HANDLE hf = CreateFile(filename, GENERIC_WRITE, 0, NULL,
1738                            CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1739
1740     WriteFile(hf, data, data_size, &size, NULL);
1741     CloseHandle(hf);
1742 }
1743
1744 static UINT add_table_to_db(MSIHANDLE hdb, LPCSTR table_data)
1745 {
1746     UINT r;
1747
1748     write_file("temp_file", table_data, (lstrlen(table_data) - 1) * sizeof(char));
1749     r = MsiDatabaseImportA(hdb, CURR_DIR, "temp_file");
1750     DeleteFileA("temp_file");
1751
1752     return r;
1753 }
1754
1755 static void test_suminfo_import(void)
1756 {
1757     MSIHANDLE hdb, hsi, view = 0;
1758     LPCSTR query;
1759     UINT r, count, size, type;
1760     char str_value[50];
1761     INT int_value;
1762     FILETIME ft_value;
1763
1764     GetCurrentDirectoryA(MAX_PATH, CURR_DIR);
1765
1766     r = MsiOpenDatabaseA(msifile, MSIDBOPEN_CREATE, &hdb);
1767     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
1768
1769     r = add_table_to_db(hdb, suminfo);
1770     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
1771
1772     /* _SummaryInformation is not imported as a regular table... */
1773
1774     query = "SELECT * FROM `_SummaryInformation`";
1775     r = MsiDatabaseOpenViewA(hdb, query, &view);
1776     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %u\n", r);
1777     MsiCloseHandle(view);
1778
1779     /* ...its data is added to the special summary information stream */
1780
1781     r = MsiGetSummaryInformationA(hdb, NULL, 0, &hsi);
1782     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
1783
1784     r = MsiSummaryInfoGetPropertyCount(hsi, &count);
1785     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
1786     ok(count == 14, "Expected 14, got %u\n", count);
1787
1788     r = MsiSummaryInfoGetPropertyA(hsi, PID_CODEPAGE, &type, &int_value, NULL, NULL, NULL);
1789     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
1790     ok(type ==  VT_I2, "Expected VT_I2, got %u\n", type);
1791     ok(int_value == 1252, "Expected 1252, got %d\n", int_value);
1792
1793     size = sizeof(str_value);
1794     r = MsiSummaryInfoGetPropertyA(hsi, PID_TITLE, &type, NULL, NULL, str_value, &size);
1795     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
1796     ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
1797     ok(size == 18, "Expected 18, got %u\n", size);
1798     ok(!strcmp(str_value, "Installer Database"),
1799        "Expected \"Installer Database\", got %s\n", str_value);
1800
1801     size = sizeof(str_value);
1802     r = MsiSummaryInfoGetPropertyA(hsi, PID_SUBJECT, &type, NULL, NULL, str_value, &size);
1803     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
1804     ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
1805     ok(!strcmp(str_value, "Installer description"),
1806        "Expected \"Installer description\", got %s\n", str_value);
1807
1808     size = sizeof(str_value);
1809     r = MsiSummaryInfoGetPropertyA(hsi, PID_AUTHOR, &type, NULL, NULL, str_value, &size);
1810     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
1811     ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
1812     ok(!strcmp(str_value, "WineHQ"),
1813        "Expected \"WineHQ\", got %s\n", str_value);
1814
1815     size = sizeof(str_value);
1816     r = MsiSummaryInfoGetPropertyA(hsi, PID_KEYWORDS, &type, NULL, NULL, str_value, &size);
1817     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
1818     ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
1819     ok(!strcmp(str_value, "Installer"),
1820        "Expected \"Installer\", got %s\n", str_value);
1821
1822     size = sizeof(str_value);
1823     r = MsiSummaryInfoGetPropertyA(hsi, PID_COMMENTS, &type, NULL, NULL, str_value, &size);
1824     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
1825     ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
1826     ok(!strcmp(str_value, "Installer comments"),
1827        "Expected \"Installer comments\", got %s\n", str_value);
1828
1829     size = sizeof(str_value);
1830     r = MsiSummaryInfoGetPropertyA(hsi, PID_TEMPLATE, &type, NULL, NULL, str_value, &size);
1831     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
1832     ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
1833     ok(!strcmp(str_value, "Intel;1033"),
1834        "Expected \"Intel;1033\", got %s\n", str_value);
1835
1836     size = sizeof(str_value);
1837     r = MsiSummaryInfoGetPropertyA(hsi, PID_REVNUMBER, &type, NULL, NULL, str_value, &size);
1838     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
1839     ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
1840     ok(!strcmp(str_value, "{12345678-1234-1234-1234-123456789012}"),
1841        "Expected \"{12345678-1234-1234-1234-123456789012}\", got %s\n", str_value);
1842
1843     r = MsiSummaryInfoGetPropertyA(hsi, PID_CREATE_DTM, &type, NULL, &ft_value, NULL, NULL);
1844     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
1845     ok(type == VT_FILETIME, "Expected VT_FILETIME, got %u\n", type);
1846
1847     r = MsiSummaryInfoGetPropertyA(hsi, PID_LASTSAVE_DTM, &type, NULL, &ft_value, NULL, NULL);
1848     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
1849     ok(type == VT_FILETIME, "Expected VT_FILETIME, got %u\n", type);
1850
1851     r = MsiSummaryInfoGetPropertyA(hsi, PID_PAGECOUNT, &type, &int_value, NULL, NULL, NULL);
1852     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
1853     ok(type ==  VT_I4, "Expected VT_I4, got %u\n", type);
1854     ok(int_value == 200, "Expected 200, got %d\n", int_value);
1855
1856     r = MsiSummaryInfoGetPropertyA(hsi, PID_WORDCOUNT, &type, &int_value, NULL, NULL, NULL);
1857     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
1858     ok(type ==  VT_I4, "Expected VT_I4, got %u\n", type);
1859     ok(int_value == 2, "Expected 2, got %d\n", int_value);
1860
1861     r = MsiSummaryInfoGetPropertyA(hsi, PID_SECURITY, &type, &int_value, NULL, NULL, NULL);
1862     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
1863     ok(type ==  VT_I4, "Expected VT_I4, got %u\n", type);
1864     ok(int_value == 2, "Expected 2, got %d\n", int_value);
1865
1866     size = sizeof(str_value);
1867     r = MsiSummaryInfoGetPropertyA(hsi, PID_APPNAME, &type, NULL, NULL, str_value, &size);
1868     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
1869     ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
1870     ok(!strcmp(str_value, "Vim"), "Expected \"Vim\", got %s\n", str_value);
1871
1872     MsiCloseHandle(hsi);
1873     MsiCloseHandle(hdb);
1874     DeleteFileA(msifile);
1875 }
1876
1877 static void test_msiimport(void)
1878 {
1879     MSIHANDLE hdb, view, rec;
1880     LPCSTR query;
1881     UINT r, count;
1882     signed int i;
1883
1884     GetCurrentDirectoryA(MAX_PATH, CURR_DIR);
1885
1886     r = MsiOpenDatabaseA(msifile, MSIDBOPEN_CREATE, &hdb);
1887     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1888
1889     r = add_table_to_db(hdb, test_data);
1890     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1891
1892     r = add_table_to_db(hdb, two_primary);
1893     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1894
1895     r = add_table_to_db(hdb, endlines1);
1896     if (r == ERROR_FUNCTION_FAILED)
1897     {
1898         /* win9x doesn't handle this case */
1899         skip("endlines not handled correctly.\n");
1900         MsiCloseHandle(hdb);
1901         DeleteFileA(msifile);
1902         return;
1903     }
1904
1905     r = add_table_to_db(hdb, endlines2);
1906     ok(r == ERROR_FUNCTION_FAILED,
1907        "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
1908
1909     query = "SELECT * FROM `TestTable`";
1910     r = MsiDatabaseOpenView(hdb, query, &view);
1911     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1912
1913     r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec);
1914     count = MsiRecordGetFieldCount(rec);
1915     ok(count == 9, "Expected 9, got %d\n", count);
1916     ok(check_record(rec, 1, "FirstPrimaryColumn"), "Expected FirstPrimaryColumn\n");
1917     ok(check_record(rec, 2, "SecondPrimaryColumn"), "Expected SecondPrimaryColumn\n");
1918     ok(check_record(rec, 3, "ShortInt"), "Expected ShortInt\n");
1919     ok(check_record(rec, 4, "ShortIntNullable"), "Expected ShortIntNullalble\n");
1920     ok(check_record(rec, 5, "LongInt"), "Expected LongInt\n");
1921     ok(check_record(rec, 6, "LongIntNullable"), "Expected LongIntNullalble\n");
1922     ok(check_record(rec, 7, "String"), "Expected String\n");
1923     ok(check_record(rec, 8, "LocalizableString"), "Expected LocalizableString\n");
1924     ok(check_record(rec, 9, "LocalizableStringNullable"), "Expected LocalizableStringNullable\n");
1925     MsiCloseHandle(rec);
1926
1927     r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
1928     count = MsiRecordGetFieldCount(rec);
1929     ok(count == 9, "Expected 9, got %d\n", count);
1930     ok(check_record(rec, 1, "s255"), "Expected s255\n");
1931     ok(check_record(rec, 2, "i2"), "Expected i2\n");
1932     ok(check_record(rec, 3, "i2"), "Expected i2\n");
1933     ok(check_record(rec, 4, "I2"), "Expected I2\n");
1934     ok(check_record(rec, 5, "i4"), "Expected i4\n");
1935     ok(check_record(rec, 6, "I4"), "Expected I4\n");
1936     ok(check_record(rec, 7, "S255"), "Expected S255\n");
1937     ok(check_record(rec, 8, "S0"), "Expected S0\n");
1938     ok(check_record(rec, 9, "s0"), "Expected s0\n");
1939     MsiCloseHandle(rec);
1940
1941     query = "SELECT * FROM `TestTable`";
1942     r = do_query(hdb, query, &rec);
1943     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1944     ok(check_record(rec, 1, "stringage"), "Expected 'stringage'\n");
1945     ok(check_record(rec, 7, "another string"), "Expected 'another string'\n");
1946     ok(check_record(rec, 8, "localizable"), "Expected 'localizable'\n");
1947     ok(check_record(rec, 9, "duh"), "Expected 'duh'\n");
1948
1949     i = MsiRecordGetInteger(rec, 2);
1950     ok(i == 5, "Expected 5, got %d\n", i);
1951
1952     i = MsiRecordGetInteger(rec, 3);
1953     ok(i == 2, "Expected 2, got %d\n", i);
1954
1955     i = MsiRecordGetInteger(rec, 4);
1956     ok(i == MSI_NULL_INTEGER, "Expected MSI_NULL_INTEGER, got %d\n", i);
1957
1958     i = MsiRecordGetInteger(rec, 5);
1959     ok(i == 2147483640, "Expected 2147483640, got %d\n", i);
1960
1961     i = MsiRecordGetInteger(rec, 6);
1962     ok(i == -2147483640, "Expected -2147483640, got %d\n", i);
1963
1964     MsiCloseHandle(rec);
1965     MsiViewClose(view);
1966     MsiCloseHandle(view);
1967
1968     query = "SELECT * FROM `TwoPrimary`";
1969     r = MsiDatabaseOpenView(hdb, query, &view);
1970     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1971
1972     r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec);
1973     count = MsiRecordGetFieldCount(rec);
1974     ok(count == 2, "Expected 2, got %d\n", count);
1975     ok(check_record(rec, 1, "PrimaryOne"), "Expected PrimaryOne\n");
1976     ok(check_record(rec, 2, "PrimaryTwo"), "Expected PrimaryTwo\n");
1977
1978     MsiCloseHandle(rec);
1979
1980     r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
1981     count = MsiRecordGetFieldCount(rec);
1982     ok(count == 2, "Expected 2, got %d\n", count);
1983     ok(check_record(rec, 1, "s255"), "Expected s255\n");
1984     ok(check_record(rec, 2, "s255"), "Expected s255\n");
1985     MsiCloseHandle(rec);
1986
1987     r = MsiViewExecute(view, 0);
1988     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1989
1990     r = MsiViewFetch(view, &rec);
1991     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1992
1993     ok(check_record(rec, 1, "papaya"), "Expected 'papaya'\n");
1994     ok(check_record(rec, 2, "leaf"), "Expected 'leaf'\n");
1995
1996     MsiCloseHandle(rec);
1997
1998     r = MsiViewFetch(view, &rec);
1999     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2000
2001     ok(check_record(rec, 1, "papaya"), "Expected 'papaya'\n");
2002     ok(check_record(rec, 2, "flower"), "Expected 'flower'\n");
2003
2004     MsiCloseHandle(rec);
2005
2006     r = MsiViewFetch(view, &rec);
2007     ok(r == ERROR_NO_MORE_ITEMS,
2008        "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
2009
2010     r = MsiViewClose(view);
2011     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2012
2013     MsiCloseHandle(view);
2014
2015     query = "SELECT * FROM `Table`";
2016     r = MsiDatabaseOpenView(hdb, query, &view);
2017     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2018
2019     r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec);
2020     count = MsiRecordGetFieldCount(rec);
2021     ok(count == 6, "Expected 6, got %d\n", count);
2022     ok(check_record(rec, 1, "A"), "Expected A\n");
2023     ok(check_record(rec, 2, "B"), "Expected B\n");
2024     ok(check_record(rec, 3, "C"), "Expected C\n");
2025     ok(check_record(rec, 4, "D"), "Expected D\n");
2026     ok(check_record(rec, 5, "E"), "Expected E\n");
2027     ok(check_record(rec, 6, "F"), "Expected F\n");
2028     MsiCloseHandle(rec);
2029
2030     r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
2031     count = MsiRecordGetFieldCount(rec);
2032     ok(count == 6, "Expected 6, got %d\n", count);
2033     ok(check_record(rec, 1, "s72"), "Expected s72\n");
2034     ok(check_record(rec, 2, "s72"), "Expected s72\n");
2035     ok(check_record(rec, 3, "s72"), "Expected s72\n");
2036     ok(check_record(rec, 4, "s72"), "Expected s72\n");
2037     ok(check_record(rec, 5, "s72"), "Expected s72\n");
2038     ok(check_record(rec, 6, "s72"), "Expected s72\n");
2039     MsiCloseHandle(rec);
2040
2041     MsiViewClose(view);
2042     MsiCloseHandle(view);
2043
2044     query = "SELECT * FROM `Table`";
2045     r = MsiDatabaseOpenView(hdb, query, &view);
2046     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2047
2048     r = MsiViewExecute(view, 0);
2049     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2050
2051     r = MsiViewFetch(view, &rec);
2052     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2053     ok(check_record(rec, 1, "a"), "Expected 'a'\n");
2054     ok(check_record(rec, 2, "b"), "Expected 'b'\n");
2055     ok(check_record(rec, 3, "c"), "Expected 'c'\n");
2056     ok(check_record(rec, 4, "d"), "Expected 'd'\n");
2057     ok(check_record(rec, 5, "e"), "Expected 'e'\n");
2058     ok(check_record(rec, 6, "f"), "Expected 'f'\n");
2059
2060     MsiCloseHandle(rec);
2061
2062     r = MsiViewFetch(view, &rec);
2063     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2064     ok(check_record(rec, 1, "g"), "Expected 'g'\n");
2065     ok(check_record(rec, 2, "h"), "Expected 'h'\n");
2066     ok(check_record(rec, 3, "i"), "Expected 'i'\n");
2067     ok(check_record(rec, 4, "j"), "Expected 'j'\n");
2068     ok(check_record(rec, 5, "k"), "Expected 'k'\n");
2069     ok(check_record(rec, 6, "l"), "Expected 'l'\n");
2070
2071     MsiCloseHandle(rec);
2072
2073     r = MsiViewFetch(view, &rec);
2074     ok(r == ERROR_NO_MORE_ITEMS,
2075        "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
2076
2077     MsiViewClose(view);
2078     MsiCloseHandle(view);
2079     MsiCloseHandle(hdb);
2080     DeleteFileA(msifile);
2081 }
2082
2083 static const CHAR bin_import_dat[] = "Name\tData\r\n"
2084                                      "s72\tV0\r\n"
2085                                      "Binary\tName\r\n"
2086                                      "filename1\tfilename1.ibd\r\n";
2087
2088 static void test_binary_import(void)
2089 {
2090     MSIHANDLE hdb = 0, rec;
2091     char file[MAX_PATH];
2092     char buf[MAX_PATH];
2093     char path[MAX_PATH];
2094     DWORD size;
2095     LPCSTR query;
2096     UINT r;
2097
2098     /* create files to import */
2099     write_file("bin_import.idt", bin_import_dat,
2100           (sizeof(bin_import_dat) - 1) * sizeof(char));
2101     CreateDirectory("bin_import", NULL);
2102     create_file_data("bin_import/filename1.ibd", "just some words", 15);
2103
2104     /* import files into database */
2105     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
2106     ok( r == ERROR_SUCCESS , "Failed to open database\n");
2107
2108     GetCurrentDirectory(MAX_PATH, path);
2109     r = MsiDatabaseImport(hdb, path, "bin_import.idt");
2110     ok(r == ERROR_SUCCESS , "Failed to import Binary table\n");
2111
2112     /* read file from the Binary table */
2113     query = "SELECT * FROM `Binary`";
2114     r = do_query(hdb, query, &rec);
2115     ok(r == ERROR_SUCCESS, "SELECT query failed: %d\n", r);
2116
2117     size = MAX_PATH;
2118     r = MsiRecordGetString(rec, 1, file, &size);
2119     ok(r == ERROR_SUCCESS, "Failed to get string: %d\n", r);
2120     ok(!lstrcmp(file, "filename1"), "Expected 'filename1', got %s\n", file);
2121
2122     size = MAX_PATH;
2123     memset(buf, 0, MAX_PATH);
2124     r = MsiRecordReadStream(rec, 2, buf, &size);
2125     ok(r == ERROR_SUCCESS, "Failed to get stream: %d\n", r);
2126     ok(!lstrcmp(buf, "just some words"),
2127         "Expected 'just some words', got %s\n", buf);
2128
2129     r = MsiCloseHandle(rec);
2130     ok(r == ERROR_SUCCESS , "Failed to close record handle\n");
2131
2132     r = MsiCloseHandle(hdb);
2133     ok(r == ERROR_SUCCESS , "Failed to close database\n");
2134
2135     DeleteFile("bin_import/filename1.ibd");
2136     RemoveDirectory("bin_import");
2137     DeleteFile("bin_import.idt");
2138 }
2139
2140 static void test_markers(void)
2141 {
2142     MSIHANDLE hdb, rec;
2143     LPCSTR query;
2144     UINT r;
2145
2146     hdb = create_db();
2147     ok( hdb, "failed to create db\n");
2148
2149     rec = MsiCreateRecord(3);
2150     MsiRecordSetString(rec, 1, "Table");
2151     MsiRecordSetString(rec, 2, "Apples");
2152     MsiRecordSetString(rec, 3, "Oranges");
2153
2154     /* try a legit create */
2155     query = "CREATE TABLE `Table` ( `One` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`)";
2156     r = run_query(hdb, 0, query);
2157     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2158     MsiCloseHandle(rec);
2159
2160     /* try table name as marker */
2161     rec = MsiCreateRecord(1);
2162     MsiRecordSetString(rec, 1, "Fable");
2163     query = "CREATE TABLE `?` ( `One` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`)";
2164     r = run_query(hdb, rec, query);
2165     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2166
2167     /* verify that we just created a table called '?', not 'Fable' */
2168     r = try_query(hdb, "SELECT * from `Fable`");
2169     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2170
2171     r = try_query(hdb, "SELECT * from `?`");
2172     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2173
2174     /* try table name as marker without backticks */
2175     MsiRecordSetString(rec, 1, "Mable");
2176     query = "CREATE TABLE ? ( `One` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`)";
2177     r = run_query(hdb, rec, query);
2178     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2179
2180     /* try one column name as marker */
2181     MsiRecordSetString(rec, 1, "One");
2182     query = "CREATE TABLE `Mable` ( `?` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`)";
2183     r = run_query(hdb, rec, query);
2184     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2185     MsiCloseHandle(rec);
2186
2187     /* try column names as markers */
2188     rec = MsiCreateRecord(2);
2189     MsiRecordSetString(rec, 1, "One");
2190     MsiRecordSetString(rec, 2, "Two");
2191     query = "CREATE TABLE `Mable` ( `?` SHORT NOT NULL, `?` CHAR(255) PRIMARY KEY `One`)";
2192     r = run_query(hdb, rec, query);
2193     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2194     MsiCloseHandle(rec);
2195
2196     /* try names with backticks */
2197     rec = MsiCreateRecord(3);
2198     MsiRecordSetString(rec, 1, "One");
2199     MsiRecordSetString(rec, 2, "Two");
2200     MsiRecordSetString(rec, 3, "One");
2201     query = "CREATE TABLE `Mable` ( `?` SHORT NOT NULL, `?` CHAR(255) PRIMARY KEY `?`)";
2202     r = run_query(hdb, rec, query);
2203     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2204
2205     /* try names with backticks, minus definitions */
2206     query = "CREATE TABLE `Mable` ( `?`, `?` PRIMARY KEY `?`)";
2207     r = run_query(hdb, rec, query);
2208     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2209
2210     /* try names without backticks */
2211     query = "CREATE TABLE `Mable` ( ? SHORT NOT NULL, ? CHAR(255) PRIMARY KEY ?)";
2212     r = run_query(hdb, rec, query);
2213     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2214     MsiCloseHandle(rec);
2215
2216     /* try one long marker */
2217     rec = MsiCreateRecord(1);
2218     MsiRecordSetString(rec, 1, "`One` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`");
2219     query = "CREATE TABLE `Mable` ( ? )";
2220     r = run_query(hdb, rec, query);
2221     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2222     MsiCloseHandle(rec);
2223
2224     /* try all names as markers */
2225     rec = MsiCreateRecord(4);
2226     MsiRecordSetString(rec, 1, "Mable");
2227     MsiRecordSetString(rec, 2, "One");
2228     MsiRecordSetString(rec, 3, "Two");
2229     MsiRecordSetString(rec, 4, "One");
2230     query = "CREATE TABLE `?` ( `?` SHORT NOT NULL, `?` CHAR(255) PRIMARY KEY `?`)";
2231     r = run_query(hdb, rec, query);
2232     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2233     MsiCloseHandle(rec);
2234
2235     /* try a legit insert */
2236     query = "INSERT INTO `Table` ( `One`, `Two` ) VALUES ( 5, 'hello' )";
2237     r = run_query(hdb, 0, query);
2238     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2239
2240     r = try_query(hdb, "SELECT * from `Table`");
2241     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2242
2243     /* try values as markers */
2244     rec = MsiCreateRecord(2);
2245     MsiRecordSetInteger(rec, 1, 4);
2246     MsiRecordSetString(rec, 2, "hi");
2247     query = "INSERT INTO `Table` ( `One`, `Two` ) VALUES ( ?, '?' )";
2248     r = run_query(hdb, rec, query);
2249     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2250     MsiCloseHandle(rec);
2251
2252     /* try column names and values as markers */
2253     rec = MsiCreateRecord(4);
2254     MsiRecordSetString(rec, 1, "One");
2255     MsiRecordSetString(rec, 2, "Two");
2256     MsiRecordSetInteger(rec, 3, 5);
2257     MsiRecordSetString(rec, 4, "hi");
2258     query = "INSERT INTO `Table` ( `?`, `?` ) VALUES ( ?, '?' )";
2259     r = run_query(hdb, rec, query);
2260     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2261     MsiCloseHandle(rec);
2262
2263     /* try column names as markers */
2264     rec = MsiCreateRecord(2);
2265     MsiRecordSetString(rec, 1, "One");
2266     MsiRecordSetString(rec, 2, "Two");
2267     query = "INSERT INTO `Table` ( `?`, `?` ) VALUES ( 3, 'yellow' )";
2268     r = run_query(hdb, rec, query);
2269     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2270     MsiCloseHandle(rec);
2271
2272     /* try table name as a marker */
2273     rec = MsiCreateRecord(1);
2274     MsiRecordSetString(rec, 1, "Table");
2275     query = "INSERT INTO `?` ( `One`, `Two` ) VALUES ( 2, 'green' )";
2276     r = run_query(hdb, rec, query);
2277     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2278     MsiCloseHandle(rec);
2279
2280     /* try table name and values as markers */
2281     rec = MsiCreateRecord(3);
2282     MsiRecordSetString(rec, 1, "Table");
2283     MsiRecordSetInteger(rec, 2, 10);
2284     MsiRecordSetString(rec, 3, "haha");
2285     query = "INSERT INTO `?` ( `One`, `Two` ) VALUES ( ?, '?' )";
2286     r = run_query(hdb, rec, query);
2287     ok(r == ERROR_FUNCTION_FAILED, "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
2288     MsiCloseHandle(rec);
2289
2290     /* try all markers */
2291     rec = MsiCreateRecord(5);
2292     MsiRecordSetString(rec, 1, "Table");
2293     MsiRecordSetString(rec, 1, "One");
2294     MsiRecordSetString(rec, 1, "Two");
2295     MsiRecordSetInteger(rec, 2, 10);
2296     MsiRecordSetString(rec, 3, "haha");
2297     query = "INSERT INTO `?` ( `?`, `?` ) VALUES ( ?, '?' )";
2298     r = run_query(hdb, rec, query);
2299     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2300     MsiCloseHandle(rec);
2301
2302     /* insert an integer as a string */
2303     rec = MsiCreateRecord(2);
2304     MsiRecordSetString(rec, 1, "11");
2305     MsiRecordSetString(rec, 2, "hi");
2306     query = "INSERT INTO `Table` ( `One`, `Two` ) VALUES ( ?, '?' )";
2307     r = run_query(hdb, rec, query);
2308     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2309     MsiCloseHandle(rec);
2310
2311     /* leave off the '' for the string */
2312     rec = MsiCreateRecord(2);
2313     MsiRecordSetInteger(rec, 1, 12);
2314     MsiRecordSetString(rec, 2, "hi");
2315     query = "INSERT INTO `Table` ( `One`, `Two` ) VALUES ( ?, ? )";
2316     r = run_query(hdb, rec, query);
2317     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2318     MsiCloseHandle(rec);
2319
2320     MsiCloseHandle(hdb);
2321     DeleteFileA(msifile);
2322 }
2323
2324 #define MY_NVIEWS 4000    /* Largest installer I've seen uses < 2k */
2325 static void test_handle_limit(void)
2326 {
2327     int i;
2328     MSIHANDLE hdb;
2329     MSIHANDLE hviews[MY_NVIEWS];
2330     UINT r;
2331
2332     /* create an empty db */
2333     hdb = create_db();
2334     ok( hdb, "failed to create db\n");
2335
2336     memset(hviews, 0, sizeof(hviews));
2337
2338     for (i=0; i<MY_NVIEWS; i++) {
2339         static char szQueryBuf[256] = "SELECT * from `_Tables`";
2340         hviews[i] = 0xdeadbeeb;
2341         r = MsiDatabaseOpenView(hdb, szQueryBuf, &hviews[i]);
2342         if( r != ERROR_SUCCESS || hviews[i] == 0xdeadbeeb || 
2343             hviews[i] == 0 || (i && (hviews[i] == hviews[i-1])))
2344             break;
2345     }
2346
2347     ok( i == MY_NVIEWS, "problem opening views\n");
2348
2349     for (i=0; i<MY_NVIEWS; i++) {
2350         if (hviews[i] != 0 && hviews[i] != 0xdeadbeeb) {
2351             MsiViewClose(hviews[i]);
2352             r = MsiCloseHandle(hviews[i]);
2353             if (r != ERROR_SUCCESS)
2354                 break;
2355         }
2356     }
2357
2358     ok( i == MY_NVIEWS, "problem closing views\n");
2359
2360     r = MsiCloseHandle(hdb);
2361     ok( r == ERROR_SUCCESS, "failed to close database\n");
2362 }
2363
2364 static void generate_transform(void)
2365 {
2366     MSIHANDLE hdb1, hdb2, hrec;
2367     LPCSTR query;
2368     UINT r;
2369
2370     /* start with two identical databases */
2371     CopyFile(msifile2, msifile, FALSE);
2372
2373     r = MsiOpenDatabase(msifile, MSIDBOPEN_TRANSACT, &hdb1 );
2374     ok( r == ERROR_SUCCESS , "Failed to create database\n" );
2375
2376     r = MsiDatabaseCommit( hdb1 );
2377     ok( r == ERROR_SUCCESS , "Failed to commit database\n" );
2378
2379     r = MsiOpenDatabase(msifile2, MSIDBOPEN_READONLY, &hdb2 );
2380     ok( r == ERROR_SUCCESS , "Failed to create database\n" );
2381
2382     /* the transform between two identical database should be empty */
2383     r = MsiDatabaseGenerateTransform(hdb1, hdb2, NULL, 0, 0);
2384     todo_wine {
2385     ok( r == ERROR_NO_DATA, "return code %d, should be ERROR_NO_DATA\n", r );
2386     }
2387
2388     query = "CREATE TABLE `AAR` ( `BAR` SHORT NOT NULL, `CAR` CHAR(255) PRIMARY KEY `CAR`)";
2389     r = run_query(hdb1, 0, query);
2390     ok(r == ERROR_SUCCESS, "failed to add table\n");
2391
2392     query = "INSERT INTO `AAR` ( `BAR`, `CAR` ) VALUES ( 1, 'vw' )";
2393     r = run_query(hdb1, 0, query);
2394     ok(r == ERROR_SUCCESS, "failed to add row 1\n");
2395
2396     query = "INSERT INTO `AAR` ( `BAR`, `CAR` ) VALUES ( 2, 'bmw' )";
2397     r = run_query(hdb1, 0, query);
2398     ok(r == ERROR_SUCCESS, "failed to add row 2\n");
2399
2400     query = "UPDATE `MOO` SET `OOO` = 'c' WHERE `NOO` = 1";
2401     r = run_query(hdb1, 0, query);
2402     ok(r == ERROR_SUCCESS, "failed to modify row\n");
2403
2404     query = "DELETE FROM `MOO` WHERE `NOO` = 3";
2405     r = run_query(hdb1, 0, query);
2406     ok(r == ERROR_SUCCESS, "failed to delete row\n");
2407
2408     hrec = MsiCreateRecord(2);
2409     r = MsiRecordSetInteger(hrec, 1, 1);
2410     ok(r == ERROR_SUCCESS, "failed to set integer\n");
2411
2412     write_file("testdata.bin", "naengmyon", 9);
2413     r = MsiRecordSetStream(hrec, 2, "testdata.bin");
2414     ok(r == ERROR_SUCCESS, "failed to set stream\n");
2415
2416     query = "INSERT INTO `BINARY` ( `ID`, `BLOB` ) VALUES ( ?, ? )";
2417     r = run_query(hdb1, hrec, query);
2418     ok(r == ERROR_SUCCESS, "failed to add row with blob\n");
2419
2420     MsiCloseHandle(hrec);
2421
2422     query = "ALTER TABLE `MOO` ADD `COW` INTEGER";
2423     r = run_query(hdb1, 0, query);
2424     ok(r == ERROR_SUCCESS, "failed to add column\n");
2425
2426     query = "ALTER TABLE `MOO` ADD `PIG` INTEGER";
2427     r = run_query(hdb1, 0, query);
2428     ok(r == ERROR_SUCCESS, "failed to add column\n");
2429
2430     query = "UPDATE `MOO` SET `PIG` = 5 WHERE `NOO` = 1";
2431     r = run_query(hdb1, 0, query);
2432     ok(r == ERROR_SUCCESS, "failed to modify row\n");
2433
2434     query = "CREATE TABLE `Property` ( `Property` CHAR(72) NOT NULL, "
2435             "`Value` CHAR(0) PRIMARY KEY `Property`)";
2436     r = run_query(hdb1, 0, query);
2437     ok(r == ERROR_SUCCESS, "failed to add property table\n");
2438
2439     query = "INSERT INTO `Property` ( `Property`, `Value` ) VALUES ( 'prop', 'val' )";
2440     r = run_query(hdb1, 0, query);
2441     ok(r == ERROR_SUCCESS, "failed to add property\n");
2442
2443     /* database needs to be committed */
2444     MsiDatabaseCommit(hdb1);
2445
2446     r = MsiDatabaseGenerateTransform(hdb1, hdb2, mstfile, 0, 0);
2447     ok( r == ERROR_SUCCESS, "return code %d, should be ERROR_SUCCESS\n", r );
2448
2449     MsiCloseHandle( hdb1 );
2450     MsiCloseHandle( hdb2 );
2451
2452     DeleteFile("testdata.bin");
2453 }
2454
2455 /* data for generating a transform */
2456
2457 /* tables transform names - encoded as they would be in an msi database file */
2458 static const WCHAR name1[] = { 0x4840, 0x3a8a, 0x481b, 0 }; /* AAR */
2459 static const WCHAR name2[] = { 0x4840, 0x3b3f, 0x43f2, 0x4438, 0x45b1, 0 }; /* _Columns */
2460 static const WCHAR name3[] = { 0x4840, 0x3f7f, 0x4164, 0x422f, 0x4836, 0 }; /* _Tables */
2461 static const WCHAR name4[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0 }; /* _StringData */
2462 static const WCHAR name5[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0 }; /* _StringPool */
2463 static const WCHAR name6[] = { 0x4840, 0x3e16, 0x4818, 0}; /* MOO */
2464 static const WCHAR name7[] = { 0x4840, 0x3c8b, 0x3a97, 0x409b, 0 }; /* BINARY */
2465 static const WCHAR name8[] = { 0x3c8b, 0x3a97, 0x409b, 0x387e, 0 }; /* BINARY.1 */
2466 static const WCHAR name9[] = { 0x4840, 0x4559, 0x44f2, 0x4568, 0x4737, 0 }; /* Property */
2467
2468 /* data in each table */
2469 static const WCHAR data1[] = { /* AAR */
2470     0x0201, 0x0008, 0x8001,  /* 0x0201 = add row (1), two shorts */
2471     0x0201, 0x0009, 0x8002,
2472 };
2473 static const WCHAR data2[] = { /* _Columns */
2474     0x0401, 0x0001, 0x8003, 0x0002, 0x9502,
2475     0x0401, 0x0001, 0x8004, 0x0003, 0x9502,
2476     0x0401, 0x0005, 0x0000, 0x0006, 0xbdff,  /* 0x0401 = add row (1), 4 shorts */
2477     0x0401, 0x0005, 0x0000, 0x0007, 0x8502,
2478     0x0401, 0x000a, 0x0000, 0x000a, 0xad48,
2479     0x0401, 0x000a, 0x0000, 0x000b, 0x9d00,
2480 };
2481 static const WCHAR data3[] = { /* _Tables */
2482     0x0101, 0x0005, /* 0x0101 = add row (1), 1 short */
2483     0x0101, 0x000a,
2484 };
2485 static const char data4[] = /* _StringData */
2486     "MOOCOWPIGcAARCARBARvwbmwPropertyValuepropval";  /* all the strings squashed together */
2487 static const WCHAR data5[] = { /* _StringPool */
2488 /*  len, refs */
2489     0,   0,    /* string 0 ''    */
2490     3,   2,    /* string 1 'MOO' */
2491     3,   1,    /* string 2 'COW' */
2492     3,   1,    /* string 3 'PIG' */
2493     1,   1,    /* string 4 'c'   */
2494     3,   3,    /* string 5 'AAR' */
2495     3,   1,    /* string 6 'CAR' */
2496     3,   1,    /* string 7 'BAR' */
2497     2,   1,    /* string 8 'vw'  */
2498     3,   1,    /* string 9 'bmw' */
2499     8,   4,    /* string 10 'Property' */
2500     5,   1,    /* string 11 'Value' */
2501     4,   1,    /* string 12 'prop' */
2502     3,   1,    /* string 13 'val' */
2503 };
2504 /* update row, 0x0002 is a bitmask of present column data, keys are excluded */
2505 static const WCHAR data6[] = { /* MOO */
2506     0x000a, 0x8001, 0x0004, 0x8005, /* update row */
2507     0x0000, 0x8003,         /* delete row */
2508 };
2509
2510 static const WCHAR data7[] = { /* BINARY */
2511     0x0201, 0x8001, 0x0001,
2512 };
2513
2514 static const char data8[] =  /* stream data for the BINARY table */
2515     "naengmyon";
2516
2517 static const WCHAR data9[] = { /* Property */
2518     0x0201, 0x000c, 0x000d,
2519 };
2520
2521 static const struct {
2522     LPCWSTR name;
2523     const void *data;
2524     DWORD size;
2525 } table_transform_data[] =
2526 {
2527     { name1, data1, sizeof data1 },
2528     { name2, data2, sizeof data2 },
2529     { name3, data3, sizeof data3 },
2530     { name4, data4, sizeof data4 - 1 },
2531     { name5, data5, sizeof data5 },
2532     { name6, data6, sizeof data6 },
2533     { name7, data7, sizeof data7 },
2534     { name8, data8, sizeof data8 - 1 },
2535     { name9, data9, sizeof data9 },
2536 };
2537
2538 #define NUM_TRANSFORM_TABLES (sizeof table_transform_data/sizeof table_transform_data[0])
2539
2540 static void generate_transform_manual(void)
2541 {
2542     IStorage *stg = NULL;
2543     IStream *stm;
2544     WCHAR name[0x20];
2545     HRESULT r;
2546     DWORD i, count;
2547     const DWORD mode = STGM_CREATE|STGM_READWRITE|STGM_DIRECT|STGM_SHARE_EXCLUSIVE;
2548
2549     const CLSID CLSID_MsiTransform = { 0xc1082,0,0,{0xc0,0,0,0,0,0,0,0x46}};
2550
2551     MultiByteToWideChar(CP_ACP, 0, mstfile, -1, name, 0x20);
2552
2553     r = StgCreateDocfile(name, mode, 0, &stg);
2554     ok(r == S_OK, "failed to create storage\n");
2555     if (!stg)
2556         return;
2557
2558     r = IStorage_SetClass( stg, &CLSID_MsiTransform );
2559     ok(r == S_OK, "failed to set storage type\n");
2560
2561     for (i=0; i<NUM_TRANSFORM_TABLES; i++)
2562     {
2563         r = IStorage_CreateStream( stg, table_transform_data[i].name,
2564                             STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stm );
2565         if (FAILED(r))
2566         {
2567             ok(0, "failed to create stream %08x\n", r);
2568             continue;
2569         }
2570
2571         r = IStream_Write( stm, table_transform_data[i].data,
2572                           table_transform_data[i].size, &count );
2573         if (FAILED(r) || count != table_transform_data[i].size)
2574             ok(0, "failed to write stream\n");
2575         IStream_Release(stm);
2576     }
2577
2578     IStorage_Release(stg);
2579 }
2580
2581 static UINT set_summary_info(MSIHANDLE hdb)
2582 {
2583     UINT res;
2584     MSIHANDLE suminfo;
2585
2586     /* build summary info */
2587     res = MsiGetSummaryInformation(hdb, NULL, 7, &suminfo);
2588     ok( res == ERROR_SUCCESS , "Failed to open summaryinfo\n" );
2589
2590     res = MsiSummaryInfoSetProperty(suminfo,2, VT_LPSTR, 0,NULL,
2591                         "Installation Database");
2592     ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
2593
2594     res = MsiSummaryInfoSetProperty(suminfo,3, VT_LPSTR, 0,NULL,
2595                         "Installation Database");
2596     ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
2597
2598     res = MsiSummaryInfoSetProperty(suminfo,4, VT_LPSTR, 0,NULL,
2599                         "Wine Hackers");
2600     ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
2601
2602     res = MsiSummaryInfoSetProperty(suminfo,7, VT_LPSTR, 0,NULL,
2603                     ";1033");
2604     ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
2605
2606     res = MsiSummaryInfoSetProperty(suminfo,9, VT_LPSTR, 0,NULL,
2607                     "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}");
2608     ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
2609
2610     res = MsiSummaryInfoSetProperty(suminfo, 14, VT_I4, 100, NULL, NULL);
2611     ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
2612
2613     res = MsiSummaryInfoSetProperty(suminfo, 15, VT_I4, 0, NULL, NULL);
2614     ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
2615
2616     res = MsiSummaryInfoPersist(suminfo);
2617     ok( res == ERROR_SUCCESS , "Failed to make summary info persist\n" );
2618
2619     res = MsiCloseHandle( suminfo);
2620     ok( res == ERROR_SUCCESS , "Failed to close suminfo\n" );
2621
2622     return res;
2623 }
2624
2625 static MSIHANDLE create_package_db(LPCSTR filename)
2626 {
2627     MSIHANDLE hdb = 0;
2628     UINT res;
2629
2630     DeleteFile(msifile);
2631
2632     /* create an empty database */
2633     res = MsiOpenDatabase(filename, MSIDBOPEN_CREATE, &hdb );
2634     ok( res == ERROR_SUCCESS , "Failed to create database\n" );
2635     if( res != ERROR_SUCCESS )
2636         return hdb;
2637
2638     res = MsiDatabaseCommit( hdb );
2639     ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
2640
2641     res = set_summary_info(hdb);
2642
2643     res = create_directory_table(hdb);
2644     ok( res == ERROR_SUCCESS , "Failed to create directory table\n" );
2645
2646     return hdb;
2647 }
2648
2649 static MSIHANDLE package_from_db(MSIHANDLE hdb)
2650 {
2651     UINT res;
2652     CHAR szPackage[10];
2653     MSIHANDLE hPackage;
2654
2655     sprintf(szPackage,"#%i",hdb);
2656     res = MsiOpenPackage(szPackage,&hPackage);
2657     if (res != ERROR_SUCCESS)
2658         return 0;
2659
2660     res = MsiCloseHandle(hdb);
2661     if (res != ERROR_SUCCESS)
2662         return 0;
2663
2664     return hPackage;
2665 }
2666
2667 static void test_try_transform(void)
2668 {
2669     MSIHANDLE hdb, hview, hrec, hpkg;
2670     LPCSTR query;
2671     UINT r;
2672     DWORD sz;
2673     char buffer[MAX_PATH];
2674
2675     DeleteFile(msifile);
2676     DeleteFile(mstfile);
2677
2678     /* create the database */
2679     hdb = create_package_db(msifile);
2680     ok(hdb, "Failed to create package db\n");
2681
2682     query = "CREATE TABLE `MOO` ( `NOO` SHORT NOT NULL, `OOO` CHAR(255) PRIMARY KEY `NOO`)";
2683     r = run_query(hdb, 0, query);
2684     ok(r == ERROR_SUCCESS, "failed to add table\n");
2685
2686     query = "INSERT INTO `MOO` ( `NOO`, `OOO` ) VALUES ( 1, 'a' )";
2687     r = run_query(hdb, 0, query);
2688     ok(r == ERROR_SUCCESS, "failed to add row\n");
2689
2690     query = "INSERT INTO `MOO` ( `NOO`, `OOO` ) VALUES ( 2, 'b' )";
2691     r = run_query(hdb, 0, query);
2692     ok(r == ERROR_SUCCESS, "failed to add row\n");
2693
2694     query = "INSERT INTO `MOO` ( `NOO`, `OOO` ) VALUES ( 3, 'c' )";
2695     r = run_query(hdb, 0, query);
2696     ok(r == ERROR_SUCCESS, "failed to add row\n");
2697
2698     query = "CREATE TABLE `BINARY` ( `ID` SHORT NOT NULL, `BLOB` OBJECT PRIMARY KEY `ID`)";
2699     r = run_query(hdb, 0, query);
2700     ok(r == ERROR_SUCCESS, "failed to add table\n");
2701
2702     hrec = MsiCreateRecord(2);
2703     r = MsiRecordSetInteger(hrec, 1, 2);
2704     ok(r == ERROR_SUCCESS, "failed to set integer\n");
2705
2706     write_file("testdata.bin", "lamyon", 6);
2707     r = MsiRecordSetStream(hrec, 2, "testdata.bin");
2708     ok(r == ERROR_SUCCESS, "failed to set stream\n");
2709
2710     query = "INSERT INTO `BINARY` ( `ID`, `BLOB` ) VALUES ( ?, ? )";
2711     r = run_query(hdb, hrec, query);
2712     ok(r == ERROR_SUCCESS, "failed to add row with blob\n");
2713
2714     MsiCloseHandle(hrec);
2715
2716     r = MsiDatabaseCommit( hdb );
2717     ok( r == ERROR_SUCCESS , "Failed to commit database\n" );
2718
2719     MsiCloseHandle( hdb );
2720     DeleteFileA("testdata.bin");
2721
2722     /*
2723      * Both these generate an equivalent transform,
2724      *  but the first doesn't work in Wine yet
2725      *  because MsiDatabaseGenerateTransform is unimplemented.
2726      */
2727     if (0)
2728         generate_transform();
2729     else
2730         generate_transform_manual();
2731
2732     r = MsiOpenDatabase(msifile, MSIDBOPEN_DIRECT, &hdb );
2733     ok( r == ERROR_SUCCESS , "Failed to create database\n" );
2734
2735     r = MsiDatabaseApplyTransform( hdb, mstfile, 0 );
2736     ok( r == ERROR_SUCCESS, "return code %d, should be ERROR_SUCCESS\n", r );
2737
2738     MsiDatabaseCommit( hdb );
2739
2740     /* check new values */
2741     hrec = 0;
2742     query = "select `BAR`,`CAR` from `AAR` where `BAR` = 1 AND `CAR` = 'vw'";
2743     r = do_query(hdb, query, &hrec);
2744     ok(r == ERROR_SUCCESS, "select query failed\n");
2745     MsiCloseHandle(hrec);
2746
2747     query = "select `BAR`,`CAR` from `AAR` where `BAR` = 2 AND `CAR` = 'bmw'";
2748     hrec = 0;
2749     r = do_query(hdb, query, &hrec);
2750     ok(r == ERROR_SUCCESS, "select query failed\n");
2751     MsiCloseHandle(hrec);
2752
2753     /* check updated values */
2754     hrec = 0;
2755     query = "select `NOO`,`OOO` from `MOO` where `NOO` = 1 AND `OOO` = 'c'";
2756     r = do_query(hdb, query, &hrec);
2757     ok(r == ERROR_SUCCESS, "select query failed\n");
2758     MsiCloseHandle(hrec);
2759
2760     /* check unchanged value */
2761     hrec = 0;
2762     query = "select `NOO`,`OOO` from `MOO` where `NOO` = 2 AND `OOO` = 'b'";
2763     r = do_query(hdb, query, &hrec);
2764     ok(r == ERROR_SUCCESS, "select query failed\n");
2765     MsiCloseHandle(hrec);
2766
2767     /* check deleted value */
2768     hrec = 0;
2769     query = "select * from `MOO` where `NOO` = 3";
2770     r = do_query(hdb, query, &hrec);
2771     ok(r == ERROR_NO_MORE_ITEMS, "select query failed\n");
2772     if (hrec) MsiCloseHandle(hrec);
2773
2774     /* check added stream */
2775     hrec = 0;
2776     query = "select `BLOB` from `BINARY` where `ID` = 1";
2777     r = do_query(hdb, query, &hrec);
2778     ok(r == ERROR_SUCCESS, "select query failed\n");
2779
2780     /* check the contents of the stream */
2781     sz = sizeof buffer;
2782     r = MsiRecordReadStream( hrec, 1, buffer, &sz );
2783     ok(r == ERROR_SUCCESS, "read stream failed\n");
2784     ok(!memcmp(buffer, "naengmyon", 9), "stream data was wrong\n");
2785     ok(sz == 9, "stream data was wrong size\n");
2786     if (hrec) MsiCloseHandle(hrec);
2787
2788     /* check the validity of the table with a deleted row */
2789     hrec = 0;
2790     query = "select * from `MOO`";
2791     r = MsiDatabaseOpenView(hdb, query, &hview);
2792     ok(r == ERROR_SUCCESS, "open view failed\n");
2793
2794     r = MsiViewExecute(hview, 0);
2795     ok(r == ERROR_SUCCESS, "view execute failed\n");
2796
2797     r = MsiViewFetch(hview, &hrec);
2798     ok(r == ERROR_SUCCESS, "view fetch failed\n");
2799
2800     r = MsiRecordGetInteger(hrec, 1);
2801     ok(r == 1, "Expected 1, got %d\n", r);
2802
2803     sz = sizeof buffer;
2804     r = MsiRecordGetString(hrec, 2, buffer, &sz);
2805     ok(r == ERROR_SUCCESS, "record get string failed\n");
2806     ok(!lstrcmpA(buffer, "c"), "Expected c, got %s\n", buffer);
2807
2808     r = MsiRecordGetInteger(hrec, 3);
2809     ok(r == 0x80000000, "Expected 0x80000000, got %d\n", r);
2810
2811     r = MsiRecordGetInteger(hrec, 4);
2812     ok(r == 5, "Expected 5, got %d\n", r);
2813
2814     MsiCloseHandle(hrec);
2815
2816     r = MsiViewFetch(hview, &hrec);
2817     ok(r == ERROR_SUCCESS, "view fetch failed\n");
2818
2819     r = MsiRecordGetInteger(hrec, 1);
2820     ok(r == 2, "Expected 2, got %d\n", r);
2821
2822     sz = sizeof buffer;
2823     r = MsiRecordGetString(hrec, 2, buffer, &sz);
2824     ok(r == ERROR_SUCCESS, "record get string failed\n");
2825     ok(!lstrcmpA(buffer, "b"), "Expected b, got %s\n", buffer);
2826
2827     r = MsiRecordGetInteger(hrec, 3);
2828     ok(r == 0x80000000, "Expected 0x80000000, got %d\n", r);
2829
2830     r = MsiRecordGetInteger(hrec, 4);
2831     ok(r == 0x80000000, "Expected 0x80000000, got %d\n", r);
2832
2833     MsiCloseHandle(hrec);
2834
2835     r = MsiViewFetch(hview, &hrec);
2836     ok(r == ERROR_NO_MORE_ITEMS, "view fetch succeeded\n");
2837
2838     MsiCloseHandle(hrec);
2839     MsiViewClose(hview);
2840     MsiCloseHandle(hview);
2841
2842     /* check that the property was added */
2843     hpkg = package_from_db(hdb);
2844     ok(hpkg != 0, "Expected non-NULL hpkg\n");
2845
2846     sz = MAX_PATH;
2847     r = MsiGetProperty(hpkg, "prop", buffer, &sz);
2848     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2849     ok(!lstrcmp(buffer, "val"), "Expected val, got %s\n", buffer);
2850
2851     MsiCloseHandle(hpkg);
2852     MsiCloseHandle(hdb);
2853
2854     DeleteFile(msifile);
2855     DeleteFile(mstfile);
2856 }
2857
2858 struct join_res
2859 {
2860     const CHAR one[MAX_PATH];
2861     const CHAR two[MAX_PATH];
2862 };
2863
2864 struct join_res_4col
2865 {
2866     const CHAR one[MAX_PATH];
2867     const CHAR two[MAX_PATH];
2868     const CHAR three[MAX_PATH];
2869     const CHAR four[MAX_PATH];
2870 };
2871
2872 struct join_res_uint
2873 {
2874     UINT one;
2875     UINT two;
2876     UINT three;
2877     UINT four;
2878     UINT five;
2879     UINT six;
2880 };
2881
2882 static const struct join_res join_res_first[] =
2883 {
2884     { "alveolar", "procerus" },
2885     { "septum", "procerus" },
2886     { "septum", "nasalis" },
2887     { "ramus", "nasalis" },
2888     { "malar", "mentalis" },
2889 };
2890
2891 static const struct join_res join_res_second[] =
2892 {
2893     { "nasal", "septum" },
2894     { "mandible", "ramus" },
2895 };
2896
2897 static const struct join_res join_res_third[] =
2898 {
2899     { "msvcp.dll", "abcdefgh" },
2900     { "msvcr.dll", "ijklmnop" },
2901 };
2902
2903 static const struct join_res join_res_fourth[] =
2904 {
2905     { "msvcp.dll.01234", "single.dll.31415" },
2906 };
2907
2908 static const struct join_res join_res_fifth[] =
2909 {
2910     { "malar", "procerus" },
2911 };
2912
2913 static const struct join_res join_res_sixth[] =
2914 {
2915     { "malar", "procerus" },
2916     { "malar", "procerus" },
2917     { "malar", "nasalis" },
2918     { "malar", "nasalis" },
2919     { "malar", "nasalis" },
2920     { "malar", "mentalis" },
2921 };
2922
2923 static const struct join_res join_res_seventh[] =
2924 {
2925     { "malar", "nasalis" },
2926     { "malar", "nasalis" },
2927     { "malar", "nasalis" },
2928 };
2929
2930 static const struct join_res_4col join_res_eighth[] =
2931 {
2932     { "msvcp.dll", "msvcp.dll.01234", "msvcp.dll.01234", "abcdefgh" },
2933     { "msvcr.dll", "msvcr.dll.56789", "msvcp.dll.01234", "abcdefgh" },
2934     { "msvcp.dll", "msvcp.dll.01234", "msvcr.dll.56789", "ijklmnop" },
2935     { "msvcr.dll", "msvcr.dll.56789", "msvcr.dll.56789", "ijklmnop" },
2936     { "msvcp.dll", "msvcp.dll.01234", "single.dll.31415", "msvcp.dll" },
2937     { "msvcr.dll", "msvcr.dll.56789", "single.dll.31415", "msvcp.dll" },
2938 };
2939
2940 static const struct join_res_uint join_res_ninth[] =
2941 {
2942     { 1, 2, 3, 4, 7, 8 },
2943     { 1, 2, 5, 6, 7, 8 },
2944     { 1, 2, 3, 4, 9, 10 },
2945     { 1, 2, 5, 6, 9, 10 },
2946     { 1, 2, 3, 4, 11, 12 },
2947     { 1, 2, 5, 6, 11, 12 },
2948 };
2949
2950 static void test_join(void)
2951 {
2952     MSIHANDLE hdb, hview, hrec;
2953     LPCSTR query;
2954     CHAR buf[MAX_PATH];
2955     UINT r, count;
2956     DWORD size, i;
2957     BOOL data_correct;
2958
2959     hdb = create_db();
2960     ok( hdb, "failed to create db\n");
2961
2962     r = create_component_table( hdb );
2963     ok( r == ERROR_SUCCESS, "cannot create Component table: %d\n", r );
2964
2965     r = add_component_entry( hdb, "'zygomatic', 'malar', 'INSTALLDIR', 0, '', ''" );
2966     ok( r == ERROR_SUCCESS, "cannot add component: %d\n", r );
2967
2968     r = add_component_entry( hdb, "'maxilla', 'alveolar', 'INSTALLDIR', 0, '', ''" );
2969     ok( r == ERROR_SUCCESS, "cannot add component: %d\n", r );
2970
2971     r = add_component_entry( hdb, "'nasal', 'septum', 'INSTALLDIR', 0, '', ''" );
2972     ok( r == ERROR_SUCCESS, "cannot add component: %d\n", r );
2973
2974     r = add_component_entry( hdb, "'mandible', 'ramus', 'INSTALLDIR', 0, '', ''" );
2975     ok( r == ERROR_SUCCESS, "cannot add component: %d\n", r );
2976
2977     r = create_feature_components_table( hdb );
2978     ok( r == ERROR_SUCCESS, "cannot create FeatureComponents table: %d\n", r );
2979
2980     r = add_feature_components_entry( hdb, "'procerus', 'maxilla'" );
2981     ok( r == ERROR_SUCCESS, "cannot add feature components: %d\n", r );
2982
2983     r = add_feature_components_entry( hdb, "'procerus', 'nasal'" );
2984     ok( r == ERROR_SUCCESS, "cannot add feature components: %d\n", r );
2985
2986     r = add_feature_components_entry( hdb, "'nasalis', 'nasal'" );
2987     ok( r == ERROR_SUCCESS, "cannot add feature components: %d\n", r );
2988
2989     r = add_feature_components_entry( hdb, "'nasalis', 'mandible'" );
2990     ok( r == ERROR_SUCCESS, "cannot add feature components: %d\n", r );
2991
2992     r = add_feature_components_entry( hdb, "'nasalis', 'notacomponent'" );
2993     ok( r == ERROR_SUCCESS, "cannot add feature components: %d\n", r );
2994
2995     r = add_feature_components_entry( hdb, "'mentalis', 'zygomatic'" );
2996     ok( r == ERROR_SUCCESS, "cannot add feature components: %d\n", r );
2997
2998     r = create_std_dlls_table( hdb );
2999     ok( r == ERROR_SUCCESS, "cannot create StdDlls table: %d\n", r );
3000
3001     r = add_std_dlls_entry( hdb, "'msvcp.dll', 'msvcp.dll.01234'" );
3002     ok( r == ERROR_SUCCESS, "cannot add std dlls: %d\n", r );
3003
3004     r = add_std_dlls_entry( hdb, "'msvcr.dll', 'msvcr.dll.56789'" );
3005     ok( r == ERROR_SUCCESS, "cannot add std dlls: %d\n", r );
3006
3007     r = create_binary_table( hdb );
3008     ok( r == ERROR_SUCCESS, "cannot create Binary table: %d\n", r );
3009
3010     r = add_binary_entry( hdb, "'msvcp.dll.01234', 'abcdefgh'" );
3011     ok( r == ERROR_SUCCESS, "cannot add binary: %d\n", r );
3012
3013     r = add_binary_entry( hdb, "'msvcr.dll.56789', 'ijklmnop'" );
3014     ok( r == ERROR_SUCCESS, "cannot add binary: %d\n", r );
3015
3016     r = add_binary_entry( hdb, "'single.dll.31415', 'msvcp.dll'" );
3017     ok( r == ERROR_SUCCESS, "cannot add binary: %d\n", r );
3018
3019     query = "CREATE TABLE `One` (`A` SHORT, `B` SHORT PRIMARY KEY `A`)";
3020     r = run_query( hdb, 0, query);
3021     ok(r == ERROR_SUCCESS, "cannot create table: %d\n", r );
3022
3023     query = "CREATE TABLE `Two` (`C` SHORT, `D` SHORT PRIMARY KEY `C`)";
3024     r = run_query( hdb, 0, query);
3025     ok(r == ERROR_SUCCESS, "cannot create table: %d\n", r );
3026
3027     query = "CREATE TABLE `Three` (`E` SHORT, `F` SHORT PRIMARY KEY `E`)";
3028     r = run_query( hdb, 0, query);
3029     ok(r == ERROR_SUCCESS, "cannot create table: %d\n", r );
3030
3031     query = "INSERT INTO `One` (`A`, `B`) VALUES (1, 2)";
3032     r = run_query( hdb, 0, query);
3033     ok(r == ERROR_SUCCESS, "cannot insert into table: %d\n", r );
3034
3035     query = "INSERT INTO `Two` (`C`, `D`) VALUES (3, 4)";
3036     r = run_query( hdb, 0, query);
3037     ok(r == ERROR_SUCCESS, "cannot insert into table: %d\n", r );
3038
3039     query = "INSERT INTO `Two` (`C`, `D`) VALUES (5, 6)";
3040     r = run_query( hdb, 0, query);
3041     ok(r == ERROR_SUCCESS, "cannot insert into table: %d\n", r );
3042
3043     query = "INSERT INTO `Three` (`E`, `F`) VALUES (7, 8)";
3044     r = run_query( hdb, 0, query);
3045     ok(r == ERROR_SUCCESS, "cannot insert into table: %d\n", r );
3046
3047     query = "INSERT INTO `Three` (`E`, `F`) VALUES (9, 10)";
3048     r = run_query( hdb, 0, query);
3049     ok(r == ERROR_SUCCESS, "cannot insert into table: %d\n", r );
3050
3051     query = "INSERT INTO `Three` (`E`, `F`) VALUES (11, 12)";
3052     r = run_query( hdb, 0, query);
3053     ok(r == ERROR_SUCCESS, "cannot insert into table: %d\n", r );
3054
3055     query = "CREATE TABLE `Four` (`G` SHORT, `H` SHORT PRIMARY KEY `G`)";
3056     r = run_query( hdb, 0, query);
3057     ok(r == ERROR_SUCCESS, "cannot create table: %d\n", r );
3058
3059     query = "CREATE TABLE `Five` (`I` SHORT, `J` SHORT PRIMARY KEY `I`)";
3060     r = run_query( hdb, 0, query);
3061     ok(r == ERROR_SUCCESS, "cannot create table: %d\n", r );
3062
3063     query = "INSERT INTO `Five` (`I`, `J`) VALUES (13, 14)";
3064     r = run_query( hdb, 0, query);
3065     ok(r == ERROR_SUCCESS, "cannot insert into table: %d\n", r );
3066
3067     query = "INSERT INTO `Five` (`I`, `J`) VALUES (15, 16)";
3068     r = run_query( hdb, 0, query);
3069     ok(r == ERROR_SUCCESS, "cannot insert into table: %d\n", r );
3070
3071     query = "SELECT `Component`.`ComponentId`, `FeatureComponents`.`Feature_` "
3072             "FROM `Component`, `FeatureComponents` "
3073             "WHERE `Component`.`Component` = `FeatureComponents`.`Component_` "
3074             "ORDER BY `Feature_`";
3075     r = MsiDatabaseOpenView(hdb, query, &hview);
3076     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3077
3078     r = MsiViewExecute(hview, 0);
3079     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3080
3081     i = 0;
3082     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3083     {
3084         count = MsiRecordGetFieldCount( hrec );
3085         ok( count == 2, "Expected 2 record fields, got %d\n", count );
3086
3087         size = MAX_PATH;
3088         r = MsiRecordGetString( hrec, 1, buf, &size );
3089         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3090         ok( !lstrcmp( buf, join_res_first[i].one ),
3091             "For (row %d, column 1) expected '%s', got %s\n", i, join_res_first[i].one, buf );
3092
3093         size = MAX_PATH;
3094         r = MsiRecordGetString( hrec, 2, buf, &size );
3095         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3096         ok( !lstrcmp( buf, join_res_first[i].two ),
3097             "For (row %d, column 2) expected '%s', got %s\n", i, join_res_first[i].two, buf );
3098
3099         i++;
3100         MsiCloseHandle(hrec);
3101     }
3102
3103     ok( i == 5, "Expected 5 rows, got %d\n", i );
3104     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3105
3106     MsiViewClose(hview);
3107     MsiCloseHandle(hview);
3108
3109     /* try a join without a WHERE condition */
3110     query = "SELECT `Component`.`ComponentId`, `FeatureComponents`.`Feature_` "
3111             "FROM `Component`, `FeatureComponents` ";
3112     r = MsiDatabaseOpenView(hdb, query, &hview);
3113     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3114
3115     r = MsiViewExecute(hview, 0);
3116     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3117
3118     i = 0;
3119     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3120     {
3121         i++;
3122         MsiCloseHandle(hrec);
3123     }
3124     ok( i == 24, "Expected 24 rows, got %d\n", i );
3125
3126     MsiViewClose(hview);
3127     MsiCloseHandle(hview);
3128
3129     query = "SELECT DISTINCT Component, ComponentId FROM FeatureComponents, Component "
3130             "WHERE FeatureComponents.Component_=Component.Component "
3131             "AND (Feature_='nasalis') ORDER BY Feature_";
3132     r = MsiDatabaseOpenView(hdb, query, &hview);
3133     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3134
3135     r = MsiViewExecute(hview, 0);
3136     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3137
3138     i = 0;
3139     data_correct = TRUE;
3140     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3141     {
3142         count = MsiRecordGetFieldCount( hrec );
3143         ok( count == 2, "Expected 2 record fields, got %d\n", count );
3144
3145         size = MAX_PATH;
3146         r = MsiRecordGetString( hrec, 1, buf, &size );
3147         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3148         if( lstrcmp( buf, join_res_second[i].one ))
3149             data_correct = FALSE;
3150
3151         size = MAX_PATH;
3152         r = MsiRecordGetString( hrec, 2, buf, &size );
3153         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3154         if( lstrcmp( buf, join_res_second[i].two ))
3155             data_correct = FALSE;
3156
3157         i++;
3158         MsiCloseHandle(hrec);
3159     }
3160
3161     ok( data_correct, "data returned in the wrong order\n");
3162
3163     ok( i == 2, "Expected 2 rows, got %d\n", i );
3164     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3165
3166     MsiViewClose(hview);
3167     MsiCloseHandle(hview);
3168
3169     query = "SELECT `StdDlls`.`File`, `Binary`.`Data` "
3170             "FROM `StdDlls`, `Binary` "
3171             "WHERE `StdDlls`.`Binary_` = `Binary`.`Name` "
3172             "ORDER BY `File`";
3173     r = MsiDatabaseOpenView(hdb, query, &hview);
3174     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3175
3176     r = MsiViewExecute(hview, 0);
3177     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3178
3179     i = 0;
3180     data_correct = TRUE;
3181     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3182     {
3183         count = MsiRecordGetFieldCount( hrec );
3184         ok( count == 2, "Expected 2 record fields, got %d\n", count );
3185
3186         size = MAX_PATH;
3187         r = MsiRecordGetString( hrec, 1, buf, &size );
3188         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3189         if( lstrcmp( buf, join_res_third[i].one ) )
3190             data_correct = FALSE;
3191
3192         size = MAX_PATH;
3193         r = MsiRecordGetString( hrec, 2, buf, &size );
3194         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3195         if( lstrcmp( buf, join_res_third[i].two ) )
3196             data_correct = FALSE;
3197
3198         i++;
3199         MsiCloseHandle(hrec);
3200     }
3201     ok( data_correct, "data returned in the wrong order\n");
3202
3203     ok( i == 2, "Expected 2 rows, got %d\n", i );
3204
3205     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3206
3207     MsiViewClose(hview);
3208     MsiCloseHandle(hview);
3209
3210     query = "SELECT `StdDlls`.`Binary_`, `Binary`.`Name` "
3211             "FROM `StdDlls`, `Binary` "
3212             "WHERE `StdDlls`.`File` = `Binary`.`Data` "
3213             "ORDER BY `Name`";
3214     r = MsiDatabaseOpenView(hdb, query, &hview);
3215     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3216
3217     r = MsiViewExecute(hview, 0);
3218     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3219
3220     i = 0;
3221     data_correct = TRUE;
3222     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3223     {
3224         count = MsiRecordGetFieldCount( hrec );
3225         ok( count == 2, "Expected 2 record fields, got %d\n", count );
3226
3227         size = MAX_PATH;
3228         r = MsiRecordGetString( hrec, 1, buf, &size );
3229         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3230         if( lstrcmp( buf, join_res_fourth[i].one ))
3231             data_correct = FALSE;
3232
3233         size = MAX_PATH;
3234         r = MsiRecordGetString( hrec, 2, buf, &size );
3235         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3236         if( lstrcmp( buf, join_res_fourth[i].two ))
3237             data_correct = FALSE;
3238
3239         i++;
3240         MsiCloseHandle(hrec);
3241     }
3242     ok( data_correct, "data returned in the wrong order\n");
3243
3244     ok( i == 1, "Expected 1 rows, got %d\n", i );
3245     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3246
3247     MsiViewClose(hview);
3248     MsiCloseHandle(hview);
3249
3250     query = "SELECT `Component`.`ComponentId`, `FeatureComponents`.`Feature_` "
3251             "FROM `Component`, `FeatureComponents` "
3252             "WHERE `Component`.`Component` = 'zygomatic' "
3253             "AND `FeatureComponents`.`Component_` = 'maxilla' "
3254             "ORDER BY `Feature_`";
3255     r = MsiDatabaseOpenView(hdb, query, &hview);
3256     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3257
3258     r = MsiViewExecute(hview, 0);
3259     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3260
3261     i = 0;
3262     data_correct = TRUE;
3263     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3264     {
3265         count = MsiRecordGetFieldCount( hrec );
3266         ok( count == 2, "Expected 2 record fields, got %d\n", count );
3267
3268         size = MAX_PATH;
3269         r = MsiRecordGetString( hrec, 1, buf, &size );
3270         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3271         if( lstrcmp( buf, join_res_fifth[i].one ))
3272             data_correct = FALSE;
3273
3274         size = MAX_PATH;
3275         r = MsiRecordGetString( hrec, 2, buf, &size );
3276         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3277         if( lstrcmp( buf, join_res_fifth[i].two ))
3278             data_correct = FALSE;
3279
3280         i++;
3281         MsiCloseHandle(hrec);
3282     }
3283     ok( data_correct, "data returned in the wrong order\n");
3284
3285     ok( i == 1, "Expected 1 rows, got %d\n", i );
3286     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3287
3288     MsiViewClose(hview);
3289     MsiCloseHandle(hview);
3290
3291     query = "SELECT `Component`.`ComponentId`, `FeatureComponents`.`Feature_` "
3292             "FROM `Component`, `FeatureComponents` "
3293             "WHERE `Component` = 'zygomatic' "
3294             "ORDER BY `Feature_`";
3295     r = MsiDatabaseOpenView(hdb, query, &hview);
3296     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3297
3298     r = MsiViewExecute(hview, 0);
3299     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3300
3301     i = 0;
3302     data_correct = TRUE;
3303     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3304     {
3305         count = MsiRecordGetFieldCount( hrec );
3306         ok( count == 2, "Expected 2 record fields, got %d\n", count );
3307
3308         size = MAX_PATH;
3309         r = MsiRecordGetString( hrec, 1, buf, &size );
3310         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3311         if( lstrcmp( buf, join_res_sixth[i].one ))
3312             data_correct = FALSE;
3313
3314         size = MAX_PATH;
3315         r = MsiRecordGetString( hrec, 2, buf, &size );
3316         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3317         if( lstrcmp( buf, join_res_sixth[i].two ))
3318             data_correct = FALSE;
3319
3320         i++;
3321         MsiCloseHandle(hrec);
3322     }
3323     ok( data_correct, "data returned in the wrong order\n");
3324
3325     ok( i == 6, "Expected 6 rows, got %d\n", i );
3326     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3327
3328     MsiViewClose(hview);
3329     MsiCloseHandle(hview);
3330
3331     query = "SELECT `Component`.`ComponentId`, `FeatureComponents`.`Feature_` "
3332             "FROM `Component`, `FeatureComponents` "
3333             "WHERE `Component` = 'zygomatic' "
3334             "AND `Feature_` = 'nasalis' "
3335             "ORDER BY `Feature_`";
3336     r = MsiDatabaseOpenView(hdb, query, &hview);
3337     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3338
3339     r = MsiViewExecute(hview, 0);
3340     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3341
3342     i = 0;
3343     data_correct = TRUE;
3344     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3345     {
3346         count = MsiRecordGetFieldCount( hrec );
3347         ok( count == 2, "Expected 2 record fields, got %d\n", count );
3348
3349         size = MAX_PATH;
3350         r = MsiRecordGetString( hrec, 1, buf, &size );
3351         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3352         if( lstrcmp( buf, join_res_seventh[i].one ))
3353             data_correct = FALSE;
3354
3355         size = MAX_PATH;
3356         r = MsiRecordGetString( hrec, 2, buf, &size );
3357         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3358         if( lstrcmp( buf, join_res_seventh[i].two ))
3359             data_correct = FALSE;
3360
3361         i++;
3362         MsiCloseHandle(hrec);
3363     }
3364
3365     ok( data_correct, "data returned in the wrong order\n");
3366     ok( i == 3, "Expected 3 rows, got %d\n", i );
3367     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3368
3369     MsiViewClose(hview);
3370     MsiCloseHandle(hview);
3371
3372     query = "SELECT `StdDlls`.`File`, `Binary`.`Data` "
3373             "FROM `StdDlls`, `Binary` ";
3374     r = MsiDatabaseOpenView(hdb, query, &hview);
3375     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3376
3377     r = MsiViewExecute(hview, 0);
3378     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3379
3380     i = 0;
3381     data_correct = TRUE;
3382     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3383     {
3384         count = MsiRecordGetFieldCount( hrec );
3385         ok( count == 2, "Expected 2 record fields, got %d\n", count );
3386
3387         size = MAX_PATH;
3388         r = MsiRecordGetString( hrec, 1, buf, &size );
3389         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3390         if( lstrcmp( buf, join_res_eighth[i].one ))
3391             data_correct = FALSE;
3392
3393         size = MAX_PATH;
3394         r = MsiRecordGetString( hrec, 2, buf, &size );
3395         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3396         if( lstrcmp( buf, join_res_eighth[i].four ))
3397             data_correct = FALSE;
3398
3399         i++;
3400         MsiCloseHandle(hrec);
3401     }
3402
3403     ok( data_correct, "data returned in the wrong order\n");
3404     ok( i == 6, "Expected 6 rows, got %d\n", i );
3405     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3406
3407     MsiViewClose(hview);
3408     MsiCloseHandle(hview);
3409
3410     query = "SELECT * FROM `StdDlls`, `Binary` ";
3411     r = MsiDatabaseOpenView(hdb, query, &hview);
3412     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3413
3414     r = MsiViewExecute(hview, 0);
3415     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3416
3417     i = 0;
3418     data_correct = TRUE;
3419     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3420     {
3421         count = MsiRecordGetFieldCount( hrec );
3422         ok( count == 4, "Expected 4 record fields, got %d\n", count );
3423
3424         size = MAX_PATH;
3425         r = MsiRecordGetString( hrec, 1, buf, &size );
3426         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3427         if( lstrcmp( buf, join_res_eighth[i].one ))
3428             data_correct = FALSE;
3429
3430         size = MAX_PATH;
3431         r = MsiRecordGetString( hrec, 2, buf, &size );
3432         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3433         if( lstrcmp( buf, join_res_eighth[i].two ))
3434             data_correct = FALSE;
3435
3436         size = MAX_PATH;
3437         r = MsiRecordGetString( hrec, 3, buf, &size );
3438         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3439         if( lstrcmp( buf, join_res_eighth[i].three ))
3440             data_correct = FALSE;
3441
3442         size = MAX_PATH;
3443         r = MsiRecordGetString( hrec, 4, buf, &size );
3444         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3445         if( lstrcmp( buf, join_res_eighth[i].four ))
3446             data_correct = FALSE;
3447
3448         i++;
3449         MsiCloseHandle(hrec);
3450     }
3451     ok( data_correct, "data returned in the wrong order\n");
3452
3453     ok( i == 6, "Expected 6 rows, got %d\n", i );
3454     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3455
3456     MsiViewClose(hview);
3457     MsiCloseHandle(hview);
3458
3459     query = "SELECT * FROM `One`, `Two`, `Three` ";
3460     r = MsiDatabaseOpenView(hdb, query, &hview);
3461     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3462
3463     r = MsiViewExecute(hview, 0);
3464     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3465
3466     i = 0;
3467     data_correct = TRUE;
3468     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3469     {
3470         count = MsiRecordGetFieldCount( hrec );
3471         ok( count == 6, "Expected 6 record fields, got %d\n", count );
3472
3473         r = MsiRecordGetInteger( hrec, 1 );
3474         if( r != join_res_ninth[i].one )
3475             data_correct = FALSE;
3476
3477         r = MsiRecordGetInteger( hrec, 2 );
3478         if( r != join_res_ninth[i].two )
3479             data_correct = FALSE;
3480
3481         r = MsiRecordGetInteger( hrec, 3 );
3482         if( r != join_res_ninth[i].three )
3483             data_correct = FALSE;
3484
3485         r = MsiRecordGetInteger( hrec, 4 );
3486         if( r != join_res_ninth[i].four )
3487             data_correct = FALSE;
3488
3489         r = MsiRecordGetInteger( hrec, 5 );
3490         if( r != join_res_ninth[i].five )
3491             data_correct = FALSE;
3492
3493         r = MsiRecordGetInteger( hrec, 6);
3494         if( r != join_res_ninth[i].six )
3495             data_correct = FALSE;
3496
3497         i++;
3498         MsiCloseHandle(hrec);
3499     }
3500     ok( data_correct, "data returned in the wrong order\n");
3501
3502     ok( i == 6, "Expected 6 rows, got %d\n", i );
3503     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3504
3505     MsiViewClose(hview);
3506     MsiCloseHandle(hview);
3507
3508     query = "SELECT * FROM `Four`, `Five`";
3509     r = MsiDatabaseOpenView(hdb, query, &hview);
3510     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3511
3512     r = MsiViewExecute(hview, 0);
3513     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3514
3515     r = MsiViewFetch(hview, &hrec);
3516     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
3517
3518     MsiViewClose(hview);
3519     MsiCloseHandle(hview);
3520
3521     query = "SELECT * FROM `Nonexistent`, `One`";
3522     r = MsiDatabaseOpenView(hdb, query, &hview);
3523     ok( r == ERROR_BAD_QUERY_SYNTAX,
3524         "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r );
3525
3526     MsiCloseHandle(hdb);
3527     DeleteFile(msifile);
3528 }
3529
3530 static void test_temporary_table(void)
3531 {
3532     MSICONDITION cond;
3533     MSIHANDLE hdb = 0, view = 0, rec;
3534     const char *query;
3535     UINT r;
3536     char buf[0x10];
3537     DWORD sz;
3538
3539     cond = MsiDatabaseIsTablePersistent(0, NULL);
3540     ok( cond == MSICONDITION_ERROR, "wrong return condition\n");
3541
3542     hdb = create_db();
3543     ok( hdb, "failed to create db\n");
3544
3545     cond = MsiDatabaseIsTablePersistent(hdb, NULL);
3546     ok( cond == MSICONDITION_ERROR, "wrong return condition\n");
3547
3548     cond = MsiDatabaseIsTablePersistent(hdb, "_Tables");
3549     ok( cond == MSICONDITION_NONE, "wrong return condition\n");
3550
3551     cond = MsiDatabaseIsTablePersistent(hdb, "_Columns");
3552     ok( cond == MSICONDITION_NONE, "wrong return condition\n");
3553
3554     cond = MsiDatabaseIsTablePersistent(hdb, "_Storages");
3555     ok( cond == MSICONDITION_NONE, "wrong return condition\n");
3556
3557     cond = MsiDatabaseIsTablePersistent(hdb, "_Streams");
3558     ok( cond == MSICONDITION_NONE, "wrong return condition\n");
3559
3560     query = "CREATE TABLE `P` ( `B` SHORT NOT NULL, `C` CHAR(255) PRIMARY KEY `C`)";
3561     r = run_query(hdb, 0, query);
3562     ok(r == ERROR_SUCCESS, "failed to add table\n");
3563
3564     cond = MsiDatabaseIsTablePersistent(hdb, "P");
3565     ok( cond == MSICONDITION_TRUE, "wrong return condition\n");
3566
3567     query = "CREATE TABLE `P2` ( `B` SHORT NOT NULL, `C` CHAR(255) PRIMARY KEY `C`) HOLD";
3568     r = run_query(hdb, 0, query);
3569     ok(r == ERROR_SUCCESS, "failed to add table\n");
3570
3571     cond = MsiDatabaseIsTablePersistent(hdb, "P2");
3572     ok( cond == MSICONDITION_TRUE, "wrong return condition\n");
3573
3574     query = "CREATE TABLE `T` ( `B` SHORT NOT NULL TEMPORARY, `C` CHAR(255) TEMPORARY PRIMARY KEY `C`) HOLD";
3575     r = run_query(hdb, 0, query);
3576     ok(r == ERROR_SUCCESS, "failed to add table\n");
3577
3578     cond = MsiDatabaseIsTablePersistent(hdb, "T");
3579     ok( cond == MSICONDITION_FALSE, "wrong return condition\n");
3580
3581     query = "CREATE TABLE `T2` ( `B` SHORT NOT NULL TEMPORARY, `C` CHAR(255) TEMPORARY PRIMARY KEY `C`)";
3582     r = run_query(hdb, 0, query);
3583     ok(r == ERROR_SUCCESS, "failed to add table\n");
3584
3585     query = "SELECT * FROM `T2`";
3586     r = MsiDatabaseOpenView(hdb, query, &view);
3587     ok(r == ERROR_BAD_QUERY_SYNTAX,
3588        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
3589
3590     cond = MsiDatabaseIsTablePersistent(hdb, "T2");
3591     ok( cond == MSICONDITION_NONE, "wrong return condition\n");
3592
3593     query = "CREATE TABLE `T3` ( `B` SHORT NOT NULL TEMPORARY, `C` CHAR(255) PRIMARY KEY `C`)";
3594     r = run_query(hdb, 0, query);
3595     ok(r == ERROR_SUCCESS, "failed to add table\n");
3596
3597     cond = MsiDatabaseIsTablePersistent(hdb, "T3");
3598     ok( cond == MSICONDITION_TRUE, "wrong return condition\n");
3599
3600     query = "CREATE TABLE `T4` ( `B` SHORT NOT NULL, `C` CHAR(255) TEMPORARY PRIMARY KEY `C`)";
3601     r = run_query(hdb, 0, query);
3602     ok(r == ERROR_FUNCTION_FAILED, "failed to add table\n");
3603
3604     cond = MsiDatabaseIsTablePersistent(hdb, "T4");
3605     ok( cond == MSICONDITION_NONE, "wrong return condition\n");
3606
3607     query = "CREATE TABLE `T5` ( `B` SHORT NOT NULL TEMP, `C` CHAR(255) TEMP PRIMARY KEY `C`) HOLD";
3608     r = run_query(hdb, 0, query);
3609     ok(r == ERROR_BAD_QUERY_SYNTAX, "failed to add table\n");
3610
3611     query = "select * from `T`";
3612     r = MsiDatabaseOpenView(hdb, query, &view);
3613     ok(r == ERROR_SUCCESS, "failed to query table\n");
3614     r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
3615     ok(r == ERROR_SUCCESS, "failed to get column info\n");
3616
3617     sz = sizeof buf;
3618     r = MsiRecordGetString(rec, 1, buf, &sz);
3619     ok(r == ERROR_SUCCESS, "failed to get string\n");
3620     ok( 0 == strcmp("G255", buf), "wrong column type\n");
3621
3622     sz = sizeof buf;
3623     r = MsiRecordGetString(rec, 2, buf, &sz);
3624     ok(r == ERROR_SUCCESS, "failed to get string\n");
3625     ok( 0 == strcmp("j2", buf), "wrong column type\n");
3626
3627     MsiCloseHandle( rec );
3628     MsiViewClose( view );
3629     MsiCloseHandle( view );
3630
3631     /* query the table data */
3632     rec = 0;
3633     r = do_query(hdb, "select * from `_Tables` where `Name` = 'T'", &rec);
3634     ok( r == ERROR_SUCCESS, "temporary table exists in _Tables\n");
3635     MsiCloseHandle( rec );
3636
3637     /* query the column data */
3638     rec = 0;
3639     r = do_query(hdb, "select * from `_Columns` where `Table` = 'T' AND `Name` = 'B'", &rec);
3640     ok( r == ERROR_NO_MORE_ITEMS, "temporary table exists in _Columns\n");
3641     if (rec) MsiCloseHandle( rec );
3642
3643     r = do_query(hdb, "select * from `_Columns` where `Table` = 'T' AND `Name` = 'C'", &rec);
3644     ok( r == ERROR_NO_MORE_ITEMS, "temporary table exists in _Columns\n");
3645     if (rec) MsiCloseHandle( rec );
3646
3647     MsiCloseHandle( hdb );
3648
3649     DeleteFile(msifile);
3650 }
3651
3652 static void test_alter(void)
3653 {
3654     MSICONDITION cond;
3655     MSIHANDLE hdb = 0;
3656     const char *query;
3657     UINT r;
3658
3659     hdb = create_db();
3660     ok( hdb, "failed to create db\n");
3661
3662     query = "CREATE TABLE `T` ( `B` SHORT NOT NULL TEMPORARY, `C` CHAR(255) TEMPORARY PRIMARY KEY `C`) HOLD";
3663     r = run_query(hdb, 0, query);
3664     ok(r == ERROR_SUCCESS, "failed to add table\n");
3665
3666     cond = MsiDatabaseIsTablePersistent(hdb, "T");
3667     ok( cond == MSICONDITION_FALSE, "wrong return condition\n");
3668
3669     query = "ALTER TABLE `T` HOLD";
3670     r = run_query(hdb, 0, query);
3671     ok(r == ERROR_SUCCESS, "failed to hold table %d\n", r);
3672
3673     query = "ALTER TABLE `T` FREE";
3674     r = run_query(hdb, 0, query);
3675     ok(r == ERROR_SUCCESS, "failed to free table\n");
3676
3677     query = "ALTER TABLE `T` FREE";
3678     r = run_query(hdb, 0, query);
3679     ok(r == ERROR_SUCCESS, "failed to free table\n");
3680
3681     query = "ALTER TABLE `T` FREE";
3682     r = run_query(hdb, 0, query);
3683     ok(r == ERROR_BAD_QUERY_SYNTAX, "failed to free table\n");
3684
3685     query = "ALTER TABLE `T` HOLD";
3686     r = run_query(hdb, 0, query);
3687     ok(r == ERROR_BAD_QUERY_SYNTAX, "failed to hold table %d\n", r);
3688
3689     /* table T is removed */
3690     query = "SELECT * FROM `T`";
3691     r = run_query(hdb, 0, query);
3692     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
3693
3694     /* create the table again */
3695     query = "CREATE TABLE `U` ( `A` INTEGER, `B` INTEGER PRIMARY KEY `B`)";
3696     r = run_query(hdb, 0, query);
3697     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3698
3699     /* up the ref count */
3700     query = "ALTER TABLE `U` HOLD";
3701     r = run_query(hdb, 0, query);
3702     ok(r == ERROR_SUCCESS, "failed to free table\n");
3703
3704     /* add column, no data type */
3705     query = "ALTER TABLE `U` ADD `C`";
3706     r = run_query(hdb, 0, query);
3707     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
3708
3709     query = "ALTER TABLE `U` ADD `C` INTEGER";
3710     r = run_query(hdb, 0, query);
3711     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3712
3713     /* add column C again */
3714     query = "ALTER TABLE `U` ADD `C` INTEGER";
3715     r = run_query(hdb, 0, query);
3716     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
3717
3718     query = "ALTER TABLE `U` ADD `D` INTEGER TEMPORARY";
3719     r = run_query(hdb, 0, query);
3720     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3721
3722     query = "INSERT INTO `U` ( `A`, `B`, `C`, `D` ) VALUES ( 1, 2, 3, 4 )";
3723     r = run_query(hdb, 0, query);
3724     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3725
3726     query = "ALTER TABLE `U` ADD `D` INTEGER TEMPORARY HOLD";
3727     r = run_query(hdb, 0, query);
3728     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
3729
3730     query = "INSERT INTO `U` ( `A`, `B`, `C`, `D` ) VALUES ( 5, 6, 7, 8 )";
3731     r = run_query(hdb, 0, query);
3732     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3733
3734     query = "SELECT * FROM `U` WHERE `D` = 8";
3735     r = run_query(hdb, 0, query);
3736     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3737
3738     query = "ALTER TABLE `U` ADD `D` INTEGER TEMPORARY FREE";
3739     r = run_query(hdb, 0, query);
3740     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
3741
3742     query = "ALTER COLUMN `D` FREE";
3743     r = run_query(hdb, 0, query);
3744     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
3745
3746     /* drop the ref count */
3747     query = "ALTER TABLE `U` FREE";
3748     r = run_query(hdb, 0, query);
3749     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3750
3751     /* table is not empty */
3752     query = "SELECT * FROM `U`";
3753     r = run_query(hdb, 0, query);
3754     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3755
3756     /* column D is removed */
3757     query = "SELECT * FROM `U` WHERE `D` = 8";
3758     r = run_query(hdb, 0, query);
3759     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
3760
3761     query = "INSERT INTO `U` ( `A`, `B`, `C`, `D` ) VALUES ( 9, 10, 11, 12 )";
3762     r = run_query(hdb, 0, query);
3763     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
3764
3765     /* add the column again */
3766     query = "ALTER TABLE `U` ADD `E` INTEGER TEMPORARY HOLD";
3767     r = run_query(hdb, 0, query);
3768     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3769
3770     /* up the ref count */
3771     query = "ALTER TABLE `U` HOLD";
3772     r = run_query(hdb, 0, query);
3773     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3774
3775     query = "INSERT INTO `U` ( `A`, `B`, `C`, `E` ) VALUES ( 13, 14, 15, 16 )";
3776     r = run_query(hdb, 0, query);
3777     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3778
3779     query = "SELECT * FROM `U` WHERE `E` = 16";
3780     r = run_query(hdb, 0, query);
3781     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3782
3783     /* drop the ref count */
3784     query = "ALTER TABLE `U` FREE";
3785     r = run_query(hdb, 0, query);
3786     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3787
3788     query = "INSERT INTO `U` ( `A`, `B`, `C`, `E` ) VALUES ( 17, 18, 19, 20 )";
3789     r = run_query(hdb, 0, query);
3790     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3791
3792     query = "SELECT * FROM `U` WHERE `E` = 20";
3793     r = run_query(hdb, 0, query);
3794     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3795
3796     /* drop the ref count */
3797     query = "ALTER TABLE `U` FREE";
3798     r = run_query(hdb, 0, query);
3799     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3800
3801     /* table still exists */
3802     query = "SELECT * FROM `U`";
3803     r = run_query(hdb, 0, query);
3804     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3805
3806     /* col E is removed */
3807     query = "SELECT * FROM `U` WHERE `E` = 20";
3808     r = run_query(hdb, 0, query);
3809     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
3810
3811     query = "INSERT INTO `U` ( `A`, `B`, `C`, `E` ) VALUES ( 20, 21, 22, 23 )";
3812     r = run_query(hdb, 0, query);
3813     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
3814
3815     /* drop the ref count once more */
3816     query = "ALTER TABLE `U` FREE";
3817     r = run_query(hdb, 0, query);
3818     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3819
3820     /* table still exists */
3821     query = "SELECT * FROM `U`";
3822     r = run_query(hdb, 0, query);
3823     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3824
3825     MsiCloseHandle( hdb );
3826     DeleteFile(msifile);
3827 }
3828
3829 static void test_integers(void)
3830 {
3831     MSIHANDLE hdb = 0, view = 0, rec = 0;
3832     DWORD count, i;
3833     const char *query;
3834     UINT r;
3835
3836     /* just MsiOpenDatabase should not create a file */
3837     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
3838     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
3839
3840     /* create a table */
3841     query = "CREATE TABLE `integers` ( "
3842             "`one` SHORT, `two` INT, `three` INTEGER, `four` LONG, "
3843             "`five` SHORT NOT NULL, `six` INT NOT NULL, "
3844             "`seven` INTEGER NOT NULL, `eight` LONG NOT NULL "
3845             "PRIMARY KEY `one`)";
3846     r = MsiDatabaseOpenView(hdb, query, &view);
3847     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
3848     r = MsiViewExecute(view, 0);
3849     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
3850     r = MsiViewClose(view);
3851     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
3852     r = MsiCloseHandle(view);
3853     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
3854
3855     query = "SELECT * FROM `integers`";
3856     r = MsiDatabaseOpenView(hdb, query, &view);
3857     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3858
3859     r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec);
3860     count = MsiRecordGetFieldCount(rec);
3861     ok(count == 8, "Expected 8, got %d\n", count);
3862     ok(check_record(rec, 1, "one"), "Expected one\n");
3863     ok(check_record(rec, 2, "two"), "Expected two\n");
3864     ok(check_record(rec, 3, "three"), "Expected three\n");
3865     ok(check_record(rec, 4, "four"), "Expected four\n");
3866     ok(check_record(rec, 5, "five"), "Expected five\n");
3867     ok(check_record(rec, 6, "six"), "Expected six\n");
3868     ok(check_record(rec, 7, "seven"), "Expected seven\n");
3869     ok(check_record(rec, 8, "eight"), "Expected eight\n");
3870     MsiCloseHandle(rec);
3871
3872     r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
3873     count = MsiRecordGetFieldCount(rec);
3874     ok(count == 8, "Expected 8, got %d\n", count);
3875     ok(check_record(rec, 1, "I2"), "Expected I2\n");
3876     ok(check_record(rec, 2, "I2"), "Expected I2\n");
3877     ok(check_record(rec, 3, "I2"), "Expected I2\n");
3878     ok(check_record(rec, 4, "I4"), "Expected I4\n");
3879     ok(check_record(rec, 5, "i2"), "Expected i2\n");
3880     ok(check_record(rec, 6, "i2"), "Expected i2\n");
3881     ok(check_record(rec, 7, "i2"), "Expected i2\n");
3882     ok(check_record(rec, 8, "i4"), "Expected i4\n");
3883     MsiCloseHandle(rec);
3884
3885     MsiViewClose(view);
3886     MsiCloseHandle(view);
3887
3888     /* insert values into it, NULL where NOT NULL is specified */
3889     query = "INSERT INTO `integers` ( `one`, `two`, `three`, `four`, `five`, `six`, `seven`, `eight` )"
3890         "VALUES('', '', '', '', '', '', '', '')";
3891     r = MsiDatabaseOpenView(hdb, query, &view);
3892     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3893     r = MsiViewExecute(view, 0);
3894     ok(r == ERROR_FUNCTION_FAILED, "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
3895
3896     MsiViewClose(view);
3897     MsiCloseHandle(view);
3898
3899     query = "SELECT * FROM `integers`";
3900     r = do_query(hdb, query, &rec);
3901     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
3902
3903     r = MsiRecordGetFieldCount(rec);
3904     ok(r == -1, "record count wrong: %d\n", r);
3905
3906     MsiCloseHandle(rec);
3907
3908     /* insert legitimate values into it */
3909     query = "INSERT INTO `integers` ( `one`, `two`, `three`, `four`, `five`, `six`, `seven`, `eight` )"
3910         "VALUES('', '2', '', '4', '5', '6', '7', '8')";
3911     r = MsiDatabaseOpenView(hdb, query, &view);
3912     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3913     r = MsiViewExecute(view, 0);
3914     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3915
3916     query = "SELECT * FROM `integers`";
3917     r = do_query(hdb, query, &rec);
3918     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3919
3920     r = MsiRecordGetFieldCount(rec);
3921     ok(r == 8, "record count wrong: %d\n", r);
3922
3923     i = MsiRecordGetInteger(rec, 1);
3924     ok(i == MSI_NULL_INTEGER, "Expected MSI_NULL_INTEGER, got %d\n", i);
3925     i = MsiRecordGetInteger(rec, 3);
3926     ok(i == MSI_NULL_INTEGER, "Expected MSI_NULL_INTEGER, got %d\n", i);
3927     i = MsiRecordGetInteger(rec, 2);
3928     ok(i == 2, "Expected 2, got %d\n", i);
3929     i = MsiRecordGetInteger(rec, 4);
3930     ok(i == 4, "Expected 4, got %d\n", i);
3931     i = MsiRecordGetInteger(rec, 5);
3932     ok(i == 5, "Expected 5, got %d\n", i);
3933     i = MsiRecordGetInteger(rec, 6);
3934     ok(i == 6, "Expected 6, got %d\n", i);
3935     i = MsiRecordGetInteger(rec, 7);
3936     ok(i == 7, "Expected 7, got %d\n", i);
3937     i = MsiRecordGetInteger(rec, 8);
3938     ok(i == 8, "Expected 8, got %d\n", i);
3939
3940     MsiCloseHandle(rec);
3941     MsiViewClose(view);
3942     MsiCloseHandle(view);
3943
3944     r = MsiDatabaseCommit(hdb);
3945     ok(r == ERROR_SUCCESS, "MsiDatabaseCommit failed\n");
3946
3947     r = MsiCloseHandle(hdb);
3948     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
3949
3950     r = DeleteFile(msifile);
3951     ok(r == TRUE, "file didn't exist after commit\n");
3952 }
3953
3954 static void test_update(void)
3955 {
3956     MSIHANDLE hdb = 0, view = 0, rec = 0;
3957     CHAR result[MAX_PATH];
3958     const char *query;
3959     DWORD size;
3960     UINT r;
3961
3962     /* just MsiOpenDatabase should not create a file */
3963     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
3964     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
3965
3966     /* create the Control table */
3967     query = "CREATE TABLE `Control` ( "
3968         "`Dialog_` CHAR(72) NOT NULL, `Control` CHAR(50) NOT NULL, `Type` SHORT NOT NULL, "
3969         "`X` SHORT NOT NULL, `Y` SHORT NOT NULL, `Width` SHORT NOT NULL, `Height` SHORT NOT NULL,"
3970         "`Attributes` LONG, `Property` CHAR(50), `Text` CHAR(0) LOCALIZABLE, "
3971         "`Control_Next` CHAR(50), `Help` CHAR(50) LOCALIZABLE PRIMARY KEY `Dialog_`, `Control`)";
3972     r = MsiDatabaseOpenView(hdb, query, &view);
3973     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
3974     r = MsiViewExecute(view, 0);
3975     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
3976     r = MsiViewClose(view);
3977     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
3978     r = MsiCloseHandle(view);
3979     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
3980
3981     /* add a control */
3982     query = "INSERT INTO `Control` ( "
3983         "`Dialog_`, `Control`, `Type`, `X`, `Y`, `Width`, `Height`, "
3984         "`Property`, `Text`, `Control_Next`, `Help` )"
3985         "VALUES('ErrorDialog', 'ErrorText', '1', '5', '5', '5', '5', '', '', '', '')";
3986     r = MsiDatabaseOpenView(hdb, query, &view);
3987     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3988     r = MsiViewExecute(view, 0);
3989     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3990     r = MsiViewClose(view);
3991     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
3992     r = MsiCloseHandle(view);
3993     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
3994
3995     /* add a second control */
3996     query = "INSERT INTO `Control` ( "
3997         "`Dialog_`, `Control`, `Type`, `X`, `Y`, `Width`, `Height`, "
3998         "`Property`, `Text`, `Control_Next`, `Help` )"
3999         "VALUES('ErrorDialog', 'Button', '1', '5', '5', '5', '5', '', '', '', '')";
4000     r = MsiDatabaseOpenView(hdb, query, &view);
4001     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4002     r = MsiViewExecute(view, 0);
4003     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4004     r = MsiViewClose(view);
4005     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4006     r = MsiCloseHandle(view);
4007     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4008
4009     /* add a third control */
4010     query = "INSERT INTO `Control` ( "
4011         "`Dialog_`, `Control`, `Type`, `X`, `Y`, `Width`, `Height`, "
4012         "`Property`, `Text`, `Control_Next`, `Help` )"
4013         "VALUES('AnotherDialog', 'ErrorText', '1', '5', '5', '5', '5', '', '', '', '')";
4014     r = MsiDatabaseOpenView(hdb, query, &view);
4015     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4016     r = MsiViewExecute(view, 0);
4017     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4018     r = MsiViewClose(view);
4019     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4020     r = MsiCloseHandle(view);
4021     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4022
4023     /* bad table */
4024     query = "UPDATE `NotATable` SET `Text` = 'this is text' WHERE `Dialog_` = 'ErrorDialog'";
4025     r = MsiDatabaseOpenView(hdb, query, &view);
4026     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
4027
4028     /* bad set column */
4029     query = "UPDATE `Control` SET `NotAColumn` = 'this is text' WHERE `Dialog_` = 'ErrorDialog'";
4030     r = MsiDatabaseOpenView(hdb, query, &view);
4031     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
4032
4033     /* bad where condition */
4034     query = "UPDATE `Control` SET `Text` = 'this is text' WHERE `NotAColumn` = 'ErrorDialog'";
4035     r = MsiDatabaseOpenView(hdb, query, &view);
4036     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
4037
4038     /* just the dialog_ specified */
4039     query = "UPDATE `Control` SET `Text` = 'this is text' WHERE `Dialog_` = 'ErrorDialog'";
4040     r = MsiDatabaseOpenView(hdb, query, &view);
4041     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4042     r = MsiViewExecute(view, 0);
4043     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4044     r = MsiViewClose(view);
4045     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4046     r = MsiCloseHandle(view);
4047     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4048
4049     /* check the modified text */
4050     query = "SELECT `Text` FROM `Control` WHERE `Control` = 'ErrorText'";
4051     r = MsiDatabaseOpenView(hdb, query, &view);
4052     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4053     r = MsiViewExecute(view, 0);
4054     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4055
4056     r = MsiViewFetch(view, &rec);
4057     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4058
4059     size = MAX_PATH;
4060     r = MsiRecordGetString(rec, 1, result, &size);
4061     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4062     ok(!lstrcmp(result, "this is text"), "Expected `this is text`, got %s\n", result);
4063
4064     MsiCloseHandle(rec);
4065
4066     r = MsiViewFetch(view, &rec);
4067     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4068
4069     size = MAX_PATH;
4070     r = MsiRecordGetString(rec, 1, result, &size);
4071     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4072     ok(!lstrlen(result), "Expected an empty string, got %s\n", result);
4073
4074     MsiCloseHandle(rec);
4075
4076     r = MsiViewFetch(view, &rec);
4077     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
4078
4079     r = MsiViewClose(view);
4080     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4081     r = MsiCloseHandle(view);
4082     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4083
4084     /* dialog_ and control specified */
4085     query = "UPDATE `Control` SET `Text` = 'this is text' WHERE `Dialog_` = 'ErrorDialog' AND `Control` = 'ErrorText'";
4086     r = MsiDatabaseOpenView(hdb, query, &view);
4087     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4088     r = MsiViewExecute(view, 0);
4089     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4090     r = MsiViewClose(view);
4091     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4092     r = MsiCloseHandle(view);
4093     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4094
4095     /* check the modified text */
4096     query = "SELECT `Text` FROM `Control` WHERE `Control` = 'ErrorText'";
4097     r = MsiDatabaseOpenView(hdb, query, &view);
4098     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4099     r = MsiViewExecute(view, 0);
4100     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4101
4102     r = MsiViewFetch(view, &rec);
4103     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4104
4105     size = MAX_PATH;
4106     r = MsiRecordGetString(rec, 1, result, &size);
4107     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4108     ok(!lstrcmp(result, "this is text"), "Expected `this is text`, got %s\n", result);
4109
4110     MsiCloseHandle(rec);
4111
4112     r = MsiViewFetch(view, &rec);
4113     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4114
4115     size = MAX_PATH;
4116     r = MsiRecordGetString(rec, 1, result, &size);
4117     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4118     ok(!lstrlen(result), "Expected an empty string, got %s\n", result);
4119
4120     MsiCloseHandle(rec);
4121
4122     r = MsiViewFetch(view, &rec);
4123     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
4124
4125     r = MsiViewClose(view);
4126     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4127     r = MsiCloseHandle(view);
4128     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4129
4130     /* no where condition */
4131     query = "UPDATE `Control` SET `Text` = 'this is text'";
4132     r = MsiDatabaseOpenView(hdb, query, &view);
4133     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4134     r = MsiViewExecute(view, 0);
4135     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4136     r = MsiViewClose(view);
4137     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4138     r = MsiCloseHandle(view);
4139     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4140
4141     /* check the modified text */
4142     query = "SELECT `Text` FROM `Control`";
4143     r = MsiDatabaseOpenView(hdb, query, &view);
4144     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4145     r = MsiViewExecute(view, 0);
4146     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4147
4148     r = MsiViewFetch(view, &rec);
4149     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4150
4151     size = MAX_PATH;
4152     r = MsiRecordGetString(rec, 1, result, &size);
4153     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4154     ok(!lstrcmp(result, "this is text"), "Expected `this is text`, got %s\n", result);
4155
4156     MsiCloseHandle(rec);
4157
4158     r = MsiViewFetch(view, &rec);
4159     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4160
4161     size = MAX_PATH;
4162     r = MsiRecordGetString(rec, 1, result, &size);
4163     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4164     ok(!lstrcmp(result, "this is text"), "Expected `this is text`, got %s\n", result);
4165
4166     MsiCloseHandle(rec);
4167
4168     r = MsiViewFetch(view, &rec);
4169     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4170
4171     size = MAX_PATH;
4172     r = MsiRecordGetString(rec, 1, result, &size);
4173     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4174     ok(!lstrcmp(result, "this is text"), "Expected `this is text`, got %s\n", result);
4175
4176     MsiCloseHandle(rec);
4177
4178     r = MsiViewFetch(view, &rec);
4179     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
4180
4181     r = MsiViewClose(view);
4182     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4183     r = MsiCloseHandle(view);
4184     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4185
4186     query = "CREATE TABLE `Apple` ( `Banana` CHAR(72) NOT NULL, "
4187         "`Orange` CHAR(72),  `Pear` INT PRIMARY KEY `Banana`)";
4188     r = run_query(hdb, 0, query);
4189     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4190
4191     query = "INSERT INTO `Apple` ( `Banana`, `Orange`, `Pear` )"
4192         "VALUES('one', 'two', 3)";
4193     r = run_query(hdb, 0, query);
4194     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4195
4196     query = "INSERT INTO `Apple` ( `Banana`, `Orange`, `Pear` )"
4197         "VALUES('three', 'four', 5)";
4198     r = run_query(hdb, 0, query);
4199     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4200
4201     query = "INSERT INTO `Apple` ( `Banana`, `Orange`, `Pear` )"
4202         "VALUES('six', 'two', 7)";
4203     r = run_query(hdb, 0, query);
4204     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4205
4206     rec = MsiCreateRecord(2);
4207     MsiRecordSetInteger(rec, 1, 8);
4208     MsiRecordSetString(rec, 2, "two");
4209
4210     query = "UPDATE `Apple` SET `Pear` = ? WHERE `Orange` = ?";
4211     r = run_query(hdb, rec, query);
4212     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4213
4214     MsiCloseHandle(rec);
4215
4216     query = "SELECT `Pear` FROM `Apple` ORDER BY `Orange`";
4217     r = MsiDatabaseOpenView(hdb, query, &view);
4218     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4219     r = MsiViewExecute(view, 0);
4220     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4221
4222     r = MsiViewFetch(view, &rec);
4223     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4224
4225     r = MsiRecordGetInteger(rec, 1);
4226     ok(r == 8, "Expected 8, got %d\n", r);
4227
4228     MsiCloseHandle(rec);
4229
4230     r = MsiViewFetch(view, &rec);
4231     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4232
4233     r = MsiRecordGetInteger(rec, 1);
4234     ok(r == 8, "Expected 8, got %d\n", r);
4235
4236     MsiCloseHandle(rec);
4237
4238     r = MsiViewFetch(view, &rec);
4239     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4240
4241     r = MsiRecordGetInteger(rec, 1);
4242     ok(r == 5, "Expected 5, got %d\n", r);
4243
4244     MsiCloseHandle(rec);
4245
4246     r = MsiViewFetch(view, &rec);
4247     ok(r == ERROR_NO_MORE_ITEMS, "Expectd ERROR_NO_MORE_ITEMS, got %d\n", r);
4248
4249     MsiViewClose(view);
4250     MsiCloseHandle(view);
4251
4252     r = MsiDatabaseCommit(hdb);
4253     ok(r == ERROR_SUCCESS, "MsiDatabaseCommit failed\n");
4254     r = MsiCloseHandle(hdb);
4255     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4256
4257     DeleteFile(msifile);
4258 }
4259
4260 static void test_special_tables(void)
4261 {
4262     const char *query;
4263     MSIHANDLE hdb = 0;
4264     UINT r;
4265
4266     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
4267     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
4268
4269     query = "CREATE TABLE `_Properties` ( "
4270         "`foo` INT NOT NULL, `bar` INT LOCALIZABLE PRIMARY KEY `foo`)";
4271     r = run_query(hdb, 0, query);
4272     ok(r == ERROR_SUCCESS, "failed to create table\n");
4273
4274     query = "CREATE TABLE `_Storages` ( "
4275         "`foo` INT NOT NULL, `bar` INT LOCALIZABLE PRIMARY KEY `foo`)";
4276     r = run_query(hdb, 0, query);
4277     ok(r == ERROR_BAD_QUERY_SYNTAX, "created _Streams table\n");
4278
4279     query = "CREATE TABLE `_Streams` ( "
4280         "`foo` INT NOT NULL, `bar` INT LOCALIZABLE PRIMARY KEY `foo`)";
4281     r = run_query(hdb, 0, query);
4282     ok(r == ERROR_BAD_QUERY_SYNTAX, "created _Streams table\n");
4283
4284     query = "CREATE TABLE `_Tables` ( "
4285         "`foo` INT NOT NULL, `bar` INT LOCALIZABLE PRIMARY KEY `foo`)";
4286     r = run_query(hdb, 0, query);
4287     ok(r == ERROR_BAD_QUERY_SYNTAX, "created _Tables table\n");
4288
4289     query = "CREATE TABLE `_Columns` ( "
4290         "`foo` INT NOT NULL, `bar` INT LOCALIZABLE PRIMARY KEY `foo`)";
4291     r = run_query(hdb, 0, query);
4292     ok(r == ERROR_BAD_QUERY_SYNTAX, "created _Columns table\n");
4293
4294     r = MsiCloseHandle(hdb);
4295     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4296 }
4297
4298 static void test_tables_order(void)
4299 {
4300     const char *query;
4301     MSIHANDLE hdb = 0, hview = 0, hrec = 0;
4302     UINT r;
4303     char buffer[100];
4304     DWORD sz;
4305
4306     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
4307     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
4308
4309     query = "CREATE TABLE `foo` ( "
4310         "`baz` INT NOT NULL PRIMARY KEY `baz`)";
4311     r = run_query(hdb, 0, query);
4312     ok(r == ERROR_SUCCESS, "failed to create table\n");
4313
4314     query = "CREATE TABLE `bar` ( "
4315         "`foo` INT NOT NULL PRIMARY KEY `foo`)";
4316     r = run_query(hdb, 0, query);
4317     ok(r == ERROR_SUCCESS, "failed to create table\n");
4318
4319     query = "CREATE TABLE `baz` ( "
4320         "`bar` INT NOT NULL, "
4321         "`baz` INT NOT NULL, "
4322         "`foo` INT NOT NULL PRIMARY KEY `bar`)";
4323     r = run_query(hdb, 0, query);
4324     ok(r == ERROR_SUCCESS, "failed to create table\n");
4325
4326     /* The names of the tables in the _Tables table must
4327        be in the same order as these names are created in
4328        the strings table. */
4329     query = "SELECT * FROM `_Tables`";
4330     r = MsiDatabaseOpenView(hdb, query, &hview);
4331     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
4332     r = MsiViewExecute(hview, 0);
4333     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
4334
4335     r = MsiViewFetch(hview, &hrec);
4336     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4337     sz = sizeof(buffer);
4338     r = MsiRecordGetString(hrec, 1, buffer, &sz);
4339     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4340     ok(!lstrcmp(buffer, "foo"), "Expected foo, got %s\n", buffer);
4341     r = MsiCloseHandle(hrec);
4342     ok(r == ERROR_SUCCESS, "failed to close record\n");
4343
4344     r = MsiViewFetch(hview, &hrec);
4345     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4346     sz = sizeof(buffer);
4347     r = MsiRecordGetString(hrec, 1, buffer, &sz);
4348     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4349     ok(!lstrcmp(buffer, "baz"), "Expected baz, got %s\n", buffer);
4350     r = MsiCloseHandle(hrec);
4351     ok(r == ERROR_SUCCESS, "failed to close record\n");
4352
4353     r = MsiViewFetch(hview, &hrec);
4354     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4355     sz = sizeof(buffer);
4356     r = MsiRecordGetString(hrec, 1, buffer, &sz);
4357     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4358     ok(!lstrcmp(buffer, "bar"), "Expected bar, got %s\n", buffer);
4359     r = MsiCloseHandle(hrec);
4360     ok(r == ERROR_SUCCESS, "failed to close record\n");
4361
4362     r = MsiViewClose(hview);
4363     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4364     r = MsiCloseHandle(hview);
4365     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4366
4367     /* The names of the tables in the _Columns table must
4368        be in the same order as these names are created in
4369        the strings table. */
4370     query = "SELECT * FROM `_Columns`";
4371     r = MsiDatabaseOpenView(hdb, query, &hview);
4372     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
4373     r = MsiViewExecute(hview, 0);
4374     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
4375
4376     r = MsiViewFetch(hview, &hrec);
4377     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4378     sz = sizeof(buffer);
4379     r = MsiRecordGetString(hrec, 1, buffer, &sz);
4380     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4381     ok(!lstrcmp(buffer, "foo"), "Expected foo, got %s\n", buffer);
4382     sz = sizeof(buffer);
4383     r = MsiRecordGetString(hrec, 3, buffer, &sz);
4384     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4385     ok(!lstrcmp(buffer, "baz"), "Expected baz, got %s\n", buffer);
4386     r = MsiCloseHandle(hrec);
4387     ok(r == ERROR_SUCCESS, "failed to close record\n");
4388
4389     r = MsiViewFetch(hview, &hrec);
4390     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4391     sz = sizeof(buffer);
4392     r = MsiRecordGetString(hrec, 1, buffer, &sz);
4393     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4394     ok(!lstrcmp(buffer, "baz"), "Expected baz, got %s\n", buffer);
4395     sz = sizeof(buffer);
4396     r = MsiRecordGetString(hrec, 3, buffer, &sz);
4397     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4398     ok(!lstrcmp(buffer, "bar"), "Expected bar, got %s\n", buffer);
4399     r = MsiCloseHandle(hrec);
4400     ok(r == ERROR_SUCCESS, "failed to close record\n");
4401
4402     r = MsiViewFetch(hview, &hrec);
4403     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4404     sz = sizeof(buffer);
4405     r = MsiRecordGetString(hrec, 1, buffer, &sz);
4406     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4407     ok(!lstrcmp(buffer, "baz"), "Expected baz, got %s\n", buffer);
4408     sz = sizeof(buffer);
4409     r = MsiRecordGetString(hrec, 3, buffer, &sz);
4410     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4411     ok(!lstrcmp(buffer, "baz"), "Expected baz, got %s\n", buffer);
4412     r = MsiCloseHandle(hrec);
4413     ok(r == ERROR_SUCCESS, "failed to close record\n");
4414
4415     r = MsiViewFetch(hview, &hrec);
4416     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4417     sz = sizeof(buffer);
4418     r = MsiRecordGetString(hrec, 1, buffer, &sz);
4419     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4420     ok(!lstrcmp(buffer, "baz"), "Expected baz, got %s\n", buffer);
4421     sz = sizeof(buffer);
4422     r = MsiRecordGetString(hrec, 3, buffer, &sz);
4423     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4424     ok(!lstrcmp(buffer, "foo"), "Expected foo, got %s\n", buffer);
4425     r = MsiCloseHandle(hrec);
4426     ok(r == ERROR_SUCCESS, "failed to close record\n");
4427
4428     r = MsiViewFetch(hview, &hrec);
4429     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4430     sz = sizeof(buffer);
4431     r = MsiRecordGetString(hrec, 1, buffer, &sz);
4432     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4433     ok(!lstrcmp(buffer, "bar"), "Expected bar, got %s\n", buffer);
4434     sz = sizeof(buffer);
4435     r = MsiRecordGetString(hrec, 3, buffer, &sz);
4436     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4437     ok(!lstrcmp(buffer, "foo"), "Expected foo, got %s\n", buffer);
4438     r = MsiCloseHandle(hrec);
4439     ok(r == ERROR_SUCCESS, "failed to close record\n");
4440
4441     r = MsiViewClose(hview);
4442     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4443     r = MsiCloseHandle(hview);
4444     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4445
4446     r = MsiCloseHandle(hdb);
4447     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4448
4449     DeleteFile(msifile);
4450 }
4451
4452 static void test_select_markers(void)
4453 {
4454     MSIHANDLE hdb = 0, rec, view, res;
4455     LPCSTR query;
4456     UINT r;
4457     DWORD size;
4458     CHAR buf[MAX_PATH];
4459
4460     hdb = create_db();
4461     ok( hdb, "failed to create db\n");
4462
4463     r = run_query(hdb, 0,
4464             "CREATE TABLE `Table` (`One` CHAR(72), `Two` CHAR(72), `Three` SHORT PRIMARY KEY `One`, `Two`, `Three`)");
4465     ok(r == S_OK, "cannot create table: %d\n", r);
4466
4467     r = run_query(hdb, 0, "INSERT INTO `Table` "
4468             "( `One`, `Two`, `Three` ) VALUES ( 'apple', 'one', 1 )");
4469     ok(r == S_OK, "cannot add file to the Media table: %d\n", r);
4470
4471     r = run_query(hdb, 0, "INSERT INTO `Table` "
4472             "( `One`, `Two`, `Three` ) VALUES ( 'apple', 'two', 1 )");
4473     ok(r == S_OK, "cannot add file to the Media table: %d\n", r);
4474
4475     r = run_query(hdb, 0, "INSERT INTO `Table` "
4476             "( `One`, `Two`, `Three` ) VALUES ( 'apple', 'two', 2 )");
4477     ok(r == S_OK, "cannot add file to the Media table: %d\n", r);
4478
4479     r = run_query(hdb, 0, "INSERT INTO `Table` "
4480             "( `One`, `Two`, `Three` ) VALUES ( 'banana', 'three', 3 )");
4481     ok(r == S_OK, "cannot add file to the Media table: %d\n", r);
4482
4483     rec = MsiCreateRecord(2);
4484     MsiRecordSetString(rec, 1, "apple");
4485     MsiRecordSetString(rec, 2, "two");
4486
4487     query = "SELECT * FROM `Table` WHERE `One`=? AND `Two`=? ORDER BY `Three`";
4488     r = MsiDatabaseOpenView(hdb, query, &view);
4489     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4490
4491     r = MsiViewExecute(view, rec);
4492     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4493
4494     r = MsiViewFetch(view, &res);
4495     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4496
4497     size = MAX_PATH;
4498     r = MsiRecordGetString(res, 1, buf, &size);
4499     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4500     ok(!lstrcmp(buf, "apple"), "Expected apple, got %s\n", buf);
4501
4502     size = MAX_PATH;
4503     r = MsiRecordGetString(res, 2, buf, &size);
4504     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4505     ok(!lstrcmp(buf, "two"), "Expected two, got %s\n", buf);
4506
4507     r = MsiRecordGetInteger(res, 3);
4508     ok(r == 1, "Expected 1, got %d\n", r);
4509
4510     MsiCloseHandle(res);
4511
4512     r = MsiViewFetch(view, &res);
4513     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4514
4515     size = MAX_PATH;
4516     r = MsiRecordGetString(res, 1, buf, &size);
4517     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4518     ok(!lstrcmp(buf, "apple"), "Expected apple, got %s\n", buf);
4519
4520     size = MAX_PATH;
4521     r = MsiRecordGetString(res, 2, buf, &size);
4522     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4523     ok(!lstrcmp(buf, "two"), "Expected two, got %s\n", buf);
4524
4525     r = MsiRecordGetInteger(res, 3);
4526     ok(r == 2, "Expected 2, got %d\n", r);
4527
4528     MsiCloseHandle(res);
4529
4530     r = MsiViewFetch(view, &res);
4531     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
4532
4533     MsiCloseHandle(rec);
4534     MsiViewClose(view);
4535     MsiCloseHandle(view);
4536
4537     rec = MsiCreateRecord(2);
4538     MsiRecordSetString(rec, 1, "one");
4539     MsiRecordSetInteger(rec, 2, 1);
4540
4541     query = "SELECT * FROM `Table` WHERE `Two`<>? AND `Three`>? ORDER BY `Three`";
4542     r = MsiDatabaseOpenView(hdb, query, &view);
4543     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4544     r = MsiViewExecute(view, rec);
4545     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4546
4547     r = MsiViewFetch(view, &res);
4548     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4549
4550     size = MAX_PATH;
4551     r = MsiRecordGetString(res, 1, buf, &size);
4552     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4553     ok(!lstrcmp(buf, "apple"), "Expected apple, got %s\n", buf);
4554
4555     size = MAX_PATH;
4556     r = MsiRecordGetString(res, 2, buf, &size);
4557     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4558     ok(!lstrcmp(buf, "two"), "Expected two, got %s\n", buf);
4559
4560     r = MsiRecordGetInteger(res, 3);
4561     ok(r == 2, "Expected 2, got %d\n", r);
4562
4563     MsiCloseHandle(res);
4564
4565     r = MsiViewFetch(view, &res);
4566     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4567
4568     size = MAX_PATH;
4569     r = MsiRecordGetString(res, 1, buf, &size);
4570     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4571     ok(!lstrcmp(buf, "banana"), "Expected banana, got %s\n", buf);
4572
4573     size = MAX_PATH;
4574     r = MsiRecordGetString(res, 2, buf, &size);
4575     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4576     ok(!lstrcmp(buf, "three"), "Expected three, got %s\n", buf);
4577
4578     r = MsiRecordGetInteger(res, 3);
4579     ok(r == 3, "Expected 3, got %d\n", r);
4580
4581     MsiCloseHandle(res);
4582
4583     r = MsiViewFetch(view, &res);
4584     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
4585
4586     MsiCloseHandle(rec);
4587     MsiViewClose(view);
4588     MsiCloseHandle(view);
4589     MsiCloseHandle(hdb);
4590     DeleteFile(msifile);
4591 }
4592
4593 static void test_viewmodify_update(void)
4594 {
4595     MSIHANDLE hdb = 0, hview = 0, hrec = 0;
4596     const char *query;
4597     UINT r;
4598
4599     DeleteFile(msifile);
4600
4601     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
4602     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
4603
4604     query = "CREATE TABLE `table` (`A` INT, `B` INT PRIMARY KEY `A`)";
4605     r = run_query( hdb, 0, query );
4606     ok(r == ERROR_SUCCESS, "query failed\n");
4607
4608     query = "INSERT INTO `table` (`A`, `B`) VALUES (1, 2)";
4609     r = run_query( hdb, 0, query );
4610     ok(r == ERROR_SUCCESS, "query failed\n");
4611
4612     query = "INSERT INTO `table` (`A`, `B`) VALUES (3, 4)";
4613     r = run_query( hdb, 0, query );
4614     ok(r == ERROR_SUCCESS, "query failed\n");
4615
4616     query = "INSERT INTO `table` (`A`, `B`) VALUES (5, 6)";
4617     r = run_query( hdb, 0, query );
4618     ok(r == ERROR_SUCCESS, "query failed\n");
4619
4620     query = "SELECT `B` FROM `table`";
4621     r = MsiDatabaseOpenView(hdb, query, &hview);
4622     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
4623     r = MsiViewExecute(hview, 0);
4624     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
4625     r = MsiViewFetch(hview, &hrec);
4626     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4627
4628     r = MsiRecordSetInteger(hrec, 1, 0);
4629     ok(r == ERROR_SUCCESS, "failed to set integer\n");
4630
4631     r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
4632     ok(r == ERROR_SUCCESS, "MsiViewModify failed: %d\n", r);
4633
4634     r = MsiCloseHandle(hrec);
4635     ok(r == ERROR_SUCCESS, "failed to close record\n");
4636
4637     r = MsiViewClose(hview);
4638     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4639     r = MsiCloseHandle(hview);
4640     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4641
4642     query = "SELECT * FROM `table`";
4643     r = MsiDatabaseOpenView(hdb, query, &hview);
4644     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
4645     r = MsiViewExecute(hview, 0);
4646     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
4647     r = MsiViewFetch(hview, &hrec);
4648     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4649
4650     r = MsiRecordGetInteger(hrec, 1);
4651     ok(r == 1, "Expected 1, got %d\n", r);
4652     r = MsiRecordGetInteger(hrec, 2);
4653     ok(r == 0, "Expected 0, got %d\n", r);
4654
4655     r = MsiCloseHandle(hrec);
4656     ok(r == ERROR_SUCCESS, "failed to close record\n");
4657
4658     r = MsiViewFetch(hview, &hrec);
4659     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4660
4661     r = MsiRecordGetInteger(hrec, 1);
4662     ok(r == 3, "Expected 3, got %d\n", r);
4663     r = MsiRecordGetInteger(hrec, 2);
4664     ok(r == 4, "Expected 4, got %d\n", r);
4665
4666     r = MsiCloseHandle(hrec);
4667     ok(r == ERROR_SUCCESS, "failed to close record\n");
4668
4669     r = MsiViewFetch(hview, &hrec);
4670     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4671
4672     r = MsiRecordGetInteger(hrec, 1);
4673     ok(r == 5, "Expected 5, got %d\n", r);
4674     r = MsiRecordGetInteger(hrec, 2);
4675     ok(r == 6, "Expected 6, got %d\n", r);
4676
4677     r = MsiCloseHandle(hrec);
4678     ok(r == ERROR_SUCCESS, "failed to close record\n");
4679
4680     r = MsiViewFetch(hview, &hrec);
4681     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
4682
4683     r = MsiViewClose(hview);
4684     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4685     r = MsiCloseHandle(hview);
4686     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4687
4688     /* loop through all elements */
4689     query = "SELECT `B` FROM `table`";
4690     r = MsiDatabaseOpenView(hdb, query, &hview);
4691     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
4692     r = MsiViewExecute(hview, 0);
4693     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
4694
4695     while (TRUE)
4696     {
4697         r = MsiViewFetch(hview, &hrec);
4698         if (r != ERROR_SUCCESS)
4699             break;
4700
4701         r = MsiRecordSetInteger(hrec, 1, 0);
4702         ok(r == ERROR_SUCCESS, "failed to set integer\n");
4703
4704         r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
4705         ok(r == ERROR_SUCCESS, "MsiViewModify failed: %d\n", r);
4706
4707         r = MsiCloseHandle(hrec);
4708         ok(r == ERROR_SUCCESS, "failed to close record\n");
4709     }
4710
4711     r = MsiViewClose(hview);
4712     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4713     r = MsiCloseHandle(hview);
4714     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4715
4716     query = "SELECT * FROM `table`";
4717     r = MsiDatabaseOpenView(hdb, query, &hview);
4718     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
4719     r = MsiViewExecute(hview, 0);
4720     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
4721     r = MsiViewFetch(hview, &hrec);
4722     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4723
4724     r = MsiRecordGetInteger(hrec, 1);
4725     ok(r == 1, "Expected 1, got %d\n", r);
4726     r = MsiRecordGetInteger(hrec, 2);
4727     ok(r == 0, "Expected 0, got %d\n", r);
4728
4729     r = MsiCloseHandle(hrec);
4730     ok(r == ERROR_SUCCESS, "failed to close record\n");
4731
4732     r = MsiViewFetch(hview, &hrec);
4733     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4734
4735     r = MsiRecordGetInteger(hrec, 1);
4736     ok(r == 3, "Expected 3, got %d\n", r);
4737     r = MsiRecordGetInteger(hrec, 2);
4738     ok(r == 0, "Expected 0, got %d\n", r);
4739
4740     r = MsiCloseHandle(hrec);
4741     ok(r == ERROR_SUCCESS, "failed to close record\n");
4742
4743     r = MsiViewFetch(hview, &hrec);
4744     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4745
4746     r = MsiRecordGetInteger(hrec, 1);
4747     ok(r == 5, "Expected 5, got %d\n", r);
4748     r = MsiRecordGetInteger(hrec, 2);
4749     ok(r == 0, "Expected 0, got %d\n", r);
4750
4751     r = MsiCloseHandle(hrec);
4752     ok(r == ERROR_SUCCESS, "failed to close record\n");
4753
4754     r = MsiViewFetch(hview, &hrec);
4755     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
4756
4757     r = MsiViewClose(hview);
4758     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4759     r = MsiCloseHandle(hview);
4760     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4761
4762     r = MsiCloseHandle( hdb );
4763     ok(r == ERROR_SUCCESS, "MsiOpenDatabase close failed\n");
4764 }
4765
4766 static void test_viewmodify_assign(void)
4767 {
4768     MSIHANDLE hdb = 0, hview = 0, hrec = 0;
4769     const char *query;
4770     UINT r;
4771
4772     /* setup database */
4773     DeleteFile(msifile);
4774
4775     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
4776     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
4777
4778     query = "CREATE TABLE `table` (`A` INT, `B` INT PRIMARY KEY `A`)";
4779     r = run_query( hdb, 0, query );
4780     ok(r == ERROR_SUCCESS, "query failed\n");
4781
4782     /* assign to view, new primary key */
4783     query = "SELECT * FROM `table`";
4784     r = MsiDatabaseOpenView(hdb, query, &hview);
4785     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
4786     r = MsiViewExecute(hview, 0);
4787     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
4788
4789     hrec = MsiCreateRecord(2);
4790     ok(hrec != 0, "MsiCreateRecord failed\n");
4791
4792     r = MsiRecordSetInteger(hrec, 1, 1);
4793     ok(r == ERROR_SUCCESS, "failed to set integer\n");
4794     r = MsiRecordSetInteger(hrec, 2, 2);
4795     ok(r == ERROR_SUCCESS, "failed to set integer\n");
4796
4797     r = MsiViewModify(hview, MSIMODIFY_ASSIGN, hrec);
4798     ok(r == ERROR_SUCCESS, "MsiViewModify failed: %d\n", r);
4799
4800     r = MsiCloseHandle(hrec);
4801     ok(r == ERROR_SUCCESS, "failed to close record\n");
4802
4803     r = MsiViewClose(hview);
4804     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4805     r = MsiCloseHandle(hview);
4806     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4807
4808     query = "SELECT * FROM `table`";
4809     r = MsiDatabaseOpenView(hdb, query, &hview);
4810     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
4811     r = MsiViewExecute(hview, 0);
4812     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
4813     r = MsiViewFetch(hview, &hrec);
4814     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4815
4816     r = MsiRecordGetInteger(hrec, 1);
4817     ok(r == 1, "Expected 1, got %d\n", r);
4818     r = MsiRecordGetInteger(hrec, 2);
4819     ok(r == 2, "Expected 2, got %d\n", r);
4820
4821     r = MsiCloseHandle(hrec);
4822     ok(r == ERROR_SUCCESS, "failed to close record\n");
4823
4824     r = MsiViewFetch(hview, &hrec);
4825     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
4826
4827     r = MsiViewClose(hview);
4828     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4829     r = MsiCloseHandle(hview);
4830     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4831
4832     /* assign to view, primary key matches */
4833     query = "SELECT * FROM `table`";
4834     r = MsiDatabaseOpenView(hdb, query, &hview);
4835     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
4836     r = MsiViewExecute(hview, 0);
4837     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
4838
4839     hrec = MsiCreateRecord(2);
4840     ok(hrec != 0, "MsiCreateRecord failed\n");
4841
4842     r = MsiRecordSetInteger(hrec, 1, 1);
4843     ok(r == ERROR_SUCCESS, "failed to set integer\n");
4844     r = MsiRecordSetInteger(hrec, 2, 4);
4845     ok(r == ERROR_SUCCESS, "failed to set integer\n");
4846
4847     r = MsiViewModify(hview, MSIMODIFY_ASSIGN, hrec);
4848     ok(r == ERROR_SUCCESS, "MsiViewModify failed: %d\n", r);
4849
4850     r = MsiCloseHandle(hrec);
4851     ok(r == ERROR_SUCCESS, "failed to close record\n");
4852
4853     r = MsiViewClose(hview);
4854     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4855     r = MsiCloseHandle(hview);
4856     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4857
4858     query = "SELECT * FROM `table`";
4859     r = MsiDatabaseOpenView(hdb, query, &hview);
4860     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
4861     r = MsiViewExecute(hview, 0);
4862     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
4863     r = MsiViewFetch(hview, &hrec);
4864     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4865
4866     r = MsiRecordGetInteger(hrec, 1);
4867     ok(r == 1, "Expected 1, got %d\n", r);
4868     r = MsiRecordGetInteger(hrec, 2);
4869     ok(r == 4, "Expected 4, got %d\n", r);
4870
4871     r = MsiCloseHandle(hrec);
4872     ok(r == ERROR_SUCCESS, "failed to close record\n");
4873
4874     r = MsiViewFetch(hview, &hrec);
4875     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
4876
4877     r = MsiViewClose(hview);
4878     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4879     r = MsiCloseHandle(hview);
4880     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4881
4882     /* close database */
4883     r = MsiCloseHandle( hdb );
4884     ok(r == ERROR_SUCCESS, "MsiOpenDatabase close failed\n");
4885 }
4886
4887 static const WCHAR data10[] = { /* MOO */
4888     0x8001, 0x000b,
4889 };
4890 static const WCHAR data11[] = { /* AAR */
4891     0x8002, 0x8005,
4892     0x000c, 0x000f,
4893 };
4894 static const char data12[] = /* _StringData */
4895     "MOOABAARCDonetwofourfive";
4896 static const WCHAR data13[] = { /* _StringPool */
4897 /*  len, refs */
4898     0,   0,    /* string 0 ''     */
4899     0,   0,    /* string 1 ''     */
4900     0,   0,    /* string 2 ''     */
4901     0,   0,    /* string 3 ''     */
4902     0,   0,    /* string 4 ''     */
4903     3,   3,    /* string 5 'MOO'  */
4904     1,   1,    /* string 6 'A'    */
4905     1,   1,    /* string 7 'B'    */
4906     3,   3,    /* string 8 'AAR'  */
4907     1,   1,    /* string 9 'C'    */
4908     1,   1,    /* string a 'D'    */
4909     3,   1,    /* string b 'one'  */
4910     3,   1,    /* string c 'two'  */
4911     0,   0,    /* string d ''     */
4912     4,   1,    /* string e 'four' */
4913     4,   1,    /* string f 'five' */
4914 };
4915
4916 static void test_stringtable(void)
4917 {
4918     MSIHANDLE hdb = 0, hview = 0, hrec = 0;
4919     IStorage *stg = NULL;
4920     IStream *stm;
4921     WCHAR name[0x20];
4922     HRESULT hr;
4923     const char *query;
4924     char buffer[MAX_PATH];
4925     WCHAR data[MAX_PATH];
4926     DWORD sz, read;
4927     UINT r;
4928
4929     static const DWORD mode = STGM_DIRECT | STGM_READ | STGM_SHARE_DENY_WRITE;
4930     static const WCHAR stringdata[] = {0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0}; /* _StringData */
4931     static const WCHAR stringpool[] = {0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0}; /* _StringPool */
4932     static const WCHAR moo[] = {0x4840, 0x3e16, 0x4818, 0}; /* MOO */
4933     static const WCHAR aar[] = {0x4840, 0x3a8a, 0x481b, 0}; /* AAR */
4934
4935     DeleteFile(msifile);
4936
4937     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
4938     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4939
4940     query = "CREATE TABLE `MOO` (`A` INT, `B` CHAR(72) PRIMARY KEY `A`)";
4941     r = run_query(hdb, 0, query);
4942     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4943
4944     query = "CREATE TABLE `AAR` (`C` INT, `D` CHAR(72) PRIMARY KEY `C`)";
4945     r = run_query(hdb, 0, query);
4946     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4947
4948     /* insert persistent row */
4949     query = "INSERT INTO `MOO` (`A`, `B`) VALUES (1, 'one')";
4950     r = run_query(hdb, 0, query);
4951     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4952
4953     /* insert persistent row */
4954     query = "INSERT INTO `AAR` (`C`, `D`) VALUES (2, 'two')";
4955     r = run_query(hdb, 0, query);
4956     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4957
4958     /* open a view */
4959     query = "SELECT * FROM `MOO`";
4960     r = MsiDatabaseOpenView(hdb, query, &hview);
4961     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4962     r = MsiViewExecute(hview, 0);
4963     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4964
4965     hrec = MsiCreateRecord(2);
4966
4967     r = MsiRecordSetInteger(hrec, 1, 3);
4968     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4969     r = MsiRecordSetString(hrec, 2, "three");
4970     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4971
4972     /* insert a nonpersistent row */
4973     r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec);
4974     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4975
4976     r = MsiCloseHandle(hrec);
4977     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4978     r = MsiViewClose(hview);
4979     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4980     r = MsiCloseHandle(hview);
4981     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4982
4983     /* insert persistent row */
4984     query = "INSERT INTO `MOO` (`A`, `B`) VALUES (4, 'four')";
4985     r = run_query(hdb, 0, query);
4986     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4987
4988     /* insert persistent row */
4989     query = "INSERT INTO `AAR` (`C`, `D`) VALUES (5, 'five')";
4990     r = run_query(hdb, 0, query);
4991     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4992
4993     r = MsiDatabaseCommit(hdb);
4994     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4995
4996     r = MsiCloseHandle(hdb);
4997     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4998
4999     r = MsiOpenDatabase(msifile, MSIDBOPEN_READONLY, &hdb);
5000     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5001
5002     query = "SELECT * FROM `MOO`";
5003     r = MsiDatabaseOpenView(hdb, query, &hview);
5004     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5005
5006     r = MsiViewExecute(hview, 0);
5007     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5008
5009     r = MsiViewFetch(hview, &hrec);
5010     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5011
5012     r = MsiRecordGetFieldCount(hrec);
5013     ok(r == 2, "Expected 2, got %d\n", r);
5014
5015     r = MsiRecordGetInteger(hrec, 1);
5016     ok(r == 1, "Expected 1, got %d\n", r);
5017
5018     sz = sizeof(buffer);
5019     r = MsiRecordGetString(hrec, 2, buffer, &sz);
5020     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5021     ok(!lstrcmp(buffer, "one"), "Expected one, got %s\n", buffer);
5022
5023     r = MsiCloseHandle(hrec);
5024     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5025
5026     r = MsiViewFetch(hview, &hrec);
5027     todo_wine
5028     {
5029         ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5030     }
5031
5032     r = MsiViewClose(hview);
5033     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5034     r = MsiCloseHandle(hview);
5035     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5036     r = MsiCloseHandle(hrec);
5037     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5038
5039     query = "SELECT * FROM `AAR`";
5040     r = MsiDatabaseOpenView(hdb, query, &hview);
5041     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5042
5043     r = MsiViewExecute(hview, 0);
5044     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5045
5046     r = MsiViewFetch(hview, &hrec);
5047     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5048
5049     r = MsiRecordGetFieldCount(hrec);
5050     ok(r == 2, "Expected 2, got %d\n", r);
5051
5052     r = MsiRecordGetInteger(hrec, 1);
5053     ok(r == 2, "Expected 2, got %d\n", r);
5054
5055     sz = sizeof(buffer);
5056     r = MsiRecordGetString(hrec, 2, buffer, &sz);
5057     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5058     ok(!lstrcmp(buffer, "two"), "Expected two, got %s\n", buffer);
5059
5060     r = MsiCloseHandle(hrec);
5061     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5062
5063     r = MsiViewFetch(hview, &hrec);
5064     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5065
5066     r = MsiRecordGetFieldCount(hrec);
5067     ok(r == 2, "Expected 2, got %d\n", r);
5068
5069     r = MsiRecordGetInteger(hrec, 1);
5070     ok(r == 5, "Expected 5, got %d\n", r);
5071
5072     sz = sizeof(buffer);
5073     r = MsiRecordGetString(hrec, 2, buffer, &sz);
5074     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5075     ok(!lstrcmp(buffer, "five"), "Expected five, got %s\n", buffer);
5076
5077     r = MsiCloseHandle(hrec);
5078     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5079
5080     r = MsiViewFetch(hview, &hrec);
5081     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5082
5083     r = MsiViewClose(hview);
5084     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5085     r = MsiCloseHandle(hview);
5086     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5087     r = MsiCloseHandle(hrec);
5088     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5089     r = MsiCloseHandle(hdb);
5090     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5091
5092     MultiByteToWideChar(CP_ACP, 0, msifile, -1, name, 0x20);
5093     hr = StgOpenStorage(name, NULL, mode, NULL, 0, &stg);
5094     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5095     ok(stg != NULL, "Expected non-NULL storage\n");
5096
5097     hr = IStorage_OpenStream(stg, moo, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm);
5098     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5099     ok(stm != NULL, "Expected non-NULL stream\n");
5100
5101     hr = IStream_Read(stm, data, MAX_PATH, &read);
5102     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5103     todo_wine
5104     {
5105         ok(read == 4, "Expected 4, got %d\n", read);
5106         ok(!memcmp(data, data10, read), "Unexpected data\n");
5107     }
5108
5109     hr = IStream_Release(stm);
5110     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5111
5112     hr = IStorage_OpenStream(stg, aar, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm);
5113     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5114     ok(stm != NULL, "Expected non-NULL stream\n");
5115
5116     hr = IStream_Read(stm, data, MAX_PATH, &read);
5117     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5118     ok(read == 8, "Expected 8, got %d\n", read);
5119     todo_wine
5120     {
5121         ok(!memcmp(data, data11, read), "Unexpected data\n");
5122     }
5123
5124     hr = IStream_Release(stm);
5125     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5126
5127     hr = IStorage_OpenStream(stg, stringdata, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm);
5128     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5129     ok(stm != NULL, "Expected non-NULL stream\n");
5130
5131     hr = IStream_Read(stm, buffer, MAX_PATH, &read);
5132     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5133     ok(read == 24, "Expected 24, got %d\n", read);
5134     ok(!memcmp(buffer, data12, read), "Unexpected data\n");
5135
5136     hr = IStream_Release(stm);
5137     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5138
5139     hr = IStorage_OpenStream(stg, stringpool, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm);
5140     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5141     ok(stm != NULL, "Expected non-NULL stream\n");
5142
5143     hr = IStream_Read(stm, data, MAX_PATH, &read);
5144     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5145     todo_wine
5146     {
5147         ok(read == 64, "Expected 64, got %d\n", read);
5148         ok(!memcmp(data, data13, read), "Unexpected data\n");
5149     }
5150
5151     hr = IStream_Release(stm);
5152     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5153
5154     hr = IStorage_Release(stg);
5155     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5156
5157     DeleteFileA(msifile);
5158 }
5159
5160 static void test_viewmodify_delete(void)
5161 {
5162     MSIHANDLE hdb = 0, hview = 0, hrec = 0;
5163     UINT r;
5164     const char *query;
5165     char buffer[0x100];
5166     DWORD sz;
5167
5168     DeleteFile(msifile);
5169
5170     /* just MsiOpenDatabase should not create a file */
5171     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
5172     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5173
5174     query = "CREATE TABLE `phone` ( "
5175             "`id` INT, `name` CHAR(32), `number` CHAR(32) "
5176             "PRIMARY KEY `id`)";
5177     r = run_query(hdb, 0, query);
5178     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5179
5180     query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
5181         "VALUES('1', 'Alan', '5030581')";
5182     r = run_query(hdb, 0, query);
5183     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5184
5185     query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
5186         "VALUES('2', 'Barry', '928440')";
5187     r = run_query(hdb, 0, query);
5188     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5189
5190     query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
5191         "VALUES('3', 'Cindy', '2937550')";
5192     r = run_query(hdb, 0, query);
5193     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5194
5195     query = "SELECT * FROM `phone` WHERE `id` <= 2";
5196     r = MsiDatabaseOpenView(hdb, query, &hview);
5197     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5198     r = MsiViewExecute(hview, 0);
5199     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5200     r = MsiViewFetch(hview, &hrec);
5201     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5202
5203     /* delete 1 */
5204     r = MsiViewModify(hview, MSIMODIFY_DELETE, hrec);
5205     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5206
5207     r = MsiCloseHandle(hrec);
5208     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5209     r = MsiViewFetch(hview, &hrec);
5210     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5211
5212     /* delete 2 */
5213     r = MsiViewModify(hview, MSIMODIFY_DELETE, hrec);
5214     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5215
5216     r = MsiCloseHandle(hrec);
5217     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5218     r = MsiViewClose(hview);
5219     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5220     r = MsiCloseHandle(hview);
5221     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5222
5223     query = "SELECT * FROM `phone`";
5224     r = MsiDatabaseOpenView(hdb, query, &hview);
5225     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5226     r = MsiViewExecute(hview, 0);
5227     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5228     r = MsiViewFetch(hview, &hrec);
5229     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5230
5231     r = MsiRecordGetInteger(hrec, 1);
5232     ok(r == 3, "Expected 3, got %d\n", r);
5233
5234     sz = sizeof(buffer);
5235     r = MsiRecordGetString(hrec, 2, buffer, &sz);
5236     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5237     ok(!lstrcmp(buffer, "Cindy"), "Expected Cindy, got %s\n", buffer);
5238
5239     sz = sizeof(buffer);
5240     r = MsiRecordGetString(hrec, 3, buffer, &sz);
5241     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5242     ok(!lstrcmp(buffer, "2937550"), "Expected 2937550, got %s\n", buffer);
5243
5244     r = MsiCloseHandle(hrec);
5245     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5246
5247     r = MsiViewFetch(hview, &hrec);
5248     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5249
5250     r = MsiViewClose(hview);
5251     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5252     r = MsiCloseHandle(hview);
5253     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5254     r = MsiCloseHandle(hdb);
5255     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5256 }
5257
5258 static const WCHAR _Tables[] = {0x4840, 0x3f7f, 0x4164, 0x422f, 0x4836, 0};
5259 static const WCHAR _StringData[] = {0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0};
5260 static const WCHAR _StringPool[] = {0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0};
5261
5262 static const WCHAR data14[] = { /* _StringPool */
5263 /*  len, refs */
5264     0,   0,    /* string 0 ''    */
5265 };
5266
5267 static const struct {
5268     LPCWSTR name;
5269     const void *data;
5270     DWORD size;
5271 } database_table_data[] =
5272 {
5273     {_Tables, NULL, 0},
5274     {_StringData, NULL, 0},
5275     {_StringPool, data14, sizeof data14},
5276 };
5277
5278 static void enum_stream_names(IStorage *stg)
5279 {
5280     IEnumSTATSTG *stgenum = NULL;
5281     IStream *stm;
5282     HRESULT hr;
5283     STATSTG stat;
5284     ULONG n, count;
5285     BYTE data[MAX_PATH];
5286     BYTE check[MAX_PATH];
5287     DWORD sz;
5288
5289     memset(check, 'a', MAX_PATH);
5290
5291     hr = IStorage_EnumElements(stg, 0, NULL, 0, &stgenum);
5292     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
5293
5294     n = 0;
5295     while(TRUE)
5296     {
5297         count = 0;
5298         hr = IEnumSTATSTG_Next(stgenum, 1, &stat, &count);
5299         if(FAILED(hr) || !count)
5300             break;
5301
5302         ok(!lstrcmpW(stat.pwcsName, database_table_data[n].name),
5303            "Expected table %d name to match\n", n);
5304
5305         stm = NULL;
5306         hr = IStorage_OpenStream(stg, stat.pwcsName, NULL,
5307                                  STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm);
5308         ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
5309         ok(stm != NULL, "Expected non-NULL stream\n");
5310
5311         sz = MAX_PATH;
5312         memset(data, 'a', MAX_PATH);
5313         hr = IStream_Read(stm, data, sz, &count);
5314         ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
5315
5316         ok(count == database_table_data[n].size,
5317            "Expected %d, got %d\n", database_table_data[n].size, count);
5318
5319         if (!database_table_data[n].size)
5320             ok(!memcmp(data, check, MAX_PATH), "data should not be changed\n");
5321         else
5322             ok(!memcmp(data, database_table_data[n].data, database_table_data[n].size),
5323                "Expected table %d data to match\n", n);
5324
5325         IStream_Release(stm);
5326         n++;
5327     }
5328
5329     ok(n == 3, "Expected 3, got %d\n", n);
5330
5331     IEnumSTATSTG_Release(stgenum);
5332 }
5333
5334 static void test_defaultdatabase(void)
5335 {
5336     UINT r;
5337     HRESULT hr;
5338     MSIHANDLE hdb;
5339     IStorage *stg = NULL;
5340
5341     static const WCHAR msifileW[] = {'w','i','n','e','t','e','s','t','.','m','s','i',0};
5342
5343     DeleteFile(msifile);
5344
5345     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
5346     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5347
5348     r = MsiDatabaseCommit(hdb);
5349     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5350
5351     MsiCloseHandle(hdb);
5352
5353     hr = StgOpenStorage(msifileW, NULL, STGM_READ | STGM_SHARE_DENY_WRITE, NULL, 0, &stg);
5354     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
5355     ok(stg != NULL, "Expected non-NULL stg\n");
5356
5357     enum_stream_names(stg);
5358
5359     IStorage_Release(stg);
5360     DeleteFileA(msifile);
5361 }
5362
5363 static void test_order(void)
5364 {
5365     MSIHANDLE hdb, hview, hrec;
5366     CHAR buffer[MAX_PATH];
5367     LPCSTR query;
5368     UINT r, sz;
5369     int val;
5370
5371     hdb = create_db();
5372     ok(hdb, "failed to create db\n");
5373
5374     query = "CREATE TABLE `Empty` ( `A` SHORT NOT NULL PRIMARY KEY `A`)";
5375     r = run_query(hdb, 0, query);
5376     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5377
5378     query = "CREATE TABLE `Mesa` ( `A` SHORT NOT NULL, `B` SHORT, `C` SHORT PRIMARY KEY `A`)";
5379     r = run_query(hdb, 0, query);
5380     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5381
5382     query = "INSERT INTO `Mesa` ( `A`, `B`, `C` ) VALUES ( 1, 2, 9 )";
5383     r = run_query(hdb, 0, query);
5384     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5385
5386     query = "INSERT INTO `Mesa` ( `A`, `B`, `C` ) VALUES ( 3, 4, 7 )";
5387     r = run_query(hdb, 0, query);
5388     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5389
5390     query = "INSERT INTO `Mesa` ( `A`, `B`, `C` ) VALUES ( 5, 6, 8 )";
5391     r = run_query(hdb, 0, query);
5392     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5393
5394     query = "CREATE TABLE `Sideboard` ( `D` SHORT NOT NULL, `E` SHORT, `F` SHORT PRIMARY KEY `D`)";
5395     r = run_query(hdb, 0, query);
5396     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5397
5398     query = "INSERT INTO `Sideboard` ( `D`, `E`, `F` ) VALUES ( 10, 11, 18 )";
5399     r = run_query(hdb, 0, query);
5400     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5401
5402     query = "INSERT INTO `Sideboard` ( `D`, `E`, `F` ) VALUES ( 12, 13, 16 )";
5403     r = run_query(hdb, 0, query);
5404     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5405
5406     query = "INSERT INTO `Sideboard` ( `D`, `E`, `F` ) VALUES ( 14, 15, 17 )";
5407     r = run_query(hdb, 0, query);
5408     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5409
5410     query = "SELECT `A`, `B` FROM `Mesa` ORDER BY `C`";
5411     r = MsiDatabaseOpenView(hdb, query, &hview);
5412     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5413     r = MsiViewExecute(hview, 0);
5414     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5415
5416     r = MsiViewFetch(hview, &hrec);
5417     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5418
5419     val = MsiRecordGetInteger(hrec, 1);
5420     ok(val == 3, "Expected 3, got %d\n", val);
5421
5422     val = MsiRecordGetInteger(hrec, 2);
5423     ok(val == 4, "Expected 3, got %d\n", val);
5424
5425     MsiCloseHandle(hrec);
5426
5427     r = MsiViewFetch(hview, &hrec);
5428     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5429
5430     val = MsiRecordGetInteger(hrec, 1);
5431     ok(val == 5, "Expected 5, got %d\n", val);
5432
5433     val = MsiRecordGetInteger(hrec, 2);
5434     ok(val == 6, "Expected 6, got %d\n", val);
5435
5436     MsiCloseHandle(hrec);
5437
5438     r = MsiViewFetch(hview, &hrec);
5439     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5440
5441     val = MsiRecordGetInteger(hrec, 1);
5442     ok(val == 1, "Expected 1, got %d\n", val);
5443
5444     val = MsiRecordGetInteger(hrec, 2);
5445     ok(val == 2, "Expected 2, got %d\n", val);
5446
5447     MsiCloseHandle(hrec);
5448
5449     r = MsiViewFetch(hview, &hrec);
5450     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5451
5452     MsiViewClose(hview);
5453     MsiCloseHandle(hview);
5454
5455     query = "SELECT `A`, `D` FROM `Mesa`, `Sideboard` ORDER BY `F`";
5456     r = MsiDatabaseOpenView(hdb, query, &hview);
5457     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5458     r = MsiViewExecute(hview, 0);
5459     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5460
5461     r = MsiViewFetch(hview, &hrec);
5462     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5463
5464     val = MsiRecordGetInteger(hrec, 1);
5465     ok(val == 1, "Expected 1, got %d\n", val);
5466
5467     val = MsiRecordGetInteger(hrec, 2);
5468     ok(val == 12, "Expected 12, got %d\n", val);
5469
5470     MsiCloseHandle(hrec);
5471
5472     r = MsiViewFetch(hview, &hrec);
5473     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5474
5475     val = MsiRecordGetInteger(hrec, 1);
5476     ok(val == 3, "Expected 3, got %d\n", val);
5477
5478     val = MsiRecordGetInteger(hrec, 2);
5479     ok(val == 12, "Expected 12, got %d\n", val);
5480
5481     MsiCloseHandle(hrec);
5482
5483     r = MsiViewFetch(hview, &hrec);
5484     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5485
5486     val = MsiRecordGetInteger(hrec, 1);
5487     ok(val == 5, "Expected 5, got %d\n", val);
5488
5489     val = MsiRecordGetInteger(hrec, 2);
5490     ok(val == 12, "Expected 12, got %d\n", val);
5491
5492     MsiCloseHandle(hrec);
5493
5494     r = MsiViewFetch(hview, &hrec);
5495     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5496
5497     val = MsiRecordGetInteger(hrec, 1);
5498     ok(val == 1, "Expected 1, got %d\n", val);
5499
5500     val = MsiRecordGetInteger(hrec, 2);
5501     ok(val == 14, "Expected 14, got %d\n", val);
5502
5503     MsiCloseHandle(hrec);
5504
5505     r = MsiViewFetch(hview, &hrec);
5506     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5507
5508     val = MsiRecordGetInteger(hrec, 1);
5509     ok(val == 3, "Expected 3, got %d\n", val);
5510
5511     val = MsiRecordGetInteger(hrec, 2);
5512     ok(val == 14, "Expected 14, got %d\n", val);
5513
5514     MsiCloseHandle(hrec);
5515
5516     r = MsiViewFetch(hview, &hrec);
5517     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5518
5519     val = MsiRecordGetInteger(hrec, 1);
5520     ok(val == 5, "Expected 5, got %d\n", val);
5521
5522     val = MsiRecordGetInteger(hrec, 2);
5523     ok(val == 14, "Expected 14, got %d\n", val);
5524
5525     MsiCloseHandle(hrec);
5526
5527     r = MsiViewFetch(hview, &hrec);
5528     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5529
5530     val = MsiRecordGetInteger(hrec, 1);
5531     ok(val == 1, "Expected 1, got %d\n", val);
5532
5533     val = MsiRecordGetInteger(hrec, 2);
5534     ok(val == 10, "Expected 10, got %d\n", val);
5535
5536     MsiCloseHandle(hrec);
5537
5538     r = MsiViewFetch(hview, &hrec);
5539     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5540
5541     val = MsiRecordGetInteger(hrec, 1);
5542     ok(val == 3, "Expected 3, got %d\n", val);
5543
5544     val = MsiRecordGetInteger(hrec, 2);
5545     ok(val == 10, "Expected 10, got %d\n", val);
5546
5547     MsiCloseHandle(hrec);
5548
5549     r = MsiViewFetch(hview, &hrec);
5550     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5551
5552     val = MsiRecordGetInteger(hrec, 1);
5553     ok(val == 5, "Expected 5, got %d\n", val);
5554
5555     val = MsiRecordGetInteger(hrec, 2);
5556     ok(val == 10, "Expected 10, got %d\n", val);
5557
5558     MsiCloseHandle(hrec);
5559
5560     r = MsiViewFetch(hview, &hrec);
5561     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5562
5563     MsiViewClose(hview);
5564     MsiCloseHandle(hview);
5565
5566     query = "SELECT * FROM `Empty` ORDER BY `A`";
5567     r = MsiDatabaseOpenView(hdb, query, &hview);
5568     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5569     r = MsiViewExecute(hview, 0);
5570     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5571
5572     r = MsiViewFetch(hview, &hrec);
5573     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5574
5575     MsiViewClose(hview);
5576     MsiCloseHandle(hview);
5577
5578     query = "CREATE TABLE `Buffet` ( `One` CHAR(72), `Two` SHORT PRIMARY KEY `One`)";
5579     r = run_query(hdb, 0, query);
5580     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5581
5582     query = "INSERT INTO `Buffet` ( `One`, `Two` ) VALUES ( 'uno',  2)";
5583     r = run_query(hdb, 0, query);
5584     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5585
5586     query = "INSERT INTO `Buffet` ( `One`, `Two` ) VALUES ( 'dos',  3)";
5587     r = run_query(hdb, 0, query);
5588     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5589
5590     query = "INSERT INTO `Buffet` ( `One`, `Two` ) VALUES ( 'tres',  1)";
5591     r = run_query(hdb, 0, query);
5592     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5593
5594     query = "SELECT * FROM `Buffet` WHERE `One` = 'dos' ORDER BY `Two`";
5595     r = MsiDatabaseOpenView(hdb, query, &hview);
5596     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5597     r = MsiViewExecute(hview, 0);
5598     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5599
5600     r = MsiViewFetch(hview, &hrec);
5601     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5602
5603     sz = sizeof(buffer);
5604     r = MsiRecordGetString(hrec, 1, buffer, &sz);
5605     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5606     ok(!lstrcmp(buffer, "dos"), "Expected \"dos\", got \"%s\"\n", buffer);
5607
5608     r = MsiRecordGetInteger(hrec, 2);
5609     ok(r == 3, "Expected 3, got %d\n", r);
5610
5611     MsiCloseHandle(hrec);
5612
5613     r = MsiViewFetch(hview, &hrec);
5614     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5615
5616     MsiViewClose(hview);
5617     MsiCloseHandle(hview);
5618     MsiCloseHandle(hdb);
5619 }
5620
5621 static void test_viewmodify_delete_temporary(void)
5622 {
5623     MSIHANDLE hdb, hview, hrec;
5624     const char *query;
5625     UINT r;
5626
5627     DeleteFile(msifile);
5628
5629     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
5630     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5631
5632     query = "CREATE TABLE `Table` ( `A` SHORT PRIMARY KEY `A` )";
5633     r = run_query(hdb, 0, query);
5634     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5635
5636     query = "SELECT * FROM `Table`";
5637     r = MsiDatabaseOpenView(hdb, query, &hview);
5638     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5639     r = MsiViewExecute(hview, 0);
5640     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5641
5642     hrec = MsiCreateRecord(1);
5643     MsiRecordSetInteger(hrec, 1, 1);
5644
5645     r = MsiViewModify(hview, MSIMODIFY_INSERT, hrec);
5646     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5647
5648     MsiCloseHandle(hrec);
5649
5650     hrec = MsiCreateRecord(1);
5651     MsiRecordSetInteger(hrec, 1, 2);
5652
5653     r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec);
5654     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5655
5656     MsiCloseHandle(hrec);
5657
5658     hrec = MsiCreateRecord(1);
5659     MsiRecordSetInteger(hrec, 1, 3);
5660
5661     r = MsiViewModify(hview, MSIMODIFY_INSERT, hrec);
5662     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5663
5664     MsiCloseHandle(hrec);
5665
5666     hrec = MsiCreateRecord(1);
5667     MsiRecordSetInteger(hrec, 1, 4);
5668
5669     r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec);
5670     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5671
5672     MsiCloseHandle(hrec);
5673     MsiViewClose(hview);
5674     MsiCloseHandle(hview);
5675
5676     query = "SELECT * FROM `Table` WHERE  `A` = 2";
5677     r = MsiDatabaseOpenView(hdb, query, &hview);
5678     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5679     r = MsiViewExecute(hview, 0);
5680     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5681     r = MsiViewFetch(hview, &hrec);
5682     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5683
5684     r = MsiViewModify(hview, MSIMODIFY_DELETE, hrec);
5685     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5686
5687     MsiCloseHandle(hrec);
5688     MsiViewClose(hview);
5689     MsiCloseHandle(hview);
5690
5691     query = "SELECT * FROM `Table` WHERE  `A` = 3";
5692     r = MsiDatabaseOpenView(hdb, query, &hview);
5693     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5694     r = MsiViewExecute(hview, 0);
5695     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5696     r = MsiViewFetch(hview, &hrec);
5697     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5698
5699     r = MsiViewModify(hview, MSIMODIFY_DELETE, hrec);
5700     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5701
5702     MsiCloseHandle(hrec);
5703     MsiViewClose(hview);
5704     MsiCloseHandle(hview);
5705
5706     query = "SELECT * FROM `Table` ORDER BY `A`";
5707     r = MsiDatabaseOpenView(hdb, query, &hview);
5708     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5709     r = MsiViewExecute(hview, 0);
5710     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5711
5712     r = MsiViewFetch(hview, &hrec);
5713     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5714
5715     r = MsiRecordGetInteger(hrec, 1);
5716     ok(r == 1, "Expected 1, got %d\n", r);
5717
5718     MsiCloseHandle(hrec);
5719
5720     r = MsiViewFetch(hview, &hrec);
5721     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5722
5723     r = MsiRecordGetInteger(hrec, 1);
5724     ok(r == 4, "Expected 4, got %d\n", r);
5725
5726     MsiCloseHandle(hrec);
5727
5728     r = MsiViewFetch(hview, &hrec);
5729     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5730
5731     MsiViewClose(hview);
5732     MsiCloseHandle(hview);
5733     MsiCloseHandle(hdb);
5734     DeleteFileA(msifile);
5735 }
5736
5737 static void test_deleterow(void)
5738 {
5739     MSIHANDLE hdb, hview, hrec;
5740     const char *query;
5741     char buf[MAX_PATH];
5742     UINT r;
5743     DWORD size;
5744
5745     DeleteFile(msifile);
5746
5747     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
5748     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5749
5750     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
5751     r = run_query(hdb, 0, query);
5752     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5753
5754     query = "INSERT INTO `Table` (`A`) VALUES ('one')";
5755     r = run_query(hdb, 0, query);
5756     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5757
5758     query = "INSERT INTO `Table` (`A`) VALUES ('two')";
5759     r = run_query(hdb, 0, query);
5760     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5761
5762     query = "DELETE FROM `Table` WHERE `A` = 'one'";
5763     r = run_query(hdb, 0, query);
5764     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5765
5766     r = MsiDatabaseCommit(hdb);
5767     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5768
5769     MsiCloseHandle(hdb);
5770
5771     r = MsiOpenDatabase(msifile, MSIDBOPEN_READONLY, &hdb);
5772     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5773
5774     query = "SELECT * FROM `Table`";
5775     r = MsiDatabaseOpenView(hdb, query, &hview);
5776     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5777     r = MsiViewExecute(hview, 0);
5778     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5779
5780     r = MsiViewFetch(hview, &hrec);
5781     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5782
5783     size = MAX_PATH;
5784     r = MsiRecordGetStringA(hrec, 1, buf, &size);
5785     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5786     ok(!lstrcmpA(buf, "two"), "Expected two, got %s\n", buf);
5787
5788     MsiCloseHandle(hrec);
5789
5790     r = MsiViewFetch(hview, &hrec);
5791     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5792
5793     MsiViewClose(hview);
5794     MsiCloseHandle(hview);
5795     MsiCloseHandle(hdb);
5796     DeleteFileA(msifile);
5797 }
5798
5799 static const CHAR import_dat[] = "A\n"
5800                                  "s72\n"
5801                                  "Table\tA\n"
5802                                  "This is a new 'string' ok\n";
5803
5804 static void test_quotes(void)
5805 {
5806     MSIHANDLE hdb, hview, hrec;
5807     const char *query;
5808     char buf[MAX_PATH];
5809     UINT r;
5810     DWORD size;
5811
5812     DeleteFile(msifile);
5813
5814     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
5815     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5816
5817     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
5818     r = run_query(hdb, 0, query);
5819     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5820
5821     query = "INSERT INTO `Table` ( `A` ) VALUES ( 'This is a 'string' ok' )";
5822     r = run_query(hdb, 0, query);
5823     ok(r == ERROR_BAD_QUERY_SYNTAX,
5824        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5825
5826     query = "INSERT INTO `Table` ( `A` ) VALUES ( \"This is a 'string' ok\" )";
5827     r = run_query(hdb, 0, query);
5828     ok(r == ERROR_BAD_QUERY_SYNTAX,
5829        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5830
5831     query = "INSERT INTO `Table` ( `A` ) VALUES ( \"test\" )";
5832     r = run_query(hdb, 0, query);
5833     ok(r == ERROR_BAD_QUERY_SYNTAX,
5834        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5835
5836     query = "INSERT INTO `Table` ( `A` ) VALUES ( 'This is a ''string'' ok' )";
5837     r = run_query(hdb, 0, query);
5838     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5839
5840     query = "INSERT INTO `Table` ( `A` ) VALUES ( 'This is a '''string''' ok' )";
5841     r = run_query(hdb, 0, query);
5842     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5843
5844     query = "INSERT INTO `Table` ( `A` ) VALUES ( 'This is a \'string\' ok' )";
5845     r = run_query(hdb, 0, query);
5846     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5847
5848     query = "INSERT INTO `Table` ( `A` ) VALUES ( 'This is a \"string\" ok' )";
5849     r = run_query(hdb, 0, query);
5850     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5851
5852     query = "SELECT * FROM `Table`";
5853     r = MsiDatabaseOpenView(hdb, query, &hview);
5854     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5855
5856     r = MsiViewExecute(hview, 0);
5857     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5858
5859     r = MsiViewFetch(hview, &hrec);
5860     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5861
5862     size = MAX_PATH;
5863     r = MsiRecordGetString(hrec, 1, buf, &size);
5864     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5865     ok(!lstrcmp(buf, "This is a \"string\" ok"),
5866        "Expected \"This is a \"string\" ok\", got %s\n", buf);
5867
5868     MsiCloseHandle(hrec);
5869
5870     r = MsiViewFetch(hview, &hrec);
5871     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5872
5873     MsiViewClose(hview);
5874     MsiCloseHandle(hview);
5875
5876     write_file("import.idt", import_dat, (sizeof(import_dat) - 1) * sizeof(char));
5877
5878     r = MsiDatabaseImportA(hdb, CURR_DIR, "import.idt");
5879     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5880
5881     DeleteFileA("import.idt");
5882
5883     query = "SELECT * FROM `Table`";
5884     r = MsiDatabaseOpenView(hdb, query, &hview);
5885     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5886
5887     r = MsiViewExecute(hview, 0);
5888     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5889
5890     r = MsiViewFetch(hview, &hrec);
5891     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5892
5893     size = MAX_PATH;
5894     r = MsiRecordGetString(hrec, 1, buf, &size);
5895     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5896     ok(!lstrcmp(buf, "This is a new 'string' ok"),
5897        "Expected \"This is a new 'string' ok\", got %s\n", buf);
5898
5899     MsiCloseHandle(hrec);
5900
5901     r = MsiViewFetch(hview, &hrec);
5902     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5903
5904     MsiViewClose(hview);
5905     MsiCloseHandle(hview);
5906     MsiCloseHandle(hdb);
5907     DeleteFileA(msifile);
5908 }
5909
5910 static void test_carriagereturn(void)
5911 {
5912     MSIHANDLE hdb, hview, hrec;
5913     const char *query;
5914     char buf[MAX_PATH];
5915     UINT r;
5916     DWORD size;
5917
5918     DeleteFile(msifile);
5919
5920     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
5921     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5922
5923     query = "CREATE TABLE `Table`\r ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
5924     r = run_query(hdb, 0, query);
5925     ok(r == ERROR_BAD_QUERY_SYNTAX,
5926        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5927
5928     query = "CREATE TABLE `Table` \r( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
5929     r = run_query(hdb, 0, query);
5930     ok(r == ERROR_BAD_QUERY_SYNTAX,
5931        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5932
5933     query = "CREATE\r TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
5934     r = run_query(hdb, 0, query);
5935     ok(r == ERROR_BAD_QUERY_SYNTAX,
5936        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5937
5938     query = "CREATE TABLE\r `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
5939     r = run_query(hdb, 0, query);
5940     ok(r == ERROR_BAD_QUERY_SYNTAX,
5941        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5942
5943     query = "CREATE TABLE `Table` (\r `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
5944     r = run_query(hdb, 0, query);
5945     ok(r == ERROR_BAD_QUERY_SYNTAX,
5946        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5947
5948     query = "CREATE TABLE `Table` ( `A`\r CHAR(72) NOT NULL PRIMARY KEY `A` )";
5949     r = run_query(hdb, 0, query);
5950     ok(r == ERROR_BAD_QUERY_SYNTAX,
5951        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5952
5953     query = "CREATE TABLE `Table` ( `A` CHAR(72)\r NOT NULL PRIMARY KEY `A` )";
5954     r = run_query(hdb, 0, query);
5955     ok(r == ERROR_BAD_QUERY_SYNTAX,
5956        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5957
5958     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT\r NULL PRIMARY KEY `A` )";
5959     r = run_query(hdb, 0, query);
5960     ok(r == ERROR_BAD_QUERY_SYNTAX,
5961        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5962
5963     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT \rNULL PRIMARY KEY `A` )";
5964     r = run_query(hdb, 0, query);
5965     ok(r == ERROR_BAD_QUERY_SYNTAX,
5966        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5967
5968     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL\r PRIMARY KEY `A` )";
5969     r = run_query(hdb, 0, query);
5970     ok(r == ERROR_BAD_QUERY_SYNTAX,
5971        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5972
5973     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL \rPRIMARY KEY `A` )";
5974     r = run_query(hdb, 0, query);
5975     ok(r == ERROR_BAD_QUERY_SYNTAX,
5976        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5977
5978     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY\r KEY `A` )";
5979     r = run_query(hdb, 0, query);
5980     ok(r == ERROR_BAD_QUERY_SYNTAX,
5981        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5982
5983     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY \rKEY `A` )";
5984     r = run_query(hdb, 0, query);
5985     ok(r == ERROR_BAD_QUERY_SYNTAX,
5986        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5987
5988     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY\r `A` )";
5989     r = run_query(hdb, 0, query);
5990     ok(r == ERROR_BAD_QUERY_SYNTAX,
5991        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5992
5993     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A`\r )";
5994     r = run_query(hdb, 0, query);
5995     ok(r == ERROR_BAD_QUERY_SYNTAX,
5996        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5997
5998     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )\r";
5999     r = run_query(hdb, 0, query);
6000     ok(r == ERROR_BAD_QUERY_SYNTAX,
6001        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6002
6003     query = "CREATE TABLE `\rOne` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6004     r = run_query(hdb, 0, query);
6005     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6006
6007     query = "CREATE TABLE `Tw\ro` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6008     r = run_query(hdb, 0, query);
6009     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6010
6011     query = "CREATE TABLE `Three\r` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6012     r = run_query(hdb, 0, query);
6013     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6014
6015     query = "CREATE TABLE `Four` ( `A\r` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6016     r = run_query(hdb, 0, query);
6017     ok(r == ERROR_BAD_QUERY_SYNTAX,
6018        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6019
6020     query = "CREATE TABLE `Four` ( `\rA` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6021     r = run_query(hdb, 0, query);
6022     ok(r == ERROR_BAD_QUERY_SYNTAX,
6023        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6024
6025     query = "CREATE TABLE `Four` ( `A` CHAR(72\r) NOT NULL PRIMARY KEY `A` )";
6026     r = run_query(hdb, 0, query);
6027     ok(r == ERROR_BAD_QUERY_SYNTAX,
6028        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6029
6030     query = "CREATE TABLE `Four` ( `A` CHAR(\r72) NOT NULL PRIMARY KEY `A` )";
6031     r = run_query(hdb, 0, query);
6032     ok(r == ERROR_BAD_QUERY_SYNTAX,
6033        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6034
6035     query = "CREATE TABLE `Four` ( `A` CHAR(72) NOT NULL PRIMARY KEY `\rA` )";
6036     r = run_query(hdb, 0, query);
6037     ok(r == ERROR_BAD_QUERY_SYNTAX,
6038        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6039
6040     query = "CREATE TABLE `Four` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A\r` )";
6041     r = run_query(hdb, 0, query);
6042     ok(r == ERROR_BAD_QUERY_SYNTAX,
6043        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6044
6045     query = "CREATE TABLE `Four` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A\r` )";
6046     r = run_query(hdb, 0, query);
6047     ok(r == ERROR_BAD_QUERY_SYNTAX,
6048        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6049
6050     query = "SELECT * FROM `_Tables`";
6051     r = MsiDatabaseOpenView(hdb, query, &hview);
6052     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6053     r = MsiViewExecute(hview, 0);
6054     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6055
6056     r = MsiViewFetch(hview, &hrec);
6057     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6058
6059     size = MAX_PATH;
6060     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6061     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6062     ok(!lstrcmpA(buf, "\rOne"), "Expected \"\\rOne\", got \"%s\"\n", buf);
6063
6064     MsiCloseHandle(hrec);
6065
6066     r = MsiViewFetch(hview, &hrec);
6067     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6068
6069     size = MAX_PATH;
6070     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6071     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6072     ok(!lstrcmpA(buf, "Tw\ro"), "Expected \"Tw\\ro\", got \"%s\"\n", buf);
6073
6074     MsiCloseHandle(hrec);
6075
6076     r = MsiViewFetch(hview, &hrec);
6077     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6078
6079     size = MAX_PATH;
6080     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6081     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6082     ok(!lstrcmpA(buf, "Three\r"), "Expected \"Three\r\", got \"%s\"\n", buf);
6083
6084     MsiCloseHandle(hrec);
6085
6086     r = MsiViewFetch(hview, &hrec);
6087     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6088
6089     MsiViewClose(hview);
6090     MsiCloseHandle(hview);
6091
6092     MsiCloseHandle(hdb);
6093     DeleteFileA(msifile);
6094 }
6095
6096 static void test_noquotes(void)
6097 {
6098     MSIHANDLE hdb, hview, hrec;
6099     const char *query;
6100     char buf[MAX_PATH];
6101     UINT r;
6102     DWORD size;
6103
6104     DeleteFile(msifile);
6105
6106     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
6107     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6108
6109     query = "CREATE TABLE Table ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6110     r = run_query(hdb, 0, query);
6111     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6112
6113     query = "CREATE TABLE `Table` ( A CHAR(72) NOT NULL PRIMARY KEY `A` )";
6114     r = run_query(hdb, 0, query);
6115     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6116
6117     query = "CREATE TABLE `Table2` ( `A` CHAR(72) NOT NULL PRIMARY KEY A )";
6118     r = run_query(hdb, 0, query);
6119     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6120
6121     query = "CREATE TABLE `Table3` ( A CHAR(72) NOT NULL PRIMARY KEY A )";
6122     r = run_query(hdb, 0, query);
6123     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6124
6125     query = "SELECT * FROM `_Tables`";
6126     r = MsiDatabaseOpenView(hdb, query, &hview);
6127     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6128     r = MsiViewExecute(hview, 0);
6129     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6130
6131     r = MsiViewFetch(hview, &hrec);
6132     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6133
6134     size = MAX_PATH;
6135     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6136     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6137     ok(!lstrcmpA(buf, "Table"), "Expected \"Table\", got \"%s\"\n", buf);
6138
6139     MsiCloseHandle(hrec);
6140
6141     r = MsiViewFetch(hview, &hrec);
6142     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6143
6144     size = MAX_PATH;
6145     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6146     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6147     ok(!lstrcmpA(buf, "Table2"), "Expected \"Table2\", got \"%s\"\n", buf);
6148
6149     MsiCloseHandle(hrec);
6150
6151     r = MsiViewFetch(hview, &hrec);
6152     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6153
6154     size = MAX_PATH;
6155     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6156     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6157     ok(!lstrcmpA(buf, "Table3"), "Expected \"Table3\", got \"%s\"\n", buf);
6158
6159     MsiCloseHandle(hrec);
6160
6161     r = MsiViewFetch(hview, &hrec);
6162     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6163
6164     MsiViewClose(hview);
6165     MsiCloseHandle(hview);
6166
6167     query = "SELECT * FROM `_Columns`";
6168     r = MsiDatabaseOpenView(hdb, query, &hview);
6169     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6170     r = MsiViewExecute(hview, 0);
6171     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6172
6173     r = MsiViewFetch(hview, &hrec);
6174     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6175
6176     size = MAX_PATH;
6177     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6178     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6179     ok(!lstrcmpA(buf, "Table"), "Expected \"Table\", got \"%s\"\n", buf);
6180
6181     r = MsiRecordGetInteger(hrec, 2);
6182     ok(r == 1, "Expected 1, got %d\n", r);
6183
6184     size = MAX_PATH;
6185     r = MsiRecordGetStringA(hrec, 3, buf, &size);
6186     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6187     ok(!lstrcmpA(buf, "A"), "Expected \"A\", got \"%s\"\n", buf);
6188
6189     MsiCloseHandle(hrec);
6190
6191     r = MsiViewFetch(hview, &hrec);
6192     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6193
6194     size = MAX_PATH;
6195     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6196     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6197     ok(!lstrcmpA(buf, "Table2"), "Expected \"Table2\", got \"%s\"\n", buf);
6198
6199     r = MsiRecordGetInteger(hrec, 2);
6200     ok(r == 1, "Expected 1, got %d\n", r);
6201
6202     size = MAX_PATH;
6203     r = MsiRecordGetStringA(hrec, 3, buf, &size);
6204     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6205     ok(!lstrcmpA(buf, "A"), "Expected \"A\", got \"%s\"\n", buf);
6206
6207     MsiCloseHandle(hrec);
6208
6209     r = MsiViewFetch(hview, &hrec);
6210     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6211
6212     size = MAX_PATH;
6213     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6214     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6215     ok(!lstrcmpA(buf, "Table3"), "Expected \"Table3\", got \"%s\"\n", buf);
6216
6217     r = MsiRecordGetInteger(hrec, 2);
6218     ok(r == 1, "Expected 1, got %d\n", r);
6219
6220     size = MAX_PATH;
6221     r = MsiRecordGetStringA(hrec, 3, buf, &size);
6222     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6223     ok(!lstrcmpA(buf, "A"), "Expected \"A\", got \"%s\"\n", buf);
6224
6225     MsiCloseHandle(hrec);
6226
6227     r = MsiViewFetch(hview, &hrec);
6228     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6229
6230     MsiViewClose(hview);
6231     MsiCloseHandle(hview);
6232
6233     query = "INSERT INTO Table ( `A` ) VALUES ( 'hi' )";
6234     r = run_query(hdb, 0, query);
6235     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6236
6237     query = "INSERT INTO `Table` ( A ) VALUES ( 'hi' )";
6238     r = run_query(hdb, 0, query);
6239     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6240
6241     query = "INSERT INTO `Table` ( `A` ) VALUES ( hi )";
6242     r = run_query(hdb, 0, query);
6243     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6244
6245     query = "SELECT * FROM Table WHERE `A` = 'hi'";
6246     r = run_query(hdb, 0, query);
6247     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6248
6249     query = "SELECT * FROM `Table` WHERE `A` = hi";
6250     r = run_query(hdb, 0, query);
6251     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6252
6253     query = "SELECT * FROM Table";
6254     r = run_query(hdb, 0, query);
6255     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6256
6257     query = "SELECT * FROM Table2";
6258     r = MsiDatabaseOpenView(hdb, query, &hview);
6259     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6260     r = MsiViewExecute(hview, 0);
6261     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6262
6263     r = MsiViewFetch(hview, &hrec);
6264     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6265
6266     MsiViewClose(hview);
6267     MsiCloseHandle(hview);
6268
6269     query = "SELECT * FROM `Table` WHERE A = 'hi'";
6270     r = MsiDatabaseOpenView(hdb, query, &hview);
6271     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6272     r = MsiViewExecute(hview, 0);
6273     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6274
6275     r = MsiViewFetch(hview, &hrec);
6276     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6277
6278     size = MAX_PATH;
6279     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6280     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6281     ok(!lstrcmpA(buf, "hi"), "Expected \"hi\", got \"%s\"\n", buf);
6282
6283     MsiCloseHandle(hrec);
6284
6285     r = MsiViewFetch(hview, &hrec);
6286     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6287
6288     MsiViewClose(hview);
6289     MsiCloseHandle(hview);
6290     MsiCloseHandle(hdb);
6291     DeleteFileA(msifile);
6292 }
6293
6294 static void read_file_data(LPCSTR filename, LPSTR buffer)
6295 {
6296     HANDLE file;
6297     DWORD read;
6298
6299     file = CreateFileA( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
6300     ZeroMemory(buffer, MAX_PATH);
6301     ReadFile(file, buffer, MAX_PATH, &read, NULL);
6302     CloseHandle(file);
6303 }
6304
6305 static void test_forcecodepage(void)
6306 {
6307     MSIHANDLE hdb;
6308     const char *query;
6309     char buffer[MAX_PATH];
6310     UINT r;
6311
6312     DeleteFile(msifile);
6313
6314     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
6315     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6316
6317     query = "SELECT * FROM `_ForceCodepage`";
6318     r = run_query(hdb, 0, query);
6319     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6320
6321     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6322     r = run_query(hdb, 0, query);
6323     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6324
6325     query = "SELECT * FROM `_ForceCodepage`";
6326     r = run_query(hdb, 0, query);
6327     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6328
6329     r = MsiDatabaseCommit(hdb);
6330     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6331
6332     query = "SELECT * FROM `_ForceCodepage`";
6333     r = run_query(hdb, 0, query);
6334     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6335
6336     MsiCloseHandle(hdb);
6337
6338     r = MsiOpenDatabase(msifile, MSIDBOPEN_DIRECT, &hdb);
6339     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6340
6341     query = "SELECT * FROM `_ForceCodepage`";
6342     r = run_query(hdb, 0, query);
6343     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6344
6345     r = MsiDatabaseExport(hdb, "_ForceCodepage", CURR_DIR, "forcecodepage.idt");
6346     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6347
6348     read_file_data("forcecodepage.idt", buffer);
6349     ok(!lstrcmpA(buffer, "\r\n\r\n0\t_ForceCodepage\r\n"),
6350        "Expected \"\r\n\r\n0\t_ForceCodepage\r\n\", got \"%s\"", buffer);
6351
6352     MsiCloseHandle(hdb);
6353     DeleteFileA(msifile);
6354     DeleteFileA("forcecodepage.idt");
6355 }
6356
6357 static void test_viewmodify_refresh(void)
6358 {
6359     MSIHANDLE hdb, hview, hrec;
6360     const char *query;
6361     char buffer[MAX_PATH];
6362     UINT r;
6363     DWORD size;
6364
6365     DeleteFile(msifile);
6366
6367     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
6368     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6369
6370     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL, `B` INT PRIMARY KEY `A` )";
6371     r = run_query(hdb, 0, query);
6372     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6373
6374     query = "INSERT INTO `Table` ( `A`, `B` ) VALUES ( 'hi', 1 )";
6375     r = run_query(hdb, 0, query);
6376     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6377
6378     query = "SELECT * FROM `Table`";
6379     r = MsiDatabaseOpenView(hdb, query, &hview);
6380     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6381     r = MsiViewExecute(hview, 0);
6382     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6383
6384     r = MsiViewFetch(hview, &hrec);
6385     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6386
6387     query = "UPDATE `Table` SET `B` = 2 WHERE `A` = 'hi'";
6388     r = run_query(hdb, 0, query);
6389     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6390
6391     r = MsiViewModify(hview, MSIMODIFY_REFRESH, hrec);
6392     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6393
6394     size = MAX_PATH;
6395     r = MsiRecordGetStringA(hrec, 1, buffer, &size);
6396     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6397     ok(!lstrcmpA(buffer, "hi"), "Expected \"hi\", got \"%s\"\n", buffer);
6398     ok(size == 2, "Expected 2, got %d\n", size);
6399
6400     r = MsiRecordGetInteger(hrec, 2);
6401     ok(r == 2, "Expected 2, got %d\n", r);
6402
6403     MsiCloseHandle(hrec);
6404     MsiViewClose(hview);
6405     MsiCloseHandle(hview);
6406
6407     query = "INSERT INTO `Table` ( `A`, `B` ) VALUES ( 'hello', 3 )";
6408     r = run_query(hdb, 0, query);
6409     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6410
6411     query = "SELECT * FROM `Table` WHERE `B` = 3";
6412     r = MsiDatabaseOpenView(hdb, query, &hview);
6413     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6414     r = MsiViewExecute(hview, 0);
6415     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6416
6417     r = MsiViewFetch(hview, &hrec);
6418     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6419
6420     query = "UPDATE `Table` SET `B` = 2 WHERE `A` = 'hello'";
6421     r = run_query(hdb, 0, query);
6422     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6423
6424     query = "INSERT INTO `Table` ( `A`, `B` ) VALUES ( 'hithere', 3 )";
6425     r = run_query(hdb, 0, query);
6426     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6427
6428     r = MsiViewModify(hview, MSIMODIFY_REFRESH, hrec);
6429     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6430
6431     size = MAX_PATH;
6432     r = MsiRecordGetStringA(hrec, 1, buffer, &size);
6433     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6434     ok(!lstrcmpA(buffer, "hello"), "Expected \"hello\", got \"%s\"\n", buffer);
6435     ok(size == 5, "Expected 5, got %d\n", size);
6436
6437     r = MsiRecordGetInteger(hrec, 2);
6438     ok(r == 2, "Expected 2, got %d\n", r);
6439
6440     MsiCloseHandle(hrec);
6441     MsiViewClose(hview);
6442     MsiCloseHandle(hview);
6443     MsiCloseHandle(hdb);
6444     DeleteFileA(msifile);
6445 }
6446
6447 static void test_where_viewmodify(void)
6448 {
6449     MSIHANDLE hdb, hview, hrec;
6450     const char *query;
6451     UINT r;
6452
6453     DeleteFile(msifile);
6454
6455     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
6456     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6457
6458     query = "CREATE TABLE `Table` ( `A` INT, `B` INT PRIMARY KEY `A` )";
6459     r = run_query(hdb, 0, query);
6460     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6461
6462     query = "INSERT INTO `Table` ( `A`, `B` ) VALUES ( 1, 2 )";
6463     r = run_query(hdb, 0, query);
6464     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6465
6466     query = "INSERT INTO `Table` ( `A`, `B` ) VALUES ( 3, 4 )";
6467     r = run_query(hdb, 0, query);
6468     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6469
6470     query = "INSERT INTO `Table` ( `A`, `B` ) VALUES ( 5, 6 )";
6471     r = run_query(hdb, 0, query);
6472     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6473
6474     /* `B` = 3 doesn't match, but the view shouldn't be executed */
6475     query = "SELECT * FROM `Table` WHERE `B` = 3";
6476     r = MsiDatabaseOpenView(hdb, query, &hview);
6477     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6478
6479     hrec = MsiCreateRecord(2);
6480     MsiRecordSetInteger(hrec, 1, 7);
6481     MsiRecordSetInteger(hrec, 2, 8);
6482
6483     r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec);
6484     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6485
6486     MsiCloseHandle(hrec);
6487     MsiViewClose(hview);
6488     MsiCloseHandle(hview);
6489
6490     query = "SELECT * FROM `Table` WHERE `A` = 7";
6491     r = MsiDatabaseOpenView(hdb, query, &hview);
6492     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6493     r = MsiViewExecute(hview, 0);
6494     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6495
6496     r = MsiViewFetch(hview, &hrec);
6497     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6498
6499     r = MsiRecordGetInteger(hrec, 1);
6500     ok(r == 7, "Expected 7, got %d\n", r);
6501
6502     r = MsiRecordGetInteger(hrec, 2);
6503     ok(r == 8, "Expected 8, got %d\n", r);
6504
6505     MsiRecordSetInteger(hrec, 2, 9);
6506
6507     r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
6508     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6509
6510     MsiCloseHandle(hrec);
6511     MsiViewClose(hview);
6512     MsiCloseHandle(hview);
6513
6514     query = "SELECT * FROM `Table` WHERE `A` = 7";
6515     r = MsiDatabaseOpenView(hdb, query, &hview);
6516     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6517     r = MsiViewExecute(hview, 0);
6518     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6519
6520     r = MsiViewFetch(hview, &hrec);
6521     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6522
6523     r = MsiRecordGetInteger(hrec, 1);
6524     ok(r == 7, "Expected 7, got %d\n", r);
6525
6526     r = MsiRecordGetInteger(hrec, 2);
6527     ok(r == 9, "Expected 9, got %d\n", r);
6528
6529     query = "UPDATE `Table` SET `B` = 10 WHERE `A` = 7";
6530     r = run_query(hdb, 0, query);
6531     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6532
6533     r = MsiViewModify(hview, MSIMODIFY_REFRESH, hrec);
6534     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6535
6536     r = MsiRecordGetInteger(hrec, 1);
6537     ok(r == 7, "Expected 7, got %d\n", r);
6538
6539     r = MsiRecordGetInteger(hrec, 2);
6540     ok(r == 10, "Expected 10, got %d\n", r);
6541
6542     MsiCloseHandle(hrec);
6543     MsiViewClose(hview);
6544     MsiCloseHandle(hview);
6545     MsiCloseHandle(hdb);
6546 }
6547
6548 static BOOL create_storage(LPCSTR name)
6549 {
6550     WCHAR nameW[MAX_PATH];
6551     IStorage *stg;
6552     IStream *stm;
6553     HRESULT hr;
6554     DWORD count;
6555     BOOL res = FALSE;
6556
6557     MultiByteToWideChar(CP_ACP, 0, name, -1, nameW, MAX_PATH);
6558     hr = StgCreateDocfile(nameW, STGM_CREATE | STGM_READWRITE |
6559                           STGM_DIRECT | STGM_SHARE_EXCLUSIVE, 0, &stg);
6560     if (FAILED(hr))
6561         return FALSE;
6562
6563     hr = IStorage_CreateStream(stg, nameW, STGM_WRITE | STGM_SHARE_EXCLUSIVE,
6564                                0, 0, &stm);
6565     if (FAILED(hr))
6566         goto done;
6567
6568     hr = IStream_Write(stm, "stgdata", 8, &count);
6569     if (SUCCEEDED(hr))
6570         res = TRUE;
6571
6572 done:
6573     IStream_Release(stm);
6574     IStorage_Release(stg);
6575
6576     return res;
6577 }
6578
6579 static void test_storages_table(void)
6580 {
6581     MSIHANDLE hdb, hview, hrec;
6582     IStorage *stg, *inner;
6583     IStream *stm;
6584     char file[MAX_PATH];
6585     char buf[MAX_PATH];
6586     WCHAR name[MAX_PATH];
6587     LPCSTR query;
6588     HRESULT hr;
6589     DWORD size;
6590     UINT r;
6591
6592     hdb = create_db();
6593     ok(hdb, "failed to create db\n");
6594
6595     r = MsiDatabaseCommit(hdb);
6596     ok(r == ERROR_SUCCESS , "Failed to commit database\n");
6597
6598     MsiCloseHandle(hdb);
6599
6600     r = MsiOpenDatabase(msifile, MSIDBOPEN_TRANSACT, &hdb);
6601     ok(r == ERROR_SUCCESS , "Failed to open database\n");
6602
6603     /* check the column types */
6604     hrec = get_column_info(hdb, "SELECT * FROM `_Storages`", MSICOLINFO_TYPES);
6605     ok(hrec, "failed to get column info hrecord\n");
6606     ok(check_record(hrec, 1, "s62"), "wrong hrecord type\n");
6607     ok(check_record(hrec, 2, "V0"), "wrong hrecord type\n");
6608
6609     MsiCloseHandle(hrec);
6610
6611     /* now try the names */
6612     hrec = get_column_info(hdb, "SELECT * FROM `_Storages`", MSICOLINFO_NAMES);
6613     ok(hrec, "failed to get column info hrecord\n");
6614     ok(check_record(hrec, 1, "Name"), "wrong hrecord type\n");
6615     ok(check_record(hrec, 2, "Data"), "wrong hrecord type\n");
6616
6617     MsiCloseHandle(hrec);
6618
6619     create_storage("storage.bin");
6620
6621     hrec = MsiCreateRecord(2);
6622     MsiRecordSetString(hrec, 1, "stgname");
6623
6624     r = MsiRecordSetStream(hrec, 2, "storage.bin");
6625     ok(r == ERROR_SUCCESS, "Failed to add stream data to the hrecord: %d\n", r);
6626
6627     DeleteFileA("storage.bin");
6628
6629     query = "INSERT INTO `_Storages` (`Name`, `Data`) VALUES (?, ?)";
6630     r = MsiDatabaseOpenView(hdb, query, &hview);
6631     ok(r == ERROR_SUCCESS, "Failed to open database hview: %d\n", r);
6632
6633     r = MsiViewExecute(hview, hrec);
6634     ok(r == ERROR_SUCCESS, "Failed to execute hview: %d\n", r);
6635
6636     MsiCloseHandle(hrec);
6637     MsiViewClose(hview);
6638     MsiCloseHandle(hview);
6639
6640     query = "SELECT `Name`, `Data` FROM `_Storages`";
6641     r = MsiDatabaseOpenView(hdb, query, &hview);
6642     ok(r == ERROR_SUCCESS, "Failed to open database hview: %d\n", r);
6643
6644     r = MsiViewExecute(hview, 0);
6645     ok(r == ERROR_SUCCESS, "Failed to execute hview: %d\n", r);
6646
6647     r = MsiViewFetch(hview, &hrec);
6648     ok(r == ERROR_SUCCESS, "Failed to fetch hrecord: %d\n", r);
6649
6650     size = MAX_PATH;
6651     r = MsiRecordGetString(hrec, 1, file, &size);
6652     ok(r == ERROR_SUCCESS, "Failed to get string: %d\n", r);
6653     ok(!lstrcmp(file, "stgname"), "Expected \"stgname\", got \"%s\"\n", file);
6654
6655     size = MAX_PATH;
6656     lstrcpyA(buf, "apple");
6657     r = MsiRecordReadStream(hrec, 2, buf, &size);
6658     ok(r == ERROR_INVALID_DATA, "Expected ERROR_INVALID_DATA, got %d\n", r);
6659     ok(!lstrcmp(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf);
6660     ok(size == 0, "Expected 0, got %d\n", size);
6661
6662     MsiCloseHandle(hrec);
6663
6664     r = MsiViewFetch(hview, &hrec);
6665     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6666
6667     MsiViewClose(hview);
6668     MsiCloseHandle(hview);
6669
6670     MsiDatabaseCommit(hdb);
6671     MsiCloseHandle(hdb);
6672
6673     MultiByteToWideChar(CP_ACP, 0, msifile, -1, name, MAX_PATH);
6674     hr = StgOpenStorage(name, NULL, STGM_DIRECT | STGM_READ |
6675                         STGM_SHARE_DENY_WRITE, NULL, 0, &stg);
6676     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
6677     ok(stg != NULL, "Expected non-NULL storage\n");
6678
6679     MultiByteToWideChar(CP_ACP, 0, "stgname", -1, name, MAX_PATH);
6680     hr = IStorage_OpenStorage(stg, name, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE,
6681                               NULL, 0, &inner);
6682     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
6683     ok(inner != NULL, "Expected non-NULL storage\n");
6684
6685     MultiByteToWideChar(CP_ACP, 0, "storage.bin", -1, name, MAX_PATH);
6686     hr = IStorage_OpenStream(inner, name, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm);
6687     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
6688     ok(stm != NULL, "Expected non-NULL stream\n");
6689
6690     hr = IStream_Read(stm, buf, MAX_PATH, &size);
6691     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
6692     ok(size == 8, "Expected 8, got %d\n", size);
6693     ok(!lstrcmpA(buf, "stgdata"), "Expected \"stgdata\", got \"%s\"\n", buf);
6694
6695     IStream_Release(stm);
6696     IStorage_Release(inner);
6697
6698     IStorage_Release(stg);
6699     DeleteFileA(msifile);
6700 }
6701
6702 static void test_dbtopackage(void)
6703 {
6704     MSIHANDLE hdb, hpkg;
6705     CHAR package[10];
6706     CHAR buf[MAX_PATH];
6707     DWORD size;
6708     UINT r;
6709
6710     /* create an empty database, transact mode */
6711     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
6712     ok(r == ERROR_SUCCESS, "Failed to create database\n");
6713
6714     set_summary_info(hdb);
6715
6716     r = create_directory_table(hdb);
6717     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6718
6719     r = create_custom_action_table(hdb);
6720     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6721
6722     r = add_custom_action_entry(hdb, "'SetProp', 51, 'MYPROP', 'grape'");
6723     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6724
6725     sprintf(package, "#%i", hdb);
6726     r = MsiOpenPackage(package, &hpkg);
6727     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6728
6729     /* property is not set yet */
6730     size = MAX_PATH;
6731     lstrcpyA(buf, "kiwi");
6732     r = MsiGetProperty(hpkg, "MYPROP", buf, &size);
6733     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6734     ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf);
6735     ok(size == 0, "Expected 0, got %d\n", size);
6736
6737     /* run the custom action to set the property */
6738     r = MsiDoAction(hpkg, "SetProp");
6739     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6740
6741     /* property is now set */
6742     size = MAX_PATH;
6743     lstrcpyA(buf, "kiwi");
6744     r = MsiGetProperty(hpkg, "MYPROP", buf, &size);
6745     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6746     ok(!lstrcmpA(buf, "grape"), "Expected \"grape\", got \"%s\"\n", buf);
6747     ok(size == 5, "Expected 5, got %d\n", size);
6748
6749     MsiCloseHandle(hpkg);
6750
6751     /* reset the package */
6752     r = MsiOpenPackage(package, &hpkg);
6753     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6754
6755     /* property is not set anymore */
6756     size = MAX_PATH;
6757     lstrcpyA(buf, "kiwi");
6758     r = MsiGetProperty(hpkg, "MYPROP", buf, &size);
6759     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6760     todo_wine
6761     {
6762         ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf);
6763         ok(size == 0, "Expected 0, got %d\n", size);
6764     }
6765
6766     MsiCloseHandle(hdb);
6767     MsiCloseHandle(hpkg);
6768
6769     /* create an empty database, direct mode */
6770     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATEDIRECT, &hdb);
6771     ok(r == ERROR_SUCCESS, "Failed to create database\n");
6772
6773     set_summary_info(hdb);
6774
6775     r = create_directory_table(hdb);
6776     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6777
6778     r = create_custom_action_table(hdb);
6779     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6780
6781     r = add_custom_action_entry(hdb, "'SetProp', 51, 'MYPROP', 'grape'");
6782     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6783
6784     sprintf(package, "#%i", hdb);
6785     r = MsiOpenPackage(package, &hpkg);
6786     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6787
6788     /* property is not set yet */
6789     size = MAX_PATH;
6790     lstrcpyA(buf, "kiwi");
6791     r = MsiGetProperty(hpkg, "MYPROP", buf, &size);
6792     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6793     ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf);
6794     ok(size == 0, "Expected 0, got %d\n", size);
6795
6796     /* run the custom action to set the property */
6797     r = MsiDoAction(hpkg, "SetProp");
6798     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6799
6800     /* property is now set */
6801     size = MAX_PATH;
6802     lstrcpyA(buf, "kiwi");
6803     r = MsiGetProperty(hpkg, "MYPROP", buf, &size);
6804     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6805     ok(!lstrcmpA(buf, "grape"), "Expected \"grape\", got \"%s\"\n", buf);
6806     ok(size == 5, "Expected 5, got %d\n", size);
6807
6808     MsiCloseHandle(hpkg);
6809
6810     /* reset the package */
6811     r = MsiOpenPackage(package, &hpkg);
6812     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6813
6814     /* property is not set anymore */
6815     size = MAX_PATH;
6816     lstrcpyA(buf, "kiwi");
6817     r = MsiGetProperty(hpkg, "MYPROP", buf, &size);
6818     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6819     todo_wine
6820     {
6821         ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf);
6822         ok(size == 0, "Expected 0, got %d\n", size);
6823     }
6824
6825     MsiCloseHandle(hdb);
6826     MsiCloseHandle(hpkg);
6827     DeleteFileA(msifile);
6828 }
6829
6830 static void test_droptable(void)
6831 {
6832     MSIHANDLE hdb, hview, hrec;
6833     CHAR buf[MAX_PATH];
6834     LPCSTR query;
6835     DWORD size;
6836     UINT r;
6837
6838     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
6839     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6840
6841     query = "CREATE TABLE `One` ( `A` INT PRIMARY KEY `A` )";
6842     r = run_query(hdb, 0, query);
6843     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6844
6845     query = "SELECT * FROM `One`";
6846     r = do_query(hdb, query, &hrec);
6847     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6848
6849     query = "SELECT * FROM `_Tables` WHERE `Name` = 'One'";
6850     r = MsiDatabaseOpenViewA(hdb, query, &hview);
6851     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6852     r = MsiViewExecute(hview, 0);
6853     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6854
6855     r = MsiViewFetch(hview, &hrec);
6856     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6857
6858     size = MAX_PATH;
6859     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6860     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6861     ok(!lstrcmpA(buf, "One"), "Expected \"One\", got \"%s\"\n", buf);
6862
6863     MsiCloseHandle(hrec);
6864     MsiViewClose(hview);
6865     MsiCloseHandle(hview);
6866
6867     query = "SELECT * FROM `_Columns` WHERE `Table` = 'One'";
6868     r = MsiDatabaseOpenViewA(hdb, query, &hview);
6869     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6870     r = MsiViewExecute(hview, 0);
6871     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6872
6873     r = MsiViewFetch(hview, &hrec);
6874     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6875
6876     size = MAX_PATH;
6877     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6878     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6879     ok(!lstrcmpA(buf, "One"), "Expected \"One\", got \"%s\"\n", buf);
6880
6881     r = MsiRecordGetInteger(hrec, 2);
6882     ok(r == 1, "Expected 1, got %d\n", r);
6883
6884     size = MAX_PATH;
6885     r = MsiRecordGetStringA(hrec, 3, buf, &size);
6886     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6887     ok(!lstrcmpA(buf, "A"), "Expected \"A\", got \"%s\"\n", buf);
6888
6889     MsiCloseHandle(hrec);
6890
6891     r = MsiViewFetch(hview, &hrec);
6892     ok(r == ERROR_NO_MORE_ITEMS,
6893        "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6894
6895     MsiViewClose(hview);
6896     MsiCloseHandle(hview);
6897
6898     query = "DROP `One`";
6899     r = run_query(hdb, 0, query);
6900     ok(r == ERROR_BAD_QUERY_SYNTAX,
6901        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6902
6903     query = "DROP TABLE";
6904     r = run_query(hdb, 0, query);
6905     ok(r == ERROR_BAD_QUERY_SYNTAX,
6906        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6907
6908     query = "DROP TABLE `One`";
6909     hview = 0;
6910     r = MsiDatabaseOpenViewA(hdb, query, &hview);
6911     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6912     r = MsiViewExecute(hview, 0);
6913     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6914
6915     r = MsiViewFetch(hview, &hrec);
6916     ok(r == ERROR_FUNCTION_FAILED,
6917        "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
6918
6919     MsiViewClose(hview);
6920     MsiCloseHandle(hview);
6921
6922     query = "SELECT * FROM `IDontExist`";
6923     r = do_query(hdb, query, &hrec);
6924     ok(r == ERROR_BAD_QUERY_SYNTAX,
6925        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6926
6927     query = "SELECT * FROM `One`";
6928     r = do_query(hdb, query, &hrec);
6929     ok(r == ERROR_BAD_QUERY_SYNTAX,
6930        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6931
6932     query = "CREATE TABLE `One` ( `A` INT PRIMARY KEY `A` )";
6933     r = run_query(hdb, 0, query);
6934     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6935
6936     query = "DROP TABLE One";
6937     r = run_query(hdb, 0, query);
6938     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6939
6940     query = "SELECT * FROM `One`";
6941     r = do_query(hdb, query, &hrec);
6942     ok(r == ERROR_BAD_QUERY_SYNTAX,
6943        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6944
6945     query = "SELECT * FROM `_Tables` WHERE `Name` = 'One'";
6946     r = do_query(hdb, query, &hrec);
6947     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6948
6949     query = "SELECT * FROM `_Columns` WHERE `Table` = 'One'";
6950     r = do_query(hdb, query, &hrec);
6951     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6952
6953     query = "CREATE TABLE `One` ( `B` INT, `C` INT PRIMARY KEY `B` )";
6954     r = run_query(hdb, 0, query);
6955     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6956
6957     query = "SELECT * FROM `One`";
6958     r = do_query(hdb, query, &hrec);
6959     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6960
6961     query = "SELECT * FROM `_Tables` WHERE `Name` = 'One'";
6962     r = MsiDatabaseOpenViewA(hdb, query, &hview);
6963     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6964     r = MsiViewExecute(hview, 0);
6965     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6966
6967     r = MsiViewFetch(hview, &hrec);
6968     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6969
6970     size = MAX_PATH;
6971     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6972     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6973     ok(!lstrcmpA(buf, "One"), "Expected \"One\", got \"%s\"\n", buf);
6974
6975     MsiCloseHandle(hrec);
6976     MsiViewClose(hview);
6977     MsiCloseHandle(hview);
6978
6979     query = "SELECT * FROM `_Columns` WHERE `Table` = 'One'";
6980     r = MsiDatabaseOpenViewA(hdb, query, &hview);
6981     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6982     r = MsiViewExecute(hview, 0);
6983     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6984
6985     r = MsiViewFetch(hview, &hrec);
6986     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6987
6988     size = MAX_PATH;
6989     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6990     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6991     ok(!lstrcmpA(buf, "One"), "Expected \"One\", got \"%s\"\n", buf);
6992
6993     r = MsiRecordGetInteger(hrec, 2);
6994     ok(r == 1, "Expected 1, got %d\n", r);
6995
6996     size = MAX_PATH;
6997     r = MsiRecordGetStringA(hrec, 3, buf, &size);
6998     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6999     ok(!lstrcmpA(buf, "B"), "Expected \"B\", 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, "One"), "Expected \"One\", got \"%s\"\n", buf);
7010
7011     r = MsiRecordGetInteger(hrec, 2);
7012     ok(r == 2, "Expected 2, got %d\n", r);
7013
7014     size = MAX_PATH;
7015     r = MsiRecordGetStringA(hrec, 3, buf, &size);
7016     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7017     ok(!lstrcmpA(buf, "C"), "Expected \"C\", got \"%s\"\n", buf);
7018
7019     MsiCloseHandle(hrec);
7020
7021     r = MsiViewFetch(hview, &hrec);
7022     ok(r == ERROR_NO_MORE_ITEMS,
7023        "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7024
7025     MsiViewClose(hview);
7026     MsiCloseHandle(hview);
7027
7028     query = "DROP TABLE One";
7029     r = run_query(hdb, 0, query);
7030     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7031
7032     query = "SELECT * FROM `One`";
7033     r = do_query(hdb, query, &hrec);
7034     ok(r == ERROR_BAD_QUERY_SYNTAX,
7035        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7036
7037     query = "SELECT * FROM `_Tables` WHERE `Name` = 'One'";
7038     r = do_query(hdb, query, &hrec);
7039     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7040
7041     query = "SELECT * FROM `_Columns` WHERE `Table` = 'One'";
7042     r = do_query(hdb, query, &hrec);
7043     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7044
7045     MsiCloseHandle(hdb);
7046     DeleteFileA(msifile);
7047 }
7048
7049 static void test_dbmerge(void)
7050 {
7051     MSIHANDLE hdb, href, hview, hrec;
7052     CHAR buf[MAX_PATH];
7053     LPCSTR query;
7054     DWORD size;
7055     UINT r;
7056
7057     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
7058     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7059
7060     r = MsiOpenDatabase("refdb.msi", MSIDBOPEN_CREATE, &href);
7061     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7062
7063     /* hDatabase is invalid */
7064     r = MsiDatabaseMergeA(0, href, "MergeErrors");
7065     ok(r == ERROR_INVALID_HANDLE,
7066        "Expected ERROR_INVALID_HANDLE, got %d\n", r);
7067
7068     /* hDatabaseMerge is invalid */
7069     r = MsiDatabaseMergeA(hdb, 0, "MergeErrors");
7070     ok(r == ERROR_INVALID_HANDLE,
7071        "Expected ERROR_INVALID_HANDLE, got %d\n", r);
7072
7073     /* szTableName is NULL */
7074     r = MsiDatabaseMergeA(hdb, href, NULL);
7075     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7076
7077     /* szTableName is empty */
7078     r = MsiDatabaseMergeA(hdb, href, "");
7079     ok(r == ERROR_INVALID_TABLE, "Expected ERROR_INVALID_TABLE, got %d\n", r);
7080
7081     /* both DBs empty, szTableName is valid */
7082     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7083     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7084
7085     query = "CREATE TABLE `One` ( `A` INT PRIMARY KEY `A` )";
7086     r = run_query(hdb, 0, query);
7087     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7088
7089     query = "CREATE TABLE `One` ( `A` CHAR(72) PRIMARY KEY `A` )";
7090     r = run_query(href, 0, query);
7091     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7092
7093     /* column types don't match */
7094     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7095     ok(r == ERROR_DATATYPE_MISMATCH,
7096        "Expected ERROR_DATATYPE_MISMATCH, got %d\n", r);
7097
7098     /* nothing in MergeErrors */
7099     query = "SELECT * FROM `MergeErrors`";
7100     r = do_query(hdb, query, &hrec);
7101     ok(r == ERROR_BAD_QUERY_SYNTAX,
7102        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7103
7104     query = "DROP TABLE `One`";
7105     r = run_query(hdb, 0, query);
7106     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7107
7108     query = "DROP TABLE `One`";
7109     r = run_query(href, 0, query);
7110     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7111
7112     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A` )";
7113     r = run_query(hdb, 0, query);
7114     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7115
7116     query = "CREATE TABLE `One` ( `A` INT, `C` INT PRIMARY KEY `A` )";
7117     r = run_query(href, 0, query);
7118     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7119
7120     /* column names don't match */
7121     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7122     ok(r == ERROR_DATATYPE_MISMATCH,
7123        "Expected ERROR_DATATYPE_MISMATCH, got %d\n", r);
7124
7125     /* nothing in MergeErrors */
7126     query = "SELECT * FROM `MergeErrors`";
7127     r = do_query(hdb, query, &hrec);
7128     ok(r == ERROR_BAD_QUERY_SYNTAX,
7129        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7130
7131     query = "DROP TABLE `One`";
7132     r = run_query(hdb, 0, query);
7133     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7134
7135     query = "DROP TABLE `One`";
7136     r = run_query(href, 0, query);
7137     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7138
7139     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A` )";
7140     r = run_query(hdb, 0, query);
7141     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7142
7143     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `B` )";
7144     r = run_query(href, 0, query);
7145     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7146
7147     /* primary keys don't match */
7148     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7149     ok(r == ERROR_DATATYPE_MISMATCH,
7150        "Expected ERROR_DATATYPE_MISMATCH, got %d\n", r);
7151
7152     /* nothing in MergeErrors */
7153     query = "SELECT * FROM `MergeErrors`";
7154     r = do_query(hdb, query, &hrec);
7155     ok(r == ERROR_BAD_QUERY_SYNTAX,
7156        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7157
7158     query = "DROP TABLE `One`";
7159     r = run_query(hdb, 0, query);
7160     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7161
7162     query = "DROP TABLE `One`";
7163     r = run_query(href, 0, query);
7164     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7165
7166     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A` )";
7167     r = run_query(hdb, 0, query);
7168     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7169
7170     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A`, `B` )";
7171     r = run_query(href, 0, query);
7172     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7173
7174     /* number of primary keys doesn't match */
7175     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7176     ok(r == ERROR_DATATYPE_MISMATCH,
7177        "Expected ERROR_DATATYPE_MISMATCH, got %d\n", r);
7178
7179     /* nothing in MergeErrors */
7180     query = "SELECT * FROM `MergeErrors`";
7181     r = do_query(hdb, query, &hrec);
7182     ok(r == ERROR_BAD_QUERY_SYNTAX,
7183        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7184
7185     query = "DROP TABLE `One`";
7186     r = run_query(hdb, 0, query);
7187     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7188
7189     query = "DROP TABLE `One`";
7190     r = run_query(href, 0, query);
7191     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7192
7193     query = "CREATE TABLE `One` ( `A` INT, `B` INT, `C` INT PRIMARY KEY `A` )";
7194     r = run_query(hdb, 0, query);
7195     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7196
7197     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A` )";
7198     r = run_query(href, 0, query);
7199     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7200
7201     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 1, 2 )";
7202     r = run_query(href, 0, query);
7203     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7204
7205     /* number of columns doesn't match */
7206     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7207     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7208
7209     query = "SELECT * FROM `One`";
7210     r = do_query(hdb, query, &hrec);
7211     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7212
7213     r = MsiRecordGetInteger(hrec, 1);
7214     ok(r == 1, "Expected 1, got %d\n", r);
7215
7216     r = MsiRecordGetInteger(hrec, 2);
7217     ok(r == 2, "Expected 2, got %d\n", r);
7218
7219     r = MsiRecordGetInteger(hrec, 3);
7220     ok(r == MSI_NULL_INTEGER, "Expected MSI_NULL_INTEGER, got %d\n", r);
7221
7222     MsiCloseHandle(hrec);
7223
7224     /* nothing in MergeErrors */
7225     query = "SELECT * FROM `MergeErrors`";
7226     r = do_query(hdb, query, &hrec);
7227     ok(r == ERROR_BAD_QUERY_SYNTAX,
7228        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7229
7230     query = "DROP TABLE `One`";
7231     r = run_query(hdb, 0, query);
7232     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7233
7234     query = "DROP TABLE `One`";
7235     r = run_query(href, 0, query);
7236     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7237
7238     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A` )";
7239     r = run_query(hdb, 0, query);
7240     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7241
7242     query = "CREATE TABLE `One` ( `A` INT, `B` INT, `C` INT PRIMARY KEY `A` )";
7243     r = run_query(href, 0, query);
7244     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7245
7246     query = "INSERT INTO `One` ( `A`, `B`, `C` ) VALUES ( 1, 2, 3 )";
7247     r = run_query(href, 0, query);
7248     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7249
7250     /* number of columns doesn't match */
7251     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7252     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7253
7254     query = "SELECT * FROM `One`";
7255     r = do_query(hdb, query, &hrec);
7256     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7257
7258     r = MsiRecordGetInteger(hrec, 1);
7259     ok(r == 1, "Expected 1, got %d\n", r);
7260
7261     r = MsiRecordGetInteger(hrec, 2);
7262     ok(r == 2, "Expected 2, got %d\n", r);
7263
7264     r = MsiRecordGetInteger(hrec, 3);
7265     ok(r == MSI_NULL_INTEGER, "Expected MSI_NULL_INTEGER, got %d\n", r);
7266
7267     MsiCloseHandle(hrec);
7268
7269     /* nothing in MergeErrors */
7270     query = "SELECT * FROM `MergeErrors`";
7271     r = do_query(hdb, query, &hrec);
7272     ok(r == ERROR_BAD_QUERY_SYNTAX,
7273        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7274
7275     query = "DROP TABLE `One`";
7276     r = run_query(hdb, 0, query);
7277     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7278
7279     query = "DROP TABLE `One`";
7280     r = run_query(href, 0, query);
7281     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7282
7283     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A` )";
7284     r = run_query(hdb, 0, query);
7285     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7286
7287     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 1, 1 )";
7288     r = run_query(hdb, 0, query);
7289     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7290
7291     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 2, 2 )";
7292     r = run_query(hdb, 0, query);
7293     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7294
7295     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A` )";
7296     r = run_query(href, 0, query);
7297     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7298
7299     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 1, 2 )";
7300     r = run_query(href, 0, query);
7301     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7302
7303     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 2, 3 )";
7304     r = run_query(href, 0, query);
7305     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7306
7307     /* primary keys match, rows do not */
7308     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7309     ok(r == ERROR_FUNCTION_FAILED,
7310        "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
7311
7312     /* nothing in MergeErrors */
7313     query = "SELECT * FROM `MergeErrors`";
7314     r = do_query(hdb, query, &hrec);
7315     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7316
7317     size = MAX_PATH;
7318     r = MsiRecordGetStringA(hrec, 1, buf, &size);
7319     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7320     ok(!lstrcmpA(buf, "One"), "Expected \"One\", got \"%s\"\n", buf);
7321
7322     r = MsiRecordGetInteger(hrec, 2);
7323     ok(r == 2, "Expected 2, got %d\n", r);
7324
7325     MsiCloseHandle(hrec);
7326
7327     r = MsiDatabaseOpenViewA(hdb, "SELECT * FROM `MergeErrors`", &hview);
7328     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7329
7330     r = MsiViewGetColumnInfo(hview, MSICOLINFO_NAMES, &hrec);
7331     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7332
7333     size = MAX_PATH;
7334     r = MsiRecordGetString(hrec, 1, buf, &size);
7335     ok(!lstrcmpA(buf, "Table"), "Expected \"Table\", got \"%s\"\n", buf);
7336
7337     size = MAX_PATH;
7338     r = MsiRecordGetString(hrec, 2, buf, &size);
7339     ok(!lstrcmpA(buf, "NumRowMergeConflicts"),
7340        "Expected \"NumRowMergeConflicts\", got \"%s\"\n", buf);
7341
7342     MsiCloseHandle(hrec);
7343
7344     r = MsiViewGetColumnInfo(hview, MSICOLINFO_TYPES, &hrec);
7345     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7346
7347     size = MAX_PATH;
7348     r = MsiRecordGetString(hrec, 1, buf, &size);
7349     ok(!lstrcmpA(buf, "s255"), "Expected \"s255\", got \"%s\"\n", buf);
7350
7351     size = MAX_PATH;
7352     r = MsiRecordGetString(hrec, 2, buf, &size);
7353     ok(!lstrcmpA(buf, "i2"), "Expected \"i2\", got \"%s\"\n", buf);
7354
7355     MsiCloseHandle(hrec);
7356     MsiViewClose(hview);
7357     MsiCloseHandle(hview);
7358
7359     query = "DROP TABLE `MergeErrors`";
7360     r = run_query(hdb, 0, query);
7361     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7362
7363     query = "DROP TABLE `One`";
7364     r = run_query(hdb, 0, query);
7365     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7366
7367     query = "DROP TABLE `One`";
7368     r = run_query(href, 0, query);
7369     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7370
7371     query = "CREATE TABLE `One` ( `A` INT, `B` CHAR(72) PRIMARY KEY `A` )";
7372     r = run_query(href, 0, query);
7373     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7374
7375     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 1, 'hi' )";
7376     r = run_query(href, 0, query);
7377     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7378
7379     /* table from merged database is not in target database */
7380     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7381     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7382
7383     query = "SELECT * FROM `One`";
7384     r = do_query(hdb, query, &hrec);
7385     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7386
7387     r = MsiRecordGetInteger(hrec, 1);
7388     ok(r == 1, "Expected 1, got %d\n", r);
7389
7390     size = MAX_PATH;
7391     r = MsiRecordGetStringA(hrec, 2, buf, &size);
7392     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7393     ok(!lstrcmpA(buf, "hi"), "Expected \"hi\", got \"%s\"\n", buf);
7394
7395     MsiCloseHandle(hrec);
7396
7397     /* nothing in MergeErrors */
7398     query = "SELECT * FROM `MergeErrors`";
7399     r = do_query(hdb, query, &hrec);
7400     ok(r == ERROR_BAD_QUERY_SYNTAX,
7401        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7402
7403     query = "DROP TABLE `One`";
7404     r = run_query(hdb, 0, query);
7405     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7406
7407     query = "DROP TABLE `One`";
7408     r = run_query(href, 0, query);
7409     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7410
7411     query = "CREATE TABLE `One` ( "
7412             "`A` CHAR(72), `B` INT PRIMARY KEY `A` )";
7413     r = run_query(hdb, 0, query);
7414     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7415
7416     query = "CREATE TABLE `One` ( "
7417             "`A` CHAR(72), `B` INT PRIMARY KEY `A` )";
7418     r = run_query(href, 0, query);
7419     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7420
7421     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 'hi', 1 )";
7422     r = run_query(href, 0, query);
7423     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7424
7425     /* primary key is string */
7426     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7427     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7428
7429     query = "SELECT * FROM `One`";
7430     r = do_query(hdb, query, &hrec);
7431     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7432
7433     size = MAX_PATH;
7434     r = MsiRecordGetStringA(hrec, 1, buf, &size);
7435     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7436     ok(!lstrcmpA(buf, "hi"), "Expected \"hi\", got \"%s\"\n", buf);
7437
7438     r = MsiRecordGetInteger(hrec, 2);
7439     ok(r == 1, "Expected 1, got %d\n", r);
7440
7441     MsiCloseHandle(hrec);
7442
7443     /* nothing in MergeErrors */
7444     query = "SELECT * FROM `MergeErrors`";
7445     r = do_query(hdb, query, &hrec);
7446     ok(r == ERROR_BAD_QUERY_SYNTAX,
7447        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7448
7449     create_file_data("codepage.idt", "\r\n\r\n850\t_ForceCodepage\r\n", 0);
7450
7451     GetCurrentDirectoryA(MAX_PATH, buf);
7452     r = MsiDatabaseImportA(hdb, buf, "codepage.idt");
7453     todo_wine
7454     {
7455         ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7456     }
7457
7458     query = "DROP TABLE `One`";
7459     r = run_query(hdb, 0, query);
7460     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7461
7462     query = "DROP TABLE `One`";
7463     r = run_query(href, 0, query);
7464     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7465
7466     query = "CREATE TABLE `One` ( "
7467             "`A` INT, `B` CHAR(72) LOCALIZABLE PRIMARY KEY `A` )";
7468     r = run_query(hdb, 0, query);
7469     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7470
7471     query = "CREATE TABLE `One` ( "
7472             "`A` INT, `B` CHAR(72) LOCALIZABLE PRIMARY KEY `A` )";
7473     r = run_query(href, 0, query);
7474     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7475
7476     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 1, 'hi' )";
7477     r = run_query(href, 0, query);
7478     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7479
7480     /* code page does not match */
7481     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7482     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7483
7484     query = "SELECT * FROM `One`";
7485     r = do_query(hdb, query, &hrec);
7486     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7487
7488     r = MsiRecordGetInteger(hrec, 1);
7489     ok(r == 1, "Expected 1, got %d\n", r);
7490
7491     size = MAX_PATH;
7492     r = MsiRecordGetStringA(hrec, 2, buf, &size);
7493     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7494     ok(!lstrcmpA(buf, "hi"), "Expected \"hi\", got \"%s\"\n", buf);
7495
7496     MsiCloseHandle(hrec);
7497
7498     /* nothing in MergeErrors */
7499     query = "SELECT * FROM `MergeErrors`";
7500     r = do_query(hdb, query, &hrec);
7501     ok(r == ERROR_BAD_QUERY_SYNTAX,
7502        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7503
7504     query = "DROP TABLE `One`";
7505     r = run_query(hdb, 0, query);
7506     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7507
7508     query = "DROP TABLE `One`";
7509     r = run_query(href, 0, query);
7510     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7511
7512     query = "CREATE TABLE `One` ( `A` INT, `B` OBJECT PRIMARY KEY `A` )";
7513     r = run_query(hdb, 0, query);
7514     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7515
7516     query = "CREATE TABLE `One` ( `A` INT, `B` OBJECT PRIMARY KEY `A` )";
7517     r = run_query(href, 0, query);
7518     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7519
7520     create_file("binary.dat");
7521     hrec = MsiCreateRecord(1);
7522     MsiRecordSetStreamA(hrec, 1, "binary.dat");
7523
7524     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 1, ? )";
7525     r = run_query(href, hrec, query);
7526     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7527
7528     MsiCloseHandle(hrec);
7529
7530     /* binary data to merge */
7531     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7532     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7533
7534     query = "SELECT * FROM `One`";
7535     r = do_query(hdb, query, &hrec);
7536     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7537
7538     r = MsiRecordGetInteger(hrec, 1);
7539     ok(r == 1, "Expected 1, got %d\n", r);
7540
7541     size = MAX_PATH;
7542     ZeroMemory(buf, MAX_PATH);
7543     r = MsiRecordReadStream(hrec, 2, buf, &size);
7544     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7545     ok(!lstrcmpA(buf, "binary.dat\n"),
7546        "Expected \"binary.dat\\n\", got \"%s\"\n", buf);
7547
7548     MsiCloseHandle(hrec);
7549
7550     /* nothing in MergeErrors */
7551     query = "SELECT * FROM `MergeErrors`";
7552     r = do_query(hdb, query, &hrec);
7553     ok(r == ERROR_BAD_QUERY_SYNTAX,
7554        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7555
7556     MsiCloseHandle(hdb);
7557     MsiCloseHandle(href);
7558     DeleteFileA(msifile);
7559     DeleteFileA("refdb.msi");
7560     DeleteFileA("codepage.idt");
7561     DeleteFileA("binary.dat");
7562 }
7563
7564 UINT ordervals[6][3] =
7565 {
7566     { MSI_NULL_INTEGER, 12, 13 },
7567     { 1, 2, 3 },
7568     { 6, 4, 5 },
7569     { 8, 9, 7 },
7570     { 10, 11, MSI_NULL_INTEGER },
7571     { 14, MSI_NULL_INTEGER, 15 }
7572 };
7573
7574 static void test_insertorder(void)
7575 {
7576     MSIHANDLE hdb, view, rec;
7577     LPCSTR query;
7578     UINT r;
7579     int i;
7580
7581     hdb = create_db();
7582     ok(hdb, "failed to create db\n");
7583
7584     query = "CREATE TABLE `T` ( `A` SHORT, `B` SHORT, `C` SHORT PRIMARY KEY `A`)";
7585     r = run_query(hdb, 0, query);
7586     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7587
7588     query = "INSERT INTO `T` ( `A`, `B`, `C` ) VALUES ( 1, 2, 3 )";
7589     r = run_query(hdb, 0, query);
7590     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7591
7592     query = "INSERT INTO `T` ( `B`, `C`, `A` ) VALUES ( 4, 5, 6 )";
7593     r = run_query(hdb, 0, query);
7594     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7595
7596     query = "INSERT INTO `T` ( `C`, `A`, `B` ) VALUES ( 7, 8, 9 )";
7597     r = run_query(hdb, 0, query);
7598     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7599
7600     query = "INSERT INTO `T` ( `A`, `B` ) VALUES ( 10, 11 )";
7601     r = run_query(hdb, 0, query);
7602     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7603
7604     query = "INSERT INTO `T` ( `B`, `C` ) VALUES ( 12, 13 )";
7605     r = run_query(hdb, 0, query);
7606     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7607
7608     /* fails because the primary key already
7609      * has an MSI_NULL_INTEGER value set above
7610      */
7611     query = "INSERT INTO `T` ( `C` ) VALUES ( 14 )";
7612     r = run_query(hdb, 0, query);
7613     ok(r == ERROR_FUNCTION_FAILED,
7614        "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
7615
7616     /* replicate the error where primary key is set twice */
7617     query = "INSERT INTO `T` ( `A`, `C` ) VALUES ( 1, 14 )";
7618     r = run_query(hdb, 0, query);
7619     ok(r == ERROR_FUNCTION_FAILED,
7620        "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
7621
7622     query = "INSERT INTO `T` ( `A`, `C` ) VALUES ( 14, 15 )";
7623     r = run_query(hdb, 0, query);
7624     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7625
7626     query = "INSERT INTO `T` VALUES ( 16 )";
7627     r = run_query(hdb, 0, query);
7628     ok(r == ERROR_BAD_QUERY_SYNTAX,
7629        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7630
7631     query = "INSERT INTO `T` VALUES ( 17, 18 )";
7632     r = run_query(hdb, 0, query);
7633     ok(r == ERROR_BAD_QUERY_SYNTAX,
7634        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7635
7636     query = "INSERT INTO `T` VALUES ( 19, 20, 21 )";
7637     r = run_query(hdb, 0, query);
7638     ok(r == ERROR_BAD_QUERY_SYNTAX,
7639        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7640
7641     query = "SELECT * FROM `T`";
7642     r = MsiDatabaseOpenView(hdb, query, &view);
7643     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7644     r = MsiViewExecute(view, 0);
7645     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7646
7647     for (i = 0; i < 6; i++)
7648     {
7649         r = MsiViewFetch(view, &rec);
7650         ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7651
7652         r = MsiRecordGetInteger(rec, 1);
7653         ok(r == ordervals[i][0], "Expected %d, got %d\n", ordervals[i][0], r);
7654
7655         r = MsiRecordGetInteger(rec, 2);
7656         ok(r == ordervals[i][1], "Expected %d, got %d\n", ordervals[i][1], r);
7657
7658         r = MsiRecordGetInteger(rec, 3);
7659         ok(r == ordervals[i][2], "Expected %d, got %d\n", ordervals[i][2], r);
7660
7661         MsiCloseHandle(rec);
7662     }
7663
7664     r = MsiViewFetch(view, &rec);
7665     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7666
7667     MsiViewClose(view);
7668     MsiCloseHandle(view);
7669
7670     query = "DELETE FROM `T` WHERE `A` IS NULL";
7671     r = run_query(hdb, 0, query);
7672     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7673
7674     query = "INSERT INTO `T` ( `B`, `C` ) VALUES ( 12, 13 ) TEMPORARY";
7675     r = run_query(hdb, 0, query);
7676     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7677
7678     query = "SELECT * FROM `T`";
7679     r = MsiDatabaseOpenView(hdb, query, &view);
7680     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7681     r = MsiViewExecute(view, 0);
7682     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7683
7684     for (i = 0; i < 6; i++)
7685     {
7686         r = MsiViewFetch(view, &rec);
7687         ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7688
7689         r = MsiRecordGetInteger(rec, 1);
7690         ok(r == ordervals[i][0], "Expected %d, got %d\n", ordervals[i][0], r);
7691
7692         r = MsiRecordGetInteger(rec, 2);
7693         ok(r == ordervals[i][1], "Expected %d, got %d\n", ordervals[i][1], r);
7694
7695         r = MsiRecordGetInteger(rec, 3);
7696         ok(r == ordervals[i][2], "Expected %d, got %d\n", ordervals[i][2], r);
7697
7698         MsiCloseHandle(rec);
7699     }
7700
7701     r = MsiViewFetch(view, &rec);
7702     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7703
7704     MsiViewClose(view);
7705     MsiCloseHandle(view);
7706     MsiCloseHandle(hdb);
7707     DeleteFileA(msifile);
7708 }
7709
7710 static void test_columnorder(void)
7711 {
7712     MSIHANDLE hdb, view, rec;
7713     char buf[MAX_PATH];
7714     LPCSTR query;
7715     DWORD sz;
7716     UINT r;
7717
7718     hdb = create_db();
7719     ok(hdb, "failed to create db\n");
7720
7721     /* Each column is a slot:
7722      * ---------------------
7723      * | B | C | A | E | D |
7724      * ---------------------
7725      *
7726      * When a column is selected as a primary key,
7727      * the column occupying the nth primary key slot is swapped
7728      * with the current position of the primary key in question:
7729      *
7730      * set primary key `D`
7731      * ---------------------    ---------------------
7732      * | B | C | A | E | D | -> | D | C | A | E | B |
7733      * ---------------------    ---------------------
7734      *
7735      * set primary key `E`
7736      * ---------------------    ---------------------
7737      * | D | C | A | E | B | -> | D | E | A | C | B |
7738      * ---------------------    ---------------------
7739      */
7740
7741     query = "CREATE TABLE `T` ( `B` SHORT NOT NULL, `C` SHORT NOT NULL, "
7742             "`A` CHAR(255), `E` INT, `D` CHAR(255) NOT NULL "
7743             "PRIMARY KEY `D`, `E`)";
7744     r = run_query(hdb, 0, query);
7745     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7746
7747     query = "SELECT * FROM `T`";
7748     r = MsiDatabaseOpenView(hdb, query, &view);
7749     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7750
7751     r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
7752     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7753
7754     sz = MAX_PATH;
7755     lstrcpyA(buf, "kiwi");
7756     r = MsiRecordGetString(rec, 1, buf, &sz);
7757     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7758     ok(!lstrcmpA("s255", buf), "Expected \"s255\", got \"%s\"\n", buf);
7759
7760     sz = MAX_PATH;
7761     lstrcpyA(buf, "kiwi");
7762     r = MsiRecordGetString(rec, 2, buf, &sz);
7763     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7764     ok(!lstrcmpA("I2", buf), "Expected \"I2\", got \"%s\"\n", buf);
7765
7766     sz = MAX_PATH;
7767     lstrcpyA(buf, "kiwi");
7768     r = MsiRecordGetString(rec, 3, buf, &sz);
7769     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7770     ok(!lstrcmpA("S255", buf), "Expected \"S255\", got \"%s\"\n", buf);
7771
7772     sz = MAX_PATH;
7773     lstrcpyA(buf, "kiwi");
7774     r = MsiRecordGetString(rec, 4, buf, &sz);
7775     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7776     ok(!lstrcmpA("i2", buf), "Expected \"i2\", got \"%s\"\n", buf);
7777
7778     sz = MAX_PATH;
7779     lstrcpyA(buf, "kiwi");
7780     r = MsiRecordGetString(rec, 5, buf, &sz);
7781     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7782     ok(!lstrcmpA("i2", buf), "Expected \"i2\", got \"%s\"\n", buf);
7783
7784     MsiCloseHandle(rec);
7785
7786     r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec);
7787     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7788
7789     sz = MAX_PATH;
7790     lstrcpyA(buf, "kiwi");
7791     r = MsiRecordGetString(rec, 1, buf, &sz);
7792     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7793     ok(!lstrcmpA("D", buf), "Expected \"D\", got \"%s\"\n", buf);
7794
7795     sz = MAX_PATH;
7796     lstrcpyA(buf, "kiwi");
7797     r = MsiRecordGetString(rec, 2, buf, &sz);
7798     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7799     ok(!lstrcmpA("E", buf), "Expected \"E\", got \"%s\"\n", buf);
7800
7801     sz = MAX_PATH;
7802     lstrcpyA(buf, "kiwi");
7803     r = MsiRecordGetString(rec, 3, buf, &sz);
7804     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7805     ok(!lstrcmpA("A", buf), "Expected \"A\", got \"%s\"\n", buf);
7806
7807     sz = MAX_PATH;
7808     lstrcpyA(buf, "kiwi");
7809     r = MsiRecordGetString(rec, 4, buf, &sz);
7810     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7811     ok(!lstrcmpA("C", buf), "Expected \"C\", got \"%s\"\n", buf);
7812
7813     sz = MAX_PATH;
7814     lstrcpyA(buf, "kiwi");
7815     r = MsiRecordGetString(rec, 5, buf, &sz);
7816     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7817     ok(!lstrcmpA("B", buf), "Expected \"B\", got \"%s\"\n", buf);
7818
7819     MsiCloseHandle(rec);
7820     MsiViewClose(view);
7821     MsiCloseHandle(view);
7822
7823     query = "INSERT INTO `T` ( `B`, `C`, `A`, `E`, `D` ) "
7824             "VALUES ( 1, 2, 'a', 3, 'bc' )";
7825     r = run_query(hdb, 0, query);
7826     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7827
7828     query = "SELECT * FROM `T`";
7829     r = do_query(hdb, query, &rec);
7830
7831     sz = MAX_PATH;
7832     lstrcpyA(buf, "kiwi");
7833     r = MsiRecordGetString(rec, 1, buf, &sz);
7834     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7835     ok(!lstrcmpA("bc", buf), "Expected \"bc\", got \"%s\"\n", buf);
7836
7837     r = MsiRecordGetInteger(rec, 2);
7838     ok(r == 3, "Expected 3, got %d\n", r);
7839
7840     sz = MAX_PATH;
7841     lstrcpyA(buf, "kiwi");
7842     r = MsiRecordGetString(rec, 3, buf, &sz);
7843     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7844     ok(!lstrcmpA("a", buf), "Expected \"a\", got \"%s\"\n", buf);
7845
7846     r = MsiRecordGetInteger(rec, 4);
7847     ok(r == 2, "Expected 2, got %d\n", r);
7848
7849     r = MsiRecordGetInteger(rec, 5);
7850     ok(r == 1, "Expected 1, got %d\n", r);
7851
7852     MsiCloseHandle(rec);
7853
7854     query = "SELECT * FROM `_Columns` WHERE `Table` = 'T'";
7855     r = MsiDatabaseOpenView(hdb, query, &view);
7856     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7857     r = MsiViewExecute(view, 0);
7858     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7859
7860     r = MsiViewFetch(view, &rec);
7861     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7862
7863     sz = MAX_PATH;
7864     lstrcpyA(buf, "kiwi");
7865     r = MsiRecordGetString(rec, 1, buf, &sz);
7866     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7867     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
7868
7869     r = MsiRecordGetInteger(rec, 2);
7870     ok(r == 1, "Expected 1, got %d\n", r);
7871
7872     sz = MAX_PATH;
7873     lstrcpyA(buf, "kiwi");
7874     r = MsiRecordGetString(rec, 3, buf, &sz);
7875     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7876     ok(!lstrcmpA("D", buf), "Expected \"D\", got \"%s\"\n", buf);
7877
7878     MsiCloseHandle(rec);
7879
7880     r = MsiViewFetch(view, &rec);
7881     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7882
7883     sz = MAX_PATH;
7884     lstrcpyA(buf, "kiwi");
7885     r = MsiRecordGetString(rec, 1, buf, &sz);
7886     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7887     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
7888
7889     r = MsiRecordGetInteger(rec, 2);
7890     ok(r == 2, "Expected 2, got %d\n", r);
7891
7892     sz = MAX_PATH;
7893     lstrcpyA(buf, "kiwi");
7894     r = MsiRecordGetString(rec, 3, buf, &sz);
7895     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7896     ok(!lstrcmpA("E", buf), "Expected \"E\", got \"%s\"\n", buf);
7897
7898     MsiCloseHandle(rec);
7899
7900     r = MsiViewFetch(view, &rec);
7901     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7902
7903     sz = MAX_PATH;
7904     lstrcpyA(buf, "kiwi");
7905     r = MsiRecordGetString(rec, 1, buf, &sz);
7906     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7907     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
7908
7909     r = MsiRecordGetInteger(rec, 2);
7910     ok(r == 3, "Expected 3, got %d\n", r);
7911
7912     sz = MAX_PATH;
7913     lstrcpyA(buf, "kiwi");
7914     r = MsiRecordGetString(rec, 3, buf, &sz);
7915     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7916     ok(!lstrcmpA("A", buf), "Expected \"A\", got \"%s\"\n", buf);
7917
7918     MsiCloseHandle(rec);
7919
7920     r = MsiViewFetch(view, &rec);
7921     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7922
7923     sz = MAX_PATH;
7924     lstrcpyA(buf, "kiwi");
7925     r = MsiRecordGetString(rec, 1, buf, &sz);
7926     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7927     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
7928
7929     r = MsiRecordGetInteger(rec, 2);
7930     ok(r == 4, "Expected 4, got %d\n", r);
7931
7932     sz = MAX_PATH;
7933     lstrcpyA(buf, "kiwi");
7934     r = MsiRecordGetString(rec, 3, buf, &sz);
7935     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7936     ok(!lstrcmpA("C", buf), "Expected \"C\", got \"%s\"\n", buf);
7937
7938     MsiCloseHandle(rec);
7939
7940     r = MsiViewFetch(view, &rec);
7941     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7942
7943     sz = MAX_PATH;
7944     lstrcpyA(buf, "kiwi");
7945     r = MsiRecordGetString(rec, 1, buf, &sz);
7946     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7947     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
7948
7949     r = MsiRecordGetInteger(rec, 2);
7950     ok(r == 5, "Expected 5, got %d\n", r);
7951
7952     sz = MAX_PATH;
7953     lstrcpyA(buf, "kiwi");
7954     r = MsiRecordGetString(rec, 3, buf, &sz);
7955     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7956     ok(!lstrcmpA("B", buf), "Expected \"B\", got \"%s\"\n", buf);
7957
7958     MsiCloseHandle(rec);
7959
7960     r = MsiViewFetch(view, &rec);
7961     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7962
7963     MsiViewClose(view);
7964     MsiCloseHandle(view);
7965
7966     query = "CREATE TABLE `Z` ( `B` SHORT NOT NULL, `C` SHORT NOT NULL, "
7967             "`A` CHAR(255), `E` INT, `D` CHAR(255) NOT NULL "
7968             "PRIMARY KEY `C`, `A`, `D`)";
7969     r = run_query(hdb, 0, query);
7970     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7971
7972     query = "SELECT * FROM `Z`";
7973     r = MsiDatabaseOpenView(hdb, query, &view);
7974     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7975
7976     r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
7977     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7978
7979     sz = MAX_PATH;
7980     lstrcpyA(buf, "kiwi");
7981     r = MsiRecordGetString(rec, 1, buf, &sz);
7982     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7983     ok(!lstrcmpA("i2", buf), "Expected \"i2\", got \"%s\"\n", buf);
7984
7985     sz = MAX_PATH;
7986     lstrcpyA(buf, "kiwi");
7987     r = MsiRecordGetString(rec, 2, buf, &sz);
7988     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7989     ok(!lstrcmpA("S255", buf), "Expected \"S255\", got \"%s\"\n", buf);
7990
7991     sz = MAX_PATH;
7992     lstrcpyA(buf, "kiwi");
7993     r = MsiRecordGetString(rec, 3, buf, &sz);
7994     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7995     ok(!lstrcmpA("s255", buf), "Expected \"s255\", got \"%s\"\n", buf);
7996
7997     sz = MAX_PATH;
7998     lstrcpyA(buf, "kiwi");
7999     r = MsiRecordGetString(rec, 4, buf, &sz);
8000     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8001     ok(!lstrcmpA("I2", buf), "Expected \"I2\", got \"%s\"\n", buf);
8002
8003     sz = MAX_PATH;
8004     lstrcpyA(buf, "kiwi");
8005     r = MsiRecordGetString(rec, 5, buf, &sz);
8006     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8007     ok(!lstrcmpA("i2", buf), "Expected \"i2\", got \"%s\"\n", buf);
8008
8009     MsiCloseHandle(rec);
8010
8011     r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec);
8012     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8013
8014     sz = MAX_PATH;
8015     lstrcpyA(buf, "kiwi");
8016     r = MsiRecordGetString(rec, 1, buf, &sz);
8017     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8018     ok(!lstrcmpA("C", buf), "Expected \"C\", got \"%s\"\n", buf);
8019
8020     sz = MAX_PATH;
8021     lstrcpyA(buf, "kiwi");
8022     r = MsiRecordGetString(rec, 2, buf, &sz);
8023     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8024     ok(!lstrcmpA("A", buf), "Expected \"A\", got \"%s\"\n", buf);
8025
8026     sz = MAX_PATH;
8027     lstrcpyA(buf, "kiwi");
8028     r = MsiRecordGetString(rec, 3, buf, &sz);
8029     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8030     ok(!lstrcmpA("D", buf), "Expected \"D\", got \"%s\"\n", buf);
8031
8032     sz = MAX_PATH;
8033     lstrcpyA(buf, "kiwi");
8034     r = MsiRecordGetString(rec, 4, buf, &sz);
8035     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8036     ok(!lstrcmpA("E", buf), "Expected \"E\", got \"%s\"\n", buf);
8037
8038     sz = MAX_PATH;
8039     lstrcpyA(buf, "kiwi");
8040     r = MsiRecordGetString(rec, 5, buf, &sz);
8041     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8042     ok(!lstrcmpA("B", buf), "Expected \"B\", got \"%s\"\n", buf);
8043
8044     MsiCloseHandle(rec);
8045     MsiViewClose(view);
8046     MsiCloseHandle(view);
8047
8048     query = "INSERT INTO `Z` ( `B`, `C`, `A`, `E`, `D` ) "
8049             "VALUES ( 1, 2, 'a', 3, 'bc' )";
8050     r = run_query(hdb, 0, query);
8051     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8052
8053     query = "SELECT * FROM `Z`";
8054     r = do_query(hdb, query, &rec);
8055
8056     r = MsiRecordGetInteger(rec, 1);
8057     ok(r == 2, "Expected 2, got %d\n", r);
8058
8059     sz = MAX_PATH;
8060     lstrcpyA(buf, "kiwi");
8061     r = MsiRecordGetString(rec, 2, buf, &sz);
8062     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8063     ok(!lstrcmpA("a", buf), "Expected \"a\", got \"%s\"\n", buf);
8064
8065     sz = MAX_PATH;
8066     lstrcpyA(buf, "kiwi");
8067     r = MsiRecordGetString(rec, 3, buf, &sz);
8068     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8069     ok(!lstrcmpA("bc", buf), "Expected \"bc\", got \"%s\"\n", buf);
8070
8071     r = MsiRecordGetInteger(rec, 4);
8072     ok(r == 3, "Expected 3, got %d\n", r);
8073
8074     r = MsiRecordGetInteger(rec, 5);
8075     ok(r == 1, "Expected 1, got %d\n", r);
8076
8077     MsiCloseHandle(rec);
8078
8079     query = "SELECT * FROM `_Columns` WHERE `Table` = 'T'";
8080     r = MsiDatabaseOpenView(hdb, query, &view);
8081     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8082     r = MsiViewExecute(view, 0);
8083     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8084
8085     r = MsiViewFetch(view, &rec);
8086     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8087
8088     sz = MAX_PATH;
8089     lstrcpyA(buf, "kiwi");
8090     r = MsiRecordGetString(rec, 1, buf, &sz);
8091     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8092     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
8093
8094     r = MsiRecordGetInteger(rec, 2);
8095     ok(r == 1, "Expected 1, got %d\n", r);
8096
8097     sz = MAX_PATH;
8098     lstrcpyA(buf, "kiwi");
8099     r = MsiRecordGetString(rec, 3, buf, &sz);
8100     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8101     ok(!lstrcmpA("D", buf), "Expected \"D\", got \"%s\"\n", buf);
8102
8103     MsiCloseHandle(rec);
8104
8105     r = MsiViewFetch(view, &rec);
8106     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8107
8108     sz = MAX_PATH;
8109     lstrcpyA(buf, "kiwi");
8110     r = MsiRecordGetString(rec, 1, buf, &sz);
8111     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8112     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
8113
8114     r = MsiRecordGetInteger(rec, 2);
8115     ok(r == 2, "Expected 2, got %d\n", r);
8116
8117     sz = MAX_PATH;
8118     lstrcpyA(buf, "kiwi");
8119     r = MsiRecordGetString(rec, 3, buf, &sz);
8120     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8121     ok(!lstrcmpA("E", buf), "Expected \"E\", got \"%s\"\n", buf);
8122
8123     MsiCloseHandle(rec);
8124
8125     r = MsiViewFetch(view, &rec);
8126     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8127
8128     sz = MAX_PATH;
8129     lstrcpyA(buf, "kiwi");
8130     r = MsiRecordGetString(rec, 1, buf, &sz);
8131     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8132     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
8133
8134     r = MsiRecordGetInteger(rec, 2);
8135     ok(r == 3, "Expected 3, got %d\n", r);
8136
8137     sz = MAX_PATH;
8138     lstrcpyA(buf, "kiwi");
8139     r = MsiRecordGetString(rec, 3, buf, &sz);
8140     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8141     ok(!lstrcmpA("A", buf), "Expected \"A\", got \"%s\"\n", buf);
8142
8143     MsiCloseHandle(rec);
8144
8145     r = MsiViewFetch(view, &rec);
8146     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8147
8148     sz = MAX_PATH;
8149     lstrcpyA(buf, "kiwi");
8150     r = MsiRecordGetString(rec, 1, buf, &sz);
8151     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8152     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
8153
8154     r = MsiRecordGetInteger(rec, 2);
8155     ok(r == 4, "Expected 4, got %d\n", r);
8156
8157     sz = MAX_PATH;
8158     lstrcpyA(buf, "kiwi");
8159     r = MsiRecordGetString(rec, 3, buf, &sz);
8160     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8161     ok(!lstrcmpA("C", buf), "Expected \"C\", got \"%s\"\n", buf);
8162
8163     MsiCloseHandle(rec);
8164
8165     r = MsiViewFetch(view, &rec);
8166     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8167
8168     sz = MAX_PATH;
8169     lstrcpyA(buf, "kiwi");
8170     r = MsiRecordGetString(rec, 1, buf, &sz);
8171     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8172     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
8173
8174     r = MsiRecordGetInteger(rec, 2);
8175     ok(r == 5, "Expected 5, got %d\n", r);
8176
8177     sz = MAX_PATH;
8178     lstrcpyA(buf, "kiwi");
8179     r = MsiRecordGetString(rec, 3, buf, &sz);
8180     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8181     ok(!lstrcmpA("B", buf), "Expected \"B\", got \"%s\"\n", buf);
8182
8183     MsiCloseHandle(rec);
8184
8185     r = MsiViewFetch(view, &rec);
8186     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
8187
8188     MsiViewClose(view);
8189     MsiCloseHandle(view);
8190
8191     MsiCloseHandle(hdb);
8192     DeleteFileA(msifile);
8193 }
8194
8195 START_TEST(db)
8196 {
8197     test_msidatabase();
8198     test_msiinsert();
8199     test_msidecomposedesc();
8200     test_msibadqueries();
8201     test_viewmodify();
8202     test_viewgetcolumninfo();
8203     test_getcolinfo();
8204     test_msiexport();
8205     test_longstrings();
8206     test_streamtable();
8207     test_binary();
8208     test_where();
8209     test_msiimport();
8210     test_binary_import();
8211     test_markers();
8212     test_handle_limit();
8213     test_try_transform();
8214     test_join();
8215     test_temporary_table();
8216     test_alter();
8217     test_integers();
8218     test_update();
8219     test_special_tables();
8220     test_tables_order();
8221     test_select_markers();
8222     test_viewmodify_update();
8223     test_viewmodify_assign();
8224     test_stringtable();
8225     test_viewmodify_delete();
8226     test_defaultdatabase();
8227     test_order();
8228     test_viewmodify_delete_temporary();
8229     test_deleterow();
8230     test_quotes();
8231     test_carriagereturn();
8232     test_noquotes();
8233     test_forcecodepage();
8234     test_viewmodify_refresh();
8235     test_where_viewmodify();
8236     test_storages_table();
8237     test_dbtopackage();
8238     test_droptable();
8239     test_dbmerge();
8240     test_insertorder();
8241     test_columnorder();
8242     test_suminfo_import();
8243 }