crypt32: Make sure we show Unicode characters (Dutch translation).
[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 const WCHAR data10[] = { /* MOO */
4767     0x8001, 0x000b,
4768 };
4769 static const WCHAR data11[] = { /* AAR */
4770     0x8002, 0x8005,
4771     0x000c, 0x000f,
4772 };
4773 static const char data12[] = /* _StringData */
4774     "MOOABAARCDonetwofourfive";
4775 static const WCHAR data13[] = { /* _StringPool */
4776 /*  len, refs */
4777     0,   0,    /* string 0 ''     */
4778     0,   0,    /* string 1 ''     */
4779     0,   0,    /* string 2 ''     */
4780     0,   0,    /* string 3 ''     */
4781     0,   0,    /* string 4 ''     */
4782     3,   3,    /* string 5 'MOO'  */
4783     1,   1,    /* string 6 'A'    */
4784     1,   1,    /* string 7 'B'    */
4785     3,   3,    /* string 8 'AAR'  */
4786     1,   1,    /* string 9 'C'    */
4787     1,   1,    /* string a 'D'    */
4788     3,   1,    /* string b 'one'  */
4789     3,   1,    /* string c 'two'  */
4790     0,   0,    /* string d ''     */
4791     4,   1,    /* string e 'four' */
4792     4,   1,    /* string f 'five' */
4793 };
4794
4795 static void test_stringtable(void)
4796 {
4797     MSIHANDLE hdb = 0, hview = 0, hrec = 0;
4798     IStorage *stg = NULL;
4799     IStream *stm;
4800     WCHAR name[0x20];
4801     HRESULT hr;
4802     const char *query;
4803     char buffer[MAX_PATH];
4804     WCHAR data[MAX_PATH];
4805     DWORD sz, read;
4806     UINT r;
4807
4808     static const DWORD mode = STGM_DIRECT | STGM_READ | STGM_SHARE_DENY_WRITE;
4809     static const WCHAR stringdata[] = {0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0}; /* _StringData */
4810     static const WCHAR stringpool[] = {0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0}; /* _StringPool */
4811     static const WCHAR moo[] = {0x4840, 0x3e16, 0x4818, 0}; /* MOO */
4812     static const WCHAR aar[] = {0x4840, 0x3a8a, 0x481b, 0}; /* AAR */
4813
4814     DeleteFile(msifile);
4815
4816     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
4817     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4818
4819     query = "CREATE TABLE `MOO` (`A` INT, `B` CHAR(72) PRIMARY KEY `A`)";
4820     r = run_query(hdb, 0, query);
4821     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4822
4823     query = "CREATE TABLE `AAR` (`C` INT, `D` CHAR(72) PRIMARY KEY `C`)";
4824     r = run_query(hdb, 0, query);
4825     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4826
4827     /* insert persistent row */
4828     query = "INSERT INTO `MOO` (`A`, `B`) VALUES (1, 'one')";
4829     r = run_query(hdb, 0, query);
4830     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4831
4832     /* insert persistent row */
4833     query = "INSERT INTO `AAR` (`C`, `D`) VALUES (2, 'two')";
4834     r = run_query(hdb, 0, query);
4835     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4836
4837     /* open a view */
4838     query = "SELECT * FROM `MOO`";
4839     r = MsiDatabaseOpenView(hdb, query, &hview);
4840     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4841     r = MsiViewExecute(hview, 0);
4842     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4843
4844     hrec = MsiCreateRecord(2);
4845
4846     r = MsiRecordSetInteger(hrec, 1, 3);
4847     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4848     r = MsiRecordSetString(hrec, 2, "three");
4849     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4850
4851     /* insert a nonpersistent row */
4852     r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec);
4853     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4854
4855     r = MsiCloseHandle(hrec);
4856     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4857     r = MsiViewClose(hview);
4858     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4859     r = MsiCloseHandle(hview);
4860     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4861
4862     /* insert persistent row */
4863     query = "INSERT INTO `MOO` (`A`, `B`) VALUES (4, 'four')";
4864     r = run_query(hdb, 0, query);
4865     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4866
4867     /* insert persistent row */
4868     query = "INSERT INTO `AAR` (`C`, `D`) VALUES (5, 'five')";
4869     r = run_query(hdb, 0, query);
4870     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4871
4872     r = MsiDatabaseCommit(hdb);
4873     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4874
4875     r = MsiCloseHandle(hdb);
4876     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4877
4878     r = MsiOpenDatabase(msifile, MSIDBOPEN_READONLY, &hdb);
4879     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4880
4881     query = "SELECT * FROM `MOO`";
4882     r = MsiDatabaseOpenView(hdb, query, &hview);
4883     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4884
4885     r = MsiViewExecute(hview, 0);
4886     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4887
4888     r = MsiViewFetch(hview, &hrec);
4889     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4890
4891     r = MsiRecordGetFieldCount(hrec);
4892     ok(r == 2, "Expected 2, got %d\n", r);
4893
4894     r = MsiRecordGetInteger(hrec, 1);
4895     ok(r == 1, "Expected 1, got %d\n", r);
4896
4897     sz = sizeof(buffer);
4898     r = MsiRecordGetString(hrec, 2, buffer, &sz);
4899     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4900     ok(!lstrcmp(buffer, "one"), "Expected one, got %s\n", buffer);
4901
4902     r = MsiCloseHandle(hrec);
4903     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4904
4905     r = MsiViewFetch(hview, &hrec);
4906     todo_wine
4907     {
4908         ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
4909     }
4910
4911     r = MsiViewClose(hview);
4912     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4913     r = MsiCloseHandle(hview);
4914     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4915     r = MsiCloseHandle(hrec);
4916     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4917
4918     query = "SELECT * FROM `AAR`";
4919     r = MsiDatabaseOpenView(hdb, query, &hview);
4920     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4921
4922     r = MsiViewExecute(hview, 0);
4923     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4924
4925     r = MsiViewFetch(hview, &hrec);
4926     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4927
4928     r = MsiRecordGetFieldCount(hrec);
4929     ok(r == 2, "Expected 2, got %d\n", r);
4930
4931     r = MsiRecordGetInteger(hrec, 1);
4932     ok(r == 2, "Expected 2, got %d\n", r);
4933
4934     sz = sizeof(buffer);
4935     r = MsiRecordGetString(hrec, 2, buffer, &sz);
4936     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4937     ok(!lstrcmp(buffer, "two"), "Expected two, got %s\n", buffer);
4938
4939     r = MsiCloseHandle(hrec);
4940     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4941
4942     r = MsiViewFetch(hview, &hrec);
4943     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4944
4945     r = MsiRecordGetFieldCount(hrec);
4946     ok(r == 2, "Expected 2, got %d\n", r);
4947
4948     r = MsiRecordGetInteger(hrec, 1);
4949     ok(r == 5, "Expected 5, got %d\n", r);
4950
4951     sz = sizeof(buffer);
4952     r = MsiRecordGetString(hrec, 2, buffer, &sz);
4953     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4954     ok(!lstrcmp(buffer, "five"), "Expected five, got %s\n", buffer);
4955
4956     r = MsiCloseHandle(hrec);
4957     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4958
4959     r = MsiViewFetch(hview, &hrec);
4960     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
4961
4962     r = MsiViewClose(hview);
4963     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4964     r = MsiCloseHandle(hview);
4965     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4966     r = MsiCloseHandle(hrec);
4967     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4968     r = MsiCloseHandle(hdb);
4969     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4970
4971     MultiByteToWideChar(CP_ACP, 0, msifile, -1, name, 0x20);
4972     hr = StgOpenStorage(name, NULL, mode, NULL, 0, &stg);
4973     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
4974     ok(stg != NULL, "Expected non-NULL storage\n");
4975
4976     hr = IStorage_OpenStream(stg, moo, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm);
4977     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
4978     ok(stm != NULL, "Expected non-NULL stream\n");
4979
4980     hr = IStream_Read(stm, data, MAX_PATH, &read);
4981     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
4982     todo_wine
4983     {
4984         ok(read == 4, "Expected 4, got %d\n", read);
4985         ok(!memcmp(data, data10, read), "Unexpected data\n");
4986     }
4987
4988     hr = IStream_Release(stm);
4989     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
4990
4991     hr = IStorage_OpenStream(stg, aar, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm);
4992     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
4993     ok(stm != NULL, "Expected non-NULL stream\n");
4994
4995     hr = IStream_Read(stm, data, MAX_PATH, &read);
4996     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
4997     ok(read == 8, "Expected 8, got %d\n", read);
4998     todo_wine
4999     {
5000         ok(!memcmp(data, data11, read), "Unexpected data\n");
5001     }
5002
5003     hr = IStream_Release(stm);
5004     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5005
5006     hr = IStorage_OpenStream(stg, stringdata, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm);
5007     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5008     ok(stm != NULL, "Expected non-NULL stream\n");
5009
5010     hr = IStream_Read(stm, buffer, MAX_PATH, &read);
5011     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5012     ok(read == 24, "Expected 24, got %d\n", read);
5013     ok(!memcmp(buffer, data12, read), "Unexpected data\n");
5014
5015     hr = IStream_Release(stm);
5016     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5017
5018     hr = IStorage_OpenStream(stg, stringpool, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm);
5019     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5020     ok(stm != NULL, "Expected non-NULL stream\n");
5021
5022     hr = IStream_Read(stm, data, MAX_PATH, &read);
5023     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5024     todo_wine
5025     {
5026         ok(read == 64, "Expected 64, got %d\n", read);
5027         ok(!memcmp(data, data13, read), "Unexpected data\n");
5028     }
5029
5030     hr = IStream_Release(stm);
5031     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5032
5033     hr = IStorage_Release(stg);
5034     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5035
5036     DeleteFileA(msifile);
5037 }
5038
5039 static void test_viewmodify_delete(void)
5040 {
5041     MSIHANDLE hdb = 0, hview = 0, hrec = 0;
5042     UINT r;
5043     const char *query;
5044     char buffer[0x100];
5045     DWORD sz;
5046
5047     DeleteFile(msifile);
5048
5049     /* just MsiOpenDatabase should not create a file */
5050     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
5051     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5052
5053     query = "CREATE TABLE `phone` ( "
5054             "`id` INT, `name` CHAR(32), `number` CHAR(32) "
5055             "PRIMARY KEY `id`)";
5056     r = run_query(hdb, 0, query);
5057     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5058
5059     query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
5060         "VALUES('1', 'Alan', '5030581')";
5061     r = run_query(hdb, 0, query);
5062     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5063
5064     query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
5065         "VALUES('2', 'Barry', '928440')";
5066     r = run_query(hdb, 0, query);
5067     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5068
5069     query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
5070         "VALUES('3', 'Cindy', '2937550')";
5071     r = run_query(hdb, 0, query);
5072     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5073
5074     query = "SELECT * FROM `phone` WHERE `id` <= 2";
5075     r = MsiDatabaseOpenView(hdb, query, &hview);
5076     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5077     r = MsiViewExecute(hview, 0);
5078     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5079     r = MsiViewFetch(hview, &hrec);
5080     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5081
5082     /* delete 1 */
5083     r = MsiViewModify(hview, MSIMODIFY_DELETE, hrec);
5084     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5085
5086     r = MsiCloseHandle(hrec);
5087     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5088     r = MsiViewFetch(hview, &hrec);
5089     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5090
5091     /* delete 2 */
5092     r = MsiViewModify(hview, MSIMODIFY_DELETE, hrec);
5093     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5094
5095     r = MsiCloseHandle(hrec);
5096     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5097     r = MsiViewClose(hview);
5098     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5099     r = MsiCloseHandle(hview);
5100     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5101
5102     query = "SELECT * FROM `phone`";
5103     r = MsiDatabaseOpenView(hdb, query, &hview);
5104     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5105     r = MsiViewExecute(hview, 0);
5106     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5107     r = MsiViewFetch(hview, &hrec);
5108     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5109
5110     r = MsiRecordGetInteger(hrec, 1);
5111     ok(r == 3, "Expected 3, got %d\n", r);
5112
5113     sz = sizeof(buffer);
5114     r = MsiRecordGetString(hrec, 2, buffer, &sz);
5115     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5116     ok(!lstrcmp(buffer, "Cindy"), "Expected Cindy, got %s\n", buffer);
5117
5118     sz = sizeof(buffer);
5119     r = MsiRecordGetString(hrec, 3, buffer, &sz);
5120     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5121     ok(!lstrcmp(buffer, "2937550"), "Expected 2937550, got %s\n", buffer);
5122
5123     r = MsiCloseHandle(hrec);
5124     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5125
5126     r = MsiViewFetch(hview, &hrec);
5127     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5128
5129     r = MsiViewClose(hview);
5130     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5131     r = MsiCloseHandle(hview);
5132     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5133     r = MsiCloseHandle(hdb);
5134     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5135 }
5136
5137 static const WCHAR _Tables[] = {0x4840, 0x3f7f, 0x4164, 0x422f, 0x4836, 0};
5138 static const WCHAR _StringData[] = {0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0};
5139 static const WCHAR _StringPool[] = {0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0};
5140
5141 static const WCHAR data14[] = { /* _StringPool */
5142 /*  len, refs */
5143     0,   0,    /* string 0 ''    */
5144 };
5145
5146 static const struct {
5147     LPCWSTR name;
5148     const void *data;
5149     DWORD size;
5150 } database_table_data[] =
5151 {
5152     {_Tables, NULL, 0},
5153     {_StringData, NULL, 0},
5154     {_StringPool, data14, sizeof data14},
5155 };
5156
5157 static void enum_stream_names(IStorage *stg)
5158 {
5159     IEnumSTATSTG *stgenum = NULL;
5160     IStream *stm;
5161     HRESULT hr;
5162     STATSTG stat;
5163     ULONG n, count;
5164     BYTE data[MAX_PATH];
5165     BYTE check[MAX_PATH];
5166     DWORD sz;
5167
5168     memset(check, 'a', MAX_PATH);
5169
5170     hr = IStorage_EnumElements(stg, 0, NULL, 0, &stgenum);
5171     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
5172
5173     n = 0;
5174     while(TRUE)
5175     {
5176         count = 0;
5177         hr = IEnumSTATSTG_Next(stgenum, 1, &stat, &count);
5178         if(FAILED(hr) || !count)
5179             break;
5180
5181         ok(!lstrcmpW(stat.pwcsName, database_table_data[n].name),
5182            "Expected table %d name to match\n", n);
5183
5184         stm = NULL;
5185         hr = IStorage_OpenStream(stg, stat.pwcsName, NULL,
5186                                  STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm);
5187         ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
5188         ok(stm != NULL, "Expected non-NULL stream\n");
5189
5190         sz = MAX_PATH;
5191         memset(data, 'a', MAX_PATH);
5192         hr = IStream_Read(stm, data, sz, &count);
5193         ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
5194
5195         ok(count == database_table_data[n].size,
5196            "Expected %d, got %d\n", database_table_data[n].size, count);
5197
5198         if (!database_table_data[n].size)
5199             ok(!memcmp(data, check, MAX_PATH), "data should not be changed\n");
5200         else
5201             ok(!memcmp(data, database_table_data[n].data, database_table_data[n].size),
5202                "Expected table %d data to match\n", n);
5203
5204         IStream_Release(stm);
5205         n++;
5206     }
5207
5208     ok(n == 3, "Expected 3, got %d\n", n);
5209
5210     IEnumSTATSTG_Release(stgenum);
5211 }
5212
5213 static void test_defaultdatabase(void)
5214 {
5215     UINT r;
5216     HRESULT hr;
5217     MSIHANDLE hdb;
5218     IStorage *stg = NULL;
5219
5220     static const WCHAR msifileW[] = {'w','i','n','e','t','e','s','t','.','m','s','i',0};
5221
5222     DeleteFile(msifile);
5223
5224     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
5225     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5226
5227     r = MsiDatabaseCommit(hdb);
5228     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5229
5230     MsiCloseHandle(hdb);
5231
5232     hr = StgOpenStorage(msifileW, NULL, STGM_READ | STGM_SHARE_DENY_WRITE, NULL, 0, &stg);
5233     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
5234     ok(stg != NULL, "Expected non-NULL stg\n");
5235
5236     enum_stream_names(stg);
5237
5238     IStorage_Release(stg);
5239     DeleteFileA(msifile);
5240 }
5241
5242 static void test_order(void)
5243 {
5244     MSIHANDLE hdb, hview, hrec;
5245     CHAR buffer[MAX_PATH];
5246     LPCSTR query;
5247     UINT r, sz;
5248     int val;
5249
5250     hdb = create_db();
5251     ok(hdb, "failed to create db\n");
5252
5253     query = "CREATE TABLE `Empty` ( `A` SHORT NOT NULL PRIMARY KEY `A`)";
5254     r = run_query(hdb, 0, query);
5255     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5256
5257     query = "CREATE TABLE `Mesa` ( `A` SHORT NOT NULL, `B` SHORT, `C` SHORT PRIMARY KEY `A`)";
5258     r = run_query(hdb, 0, query);
5259     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5260
5261     query = "INSERT INTO `Mesa` ( `A`, `B`, `C` ) VALUES ( 1, 2, 9 )";
5262     r = run_query(hdb, 0, query);
5263     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5264
5265     query = "INSERT INTO `Mesa` ( `A`, `B`, `C` ) VALUES ( 3, 4, 7 )";
5266     r = run_query(hdb, 0, query);
5267     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5268
5269     query = "INSERT INTO `Mesa` ( `A`, `B`, `C` ) VALUES ( 5, 6, 8 )";
5270     r = run_query(hdb, 0, query);
5271     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5272
5273     query = "CREATE TABLE `Sideboard` ( `D` SHORT NOT NULL, `E` SHORT, `F` SHORT PRIMARY KEY `D`)";
5274     r = run_query(hdb, 0, query);
5275     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5276
5277     query = "INSERT INTO `Sideboard` ( `D`, `E`, `F` ) VALUES ( 10, 11, 18 )";
5278     r = run_query(hdb, 0, query);
5279     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5280
5281     query = "INSERT INTO `Sideboard` ( `D`, `E`, `F` ) VALUES ( 12, 13, 16 )";
5282     r = run_query(hdb, 0, query);
5283     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5284
5285     query = "INSERT INTO `Sideboard` ( `D`, `E`, `F` ) VALUES ( 14, 15, 17 )";
5286     r = run_query(hdb, 0, query);
5287     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5288
5289     query = "SELECT `A`, `B` FROM `Mesa` ORDER BY `C`";
5290     r = MsiDatabaseOpenView(hdb, query, &hview);
5291     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5292     r = MsiViewExecute(hview, 0);
5293     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5294
5295     r = MsiViewFetch(hview, &hrec);
5296     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5297
5298     val = MsiRecordGetInteger(hrec, 1);
5299     ok(val == 3, "Expected 3, got %d\n", val);
5300
5301     val = MsiRecordGetInteger(hrec, 2);
5302     ok(val == 4, "Expected 3, got %d\n", val);
5303
5304     MsiCloseHandle(hrec);
5305
5306     r = MsiViewFetch(hview, &hrec);
5307     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5308
5309     val = MsiRecordGetInteger(hrec, 1);
5310     ok(val == 5, "Expected 5, got %d\n", val);
5311
5312     val = MsiRecordGetInteger(hrec, 2);
5313     ok(val == 6, "Expected 6, got %d\n", val);
5314
5315     MsiCloseHandle(hrec);
5316
5317     r = MsiViewFetch(hview, &hrec);
5318     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5319
5320     val = MsiRecordGetInteger(hrec, 1);
5321     ok(val == 1, "Expected 1, got %d\n", val);
5322
5323     val = MsiRecordGetInteger(hrec, 2);
5324     ok(val == 2, "Expected 2, got %d\n", val);
5325
5326     MsiCloseHandle(hrec);
5327
5328     r = MsiViewFetch(hview, &hrec);
5329     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5330
5331     MsiViewClose(hview);
5332     MsiCloseHandle(hview);
5333
5334     query = "SELECT `A`, `D` FROM `Mesa`, `Sideboard` ORDER BY `F`";
5335     r = MsiDatabaseOpenView(hdb, query, &hview);
5336     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5337     r = MsiViewExecute(hview, 0);
5338     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5339
5340     r = MsiViewFetch(hview, &hrec);
5341     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5342
5343     val = MsiRecordGetInteger(hrec, 1);
5344     ok(val == 1, "Expected 1, got %d\n", val);
5345
5346     val = MsiRecordGetInteger(hrec, 2);
5347     ok(val == 12, "Expected 12, got %d\n", val);
5348
5349     MsiCloseHandle(hrec);
5350
5351     r = MsiViewFetch(hview, &hrec);
5352     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5353
5354     val = MsiRecordGetInteger(hrec, 1);
5355     ok(val == 3, "Expected 3, got %d\n", val);
5356
5357     val = MsiRecordGetInteger(hrec, 2);
5358     ok(val == 12, "Expected 12, got %d\n", val);
5359
5360     MsiCloseHandle(hrec);
5361
5362     r = MsiViewFetch(hview, &hrec);
5363     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5364
5365     val = MsiRecordGetInteger(hrec, 1);
5366     ok(val == 5, "Expected 5, got %d\n", val);
5367
5368     val = MsiRecordGetInteger(hrec, 2);
5369     ok(val == 12, "Expected 12, got %d\n", val);
5370
5371     MsiCloseHandle(hrec);
5372
5373     r = MsiViewFetch(hview, &hrec);
5374     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5375
5376     val = MsiRecordGetInteger(hrec, 1);
5377     ok(val == 1, "Expected 1, got %d\n", val);
5378
5379     val = MsiRecordGetInteger(hrec, 2);
5380     ok(val == 14, "Expected 14, got %d\n", val);
5381
5382     MsiCloseHandle(hrec);
5383
5384     r = MsiViewFetch(hview, &hrec);
5385     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5386
5387     val = MsiRecordGetInteger(hrec, 1);
5388     ok(val == 3, "Expected 3, got %d\n", val);
5389
5390     val = MsiRecordGetInteger(hrec, 2);
5391     ok(val == 14, "Expected 14, got %d\n", val);
5392
5393     MsiCloseHandle(hrec);
5394
5395     r = MsiViewFetch(hview, &hrec);
5396     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5397
5398     val = MsiRecordGetInteger(hrec, 1);
5399     ok(val == 5, "Expected 5, got %d\n", val);
5400
5401     val = MsiRecordGetInteger(hrec, 2);
5402     ok(val == 14, "Expected 14, got %d\n", val);
5403
5404     MsiCloseHandle(hrec);
5405
5406     r = MsiViewFetch(hview, &hrec);
5407     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5408
5409     val = MsiRecordGetInteger(hrec, 1);
5410     ok(val == 1, "Expected 1, got %d\n", val);
5411
5412     val = MsiRecordGetInteger(hrec, 2);
5413     ok(val == 10, "Expected 10, got %d\n", val);
5414
5415     MsiCloseHandle(hrec);
5416
5417     r = MsiViewFetch(hview, &hrec);
5418     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5419
5420     val = MsiRecordGetInteger(hrec, 1);
5421     ok(val == 3, "Expected 3, got %d\n", val);
5422
5423     val = MsiRecordGetInteger(hrec, 2);
5424     ok(val == 10, "Expected 10, got %d\n", val);
5425
5426     MsiCloseHandle(hrec);
5427
5428     r = MsiViewFetch(hview, &hrec);
5429     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5430
5431     val = MsiRecordGetInteger(hrec, 1);
5432     ok(val == 5, "Expected 5, got %d\n", val);
5433
5434     val = MsiRecordGetInteger(hrec, 2);
5435     ok(val == 10, "Expected 10, got %d\n", val);
5436
5437     MsiCloseHandle(hrec);
5438
5439     r = MsiViewFetch(hview, &hrec);
5440     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5441
5442     MsiViewClose(hview);
5443     MsiCloseHandle(hview);
5444
5445     query = "SELECT * FROM `Empty` ORDER BY `A`";
5446     r = MsiDatabaseOpenView(hdb, query, &hview);
5447     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5448     r = MsiViewExecute(hview, 0);
5449     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5450
5451     r = MsiViewFetch(hview, &hrec);
5452     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5453
5454     MsiViewClose(hview);
5455     MsiCloseHandle(hview);
5456
5457     query = "CREATE TABLE `Buffet` ( `One` CHAR(72), `Two` SHORT PRIMARY KEY `One`)";
5458     r = run_query(hdb, 0, query);
5459     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5460
5461     query = "INSERT INTO `Buffet` ( `One`, `Two` ) VALUES ( 'uno',  2)";
5462     r = run_query(hdb, 0, query);
5463     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5464
5465     query = "INSERT INTO `Buffet` ( `One`, `Two` ) VALUES ( 'dos',  3)";
5466     r = run_query(hdb, 0, query);
5467     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5468
5469     query = "INSERT INTO `Buffet` ( `One`, `Two` ) VALUES ( 'tres',  1)";
5470     r = run_query(hdb, 0, query);
5471     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5472
5473     query = "SELECT * FROM `Buffet` WHERE `One` = 'dos' ORDER BY `Two`";
5474     r = MsiDatabaseOpenView(hdb, query, &hview);
5475     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5476     r = MsiViewExecute(hview, 0);
5477     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5478
5479     r = MsiViewFetch(hview, &hrec);
5480     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5481
5482     sz = sizeof(buffer);
5483     r = MsiRecordGetString(hrec, 1, buffer, &sz);
5484     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5485     ok(!lstrcmp(buffer, "dos"), "Expected \"dos\", got \"%s\"\n", buffer);
5486
5487     r = MsiRecordGetInteger(hrec, 2);
5488     ok(r == 3, "Expected 3, got %d\n", r);
5489
5490     MsiCloseHandle(hrec);
5491
5492     r = MsiViewFetch(hview, &hrec);
5493     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5494
5495     MsiViewClose(hview);
5496     MsiCloseHandle(hview);
5497     MsiCloseHandle(hdb);
5498 }
5499
5500 static void test_viewmodify_delete_temporary(void)
5501 {
5502     MSIHANDLE hdb, hview, hrec;
5503     const char *query;
5504     UINT r;
5505
5506     DeleteFile(msifile);
5507
5508     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
5509     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5510
5511     query = "CREATE TABLE `Table` ( `A` SHORT PRIMARY KEY `A` )";
5512     r = run_query(hdb, 0, query);
5513     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5514
5515     query = "SELECT * FROM `Table`";
5516     r = MsiDatabaseOpenView(hdb, query, &hview);
5517     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5518     r = MsiViewExecute(hview, 0);
5519     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5520
5521     hrec = MsiCreateRecord(1);
5522     MsiRecordSetInteger(hrec, 1, 1);
5523
5524     r = MsiViewModify(hview, MSIMODIFY_INSERT, hrec);
5525     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5526
5527     MsiCloseHandle(hrec);
5528
5529     hrec = MsiCreateRecord(1);
5530     MsiRecordSetInteger(hrec, 1, 2);
5531
5532     r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec);
5533     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5534
5535     MsiCloseHandle(hrec);
5536
5537     hrec = MsiCreateRecord(1);
5538     MsiRecordSetInteger(hrec, 1, 3);
5539
5540     r = MsiViewModify(hview, MSIMODIFY_INSERT, hrec);
5541     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5542
5543     MsiCloseHandle(hrec);
5544
5545     hrec = MsiCreateRecord(1);
5546     MsiRecordSetInteger(hrec, 1, 4);
5547
5548     r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec);
5549     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5550
5551     MsiCloseHandle(hrec);
5552     MsiViewClose(hview);
5553     MsiCloseHandle(hview);
5554
5555     query = "SELECT * FROM `Table` WHERE  `A` = 2";
5556     r = MsiDatabaseOpenView(hdb, query, &hview);
5557     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5558     r = MsiViewExecute(hview, 0);
5559     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5560     r = MsiViewFetch(hview, &hrec);
5561     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5562
5563     r = MsiViewModify(hview, MSIMODIFY_DELETE, hrec);
5564     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5565
5566     MsiCloseHandle(hrec);
5567     MsiViewClose(hview);
5568     MsiCloseHandle(hview);
5569
5570     query = "SELECT * FROM `Table` WHERE  `A` = 3";
5571     r = MsiDatabaseOpenView(hdb, query, &hview);
5572     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5573     r = MsiViewExecute(hview, 0);
5574     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5575     r = MsiViewFetch(hview, &hrec);
5576     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5577
5578     r = MsiViewModify(hview, MSIMODIFY_DELETE, hrec);
5579     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5580
5581     MsiCloseHandle(hrec);
5582     MsiViewClose(hview);
5583     MsiCloseHandle(hview);
5584
5585     query = "SELECT * FROM `Table` ORDER BY `A`";
5586     r = MsiDatabaseOpenView(hdb, query, &hview);
5587     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5588     r = MsiViewExecute(hview, 0);
5589     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5590
5591     r = MsiViewFetch(hview, &hrec);
5592     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5593
5594     r = MsiRecordGetInteger(hrec, 1);
5595     ok(r == 1, "Expected 1, got %d\n", r);
5596
5597     MsiCloseHandle(hrec);
5598
5599     r = MsiViewFetch(hview, &hrec);
5600     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5601
5602     r = MsiRecordGetInteger(hrec, 1);
5603     ok(r == 4, "Expected 4, got %d\n", r);
5604
5605     MsiCloseHandle(hrec);
5606
5607     r = MsiViewFetch(hview, &hrec);
5608     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5609
5610     MsiViewClose(hview);
5611     MsiCloseHandle(hview);
5612     MsiCloseHandle(hdb);
5613     DeleteFileA(msifile);
5614 }
5615
5616 static void test_deleterow(void)
5617 {
5618     MSIHANDLE hdb, hview, hrec;
5619     const char *query;
5620     char buf[MAX_PATH];
5621     UINT r;
5622     DWORD size;
5623
5624     DeleteFile(msifile);
5625
5626     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
5627     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5628
5629     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
5630     r = run_query(hdb, 0, query);
5631     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5632
5633     query = "INSERT INTO `Table` (`A`) VALUES ('one')";
5634     r = run_query(hdb, 0, query);
5635     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5636
5637     query = "INSERT INTO `Table` (`A`) VALUES ('two')";
5638     r = run_query(hdb, 0, query);
5639     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5640
5641     query = "DELETE FROM `Table` WHERE `A` = 'one'";
5642     r = run_query(hdb, 0, query);
5643     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5644
5645     r = MsiDatabaseCommit(hdb);
5646     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5647
5648     MsiCloseHandle(hdb);
5649
5650     r = MsiOpenDatabase(msifile, MSIDBOPEN_READONLY, &hdb);
5651     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5652
5653     query = "SELECT * FROM `Table`";
5654     r = MsiDatabaseOpenView(hdb, query, &hview);
5655     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5656     r = MsiViewExecute(hview, 0);
5657     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5658
5659     r = MsiViewFetch(hview, &hrec);
5660     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5661
5662     size = MAX_PATH;
5663     r = MsiRecordGetStringA(hrec, 1, buf, &size);
5664     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5665     ok(!lstrcmpA(buf, "two"), "Expected two, got %s\n", buf);
5666
5667     MsiCloseHandle(hrec);
5668
5669     r = MsiViewFetch(hview, &hrec);
5670     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5671
5672     MsiViewClose(hview);
5673     MsiCloseHandle(hview);
5674     MsiCloseHandle(hdb);
5675     DeleteFileA(msifile);
5676 }
5677
5678 static const CHAR import_dat[] = "A\n"
5679                                  "s72\n"
5680                                  "Table\tA\n"
5681                                  "This is a new 'string' ok\n";
5682
5683 static void test_quotes(void)
5684 {
5685     MSIHANDLE hdb, hview, hrec;
5686     const char *query;
5687     char buf[MAX_PATH];
5688     UINT r;
5689     DWORD size;
5690
5691     DeleteFile(msifile);
5692
5693     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
5694     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5695
5696     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
5697     r = run_query(hdb, 0, query);
5698     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5699
5700     query = "INSERT INTO `Table` ( `A` ) VALUES ( 'This is a 'string' ok' )";
5701     r = run_query(hdb, 0, query);
5702     ok(r == ERROR_BAD_QUERY_SYNTAX,
5703        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5704
5705     query = "INSERT INTO `Table` ( `A` ) VALUES ( \"This is a 'string' ok\" )";
5706     r = run_query(hdb, 0, query);
5707     ok(r == ERROR_BAD_QUERY_SYNTAX,
5708        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5709
5710     query = "INSERT INTO `Table` ( `A` ) VALUES ( \"test\" )";
5711     r = run_query(hdb, 0, query);
5712     ok(r == ERROR_BAD_QUERY_SYNTAX,
5713        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5714
5715     query = "INSERT INTO `Table` ( `A` ) VALUES ( 'This is a ''string'' ok' )";
5716     r = run_query(hdb, 0, query);
5717     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5718
5719     query = "INSERT INTO `Table` ( `A` ) VALUES ( 'This is a '''string''' ok' )";
5720     r = run_query(hdb, 0, query);
5721     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5722
5723     query = "INSERT INTO `Table` ( `A` ) VALUES ( 'This is a \'string\' ok' )";
5724     r = run_query(hdb, 0, query);
5725     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5726
5727     query = "INSERT INTO `Table` ( `A` ) VALUES ( 'This is a \"string\" ok' )";
5728     r = run_query(hdb, 0, query);
5729     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5730
5731     query = "SELECT * FROM `Table`";
5732     r = MsiDatabaseOpenView(hdb, query, &hview);
5733     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5734
5735     r = MsiViewExecute(hview, 0);
5736     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5737
5738     r = MsiViewFetch(hview, &hrec);
5739     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5740
5741     size = MAX_PATH;
5742     r = MsiRecordGetString(hrec, 1, buf, &size);
5743     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5744     ok(!lstrcmp(buf, "This is a \"string\" ok"),
5745        "Expected \"This is a \"string\" ok\", got %s\n", buf);
5746
5747     MsiCloseHandle(hrec);
5748
5749     r = MsiViewFetch(hview, &hrec);
5750     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5751
5752     MsiViewClose(hview);
5753     MsiCloseHandle(hview);
5754
5755     write_file("import.idt", import_dat, (sizeof(import_dat) - 1) * sizeof(char));
5756
5757     r = MsiDatabaseImportA(hdb, CURR_DIR, "import.idt");
5758     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5759
5760     DeleteFileA("import.idt");
5761
5762     query = "SELECT * FROM `Table`";
5763     r = MsiDatabaseOpenView(hdb, query, &hview);
5764     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5765
5766     r = MsiViewExecute(hview, 0);
5767     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5768
5769     r = MsiViewFetch(hview, &hrec);
5770     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5771
5772     size = MAX_PATH;
5773     r = MsiRecordGetString(hrec, 1, buf, &size);
5774     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5775     ok(!lstrcmp(buf, "This is a new 'string' ok"),
5776        "Expected \"This is a new 'string' ok\", got %s\n", buf);
5777
5778     MsiCloseHandle(hrec);
5779
5780     r = MsiViewFetch(hview, &hrec);
5781     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5782
5783     MsiViewClose(hview);
5784     MsiCloseHandle(hview);
5785     MsiCloseHandle(hdb);
5786     DeleteFileA(msifile);
5787 }
5788
5789 static void test_carriagereturn(void)
5790 {
5791     MSIHANDLE hdb, hview, hrec;
5792     const char *query;
5793     char buf[MAX_PATH];
5794     UINT r;
5795     DWORD size;
5796
5797     DeleteFile(msifile);
5798
5799     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
5800     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5801
5802     query = "CREATE TABLE `Table`\r ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
5803     r = run_query(hdb, 0, query);
5804     ok(r == ERROR_BAD_QUERY_SYNTAX,
5805        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5806
5807     query = "CREATE TABLE `Table` \r( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
5808     r = run_query(hdb, 0, query);
5809     ok(r == ERROR_BAD_QUERY_SYNTAX,
5810        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5811
5812     query = "CREATE\r TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
5813     r = run_query(hdb, 0, query);
5814     ok(r == ERROR_BAD_QUERY_SYNTAX,
5815        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5816
5817     query = "CREATE TABLE\r `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
5818     r = run_query(hdb, 0, query);
5819     ok(r == ERROR_BAD_QUERY_SYNTAX,
5820        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5821
5822     query = "CREATE TABLE `Table` (\r `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
5823     r = run_query(hdb, 0, query);
5824     ok(r == ERROR_BAD_QUERY_SYNTAX,
5825        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5826
5827     query = "CREATE TABLE `Table` ( `A`\r CHAR(72) NOT NULL PRIMARY KEY `A` )";
5828     r = run_query(hdb, 0, query);
5829     ok(r == ERROR_BAD_QUERY_SYNTAX,
5830        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5831
5832     query = "CREATE TABLE `Table` ( `A` CHAR(72)\r NOT NULL PRIMARY KEY `A` )";
5833     r = run_query(hdb, 0, query);
5834     ok(r == ERROR_BAD_QUERY_SYNTAX,
5835        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5836
5837     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT\r NULL PRIMARY KEY `A` )";
5838     r = run_query(hdb, 0, query);
5839     ok(r == ERROR_BAD_QUERY_SYNTAX,
5840        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5841
5842     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT \rNULL PRIMARY KEY `A` )";
5843     r = run_query(hdb, 0, query);
5844     ok(r == ERROR_BAD_QUERY_SYNTAX,
5845        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5846
5847     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL\r PRIMARY KEY `A` )";
5848     r = run_query(hdb, 0, query);
5849     ok(r == ERROR_BAD_QUERY_SYNTAX,
5850        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5851
5852     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL \rPRIMARY KEY `A` )";
5853     r = run_query(hdb, 0, query);
5854     ok(r == ERROR_BAD_QUERY_SYNTAX,
5855        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5856
5857     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY\r KEY `A` )";
5858     r = run_query(hdb, 0, query);
5859     ok(r == ERROR_BAD_QUERY_SYNTAX,
5860        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5861
5862     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY \rKEY `A` )";
5863     r = run_query(hdb, 0, query);
5864     ok(r == ERROR_BAD_QUERY_SYNTAX,
5865        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5866
5867     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY\r `A` )";
5868     r = run_query(hdb, 0, query);
5869     ok(r == ERROR_BAD_QUERY_SYNTAX,
5870        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5871
5872     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A`\r )";
5873     r = run_query(hdb, 0, query);
5874     ok(r == ERROR_BAD_QUERY_SYNTAX,
5875        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5876
5877     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )\r";
5878     r = run_query(hdb, 0, query);
5879     ok(r == ERROR_BAD_QUERY_SYNTAX,
5880        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5881
5882     query = "CREATE TABLE `\rOne` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
5883     r = run_query(hdb, 0, query);
5884     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5885
5886     query = "CREATE TABLE `Tw\ro` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
5887     r = run_query(hdb, 0, query);
5888     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5889
5890     query = "CREATE TABLE `Three\r` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
5891     r = run_query(hdb, 0, query);
5892     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5893
5894     query = "CREATE TABLE `Four` ( `A\r` CHAR(72) NOT NULL PRIMARY KEY `A` )";
5895     r = run_query(hdb, 0, query);
5896     ok(r == ERROR_BAD_QUERY_SYNTAX,
5897        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5898
5899     query = "CREATE TABLE `Four` ( `\rA` CHAR(72) NOT NULL PRIMARY KEY `A` )";
5900     r = run_query(hdb, 0, query);
5901     ok(r == ERROR_BAD_QUERY_SYNTAX,
5902        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5903
5904     query = "CREATE TABLE `Four` ( `A` CHAR(72\r) NOT NULL PRIMARY KEY `A` )";
5905     r = run_query(hdb, 0, query);
5906     ok(r == ERROR_BAD_QUERY_SYNTAX,
5907        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5908
5909     query = "CREATE TABLE `Four` ( `A` CHAR(\r72) NOT NULL PRIMARY KEY `A` )";
5910     r = run_query(hdb, 0, query);
5911     ok(r == ERROR_BAD_QUERY_SYNTAX,
5912        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5913
5914     query = "CREATE TABLE `Four` ( `A` CHAR(72) NOT NULL PRIMARY KEY `\rA` )";
5915     r = run_query(hdb, 0, query);
5916     ok(r == ERROR_BAD_QUERY_SYNTAX,
5917        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5918
5919     query = "CREATE TABLE `Four` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A\r` )";
5920     r = run_query(hdb, 0, query);
5921     ok(r == ERROR_BAD_QUERY_SYNTAX,
5922        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5923
5924     query = "CREATE TABLE `Four` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A\r` )";
5925     r = run_query(hdb, 0, query);
5926     ok(r == ERROR_BAD_QUERY_SYNTAX,
5927        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5928
5929     query = "SELECT * FROM `_Tables`";
5930     r = MsiDatabaseOpenView(hdb, query, &hview);
5931     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5932     r = MsiViewExecute(hview, 0);
5933     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5934
5935     r = MsiViewFetch(hview, &hrec);
5936     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5937
5938     size = MAX_PATH;
5939     r = MsiRecordGetStringA(hrec, 1, buf, &size);
5940     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5941     ok(!lstrcmpA(buf, "\rOne"), "Expected \"\\rOne\", got \"%s\"\n", buf);
5942
5943     MsiCloseHandle(hrec);
5944
5945     r = MsiViewFetch(hview, &hrec);
5946     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5947
5948     size = MAX_PATH;
5949     r = MsiRecordGetStringA(hrec, 1, buf, &size);
5950     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5951     ok(!lstrcmpA(buf, "Tw\ro"), "Expected \"Tw\\ro\", got \"%s\"\n", buf);
5952
5953     MsiCloseHandle(hrec);
5954
5955     r = MsiViewFetch(hview, &hrec);
5956     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5957
5958     size = MAX_PATH;
5959     r = MsiRecordGetStringA(hrec, 1, buf, &size);
5960     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5961     ok(!lstrcmpA(buf, "Three\r"), "Expected \"Three\r\", got \"%s\"\n", buf);
5962
5963     MsiCloseHandle(hrec);
5964
5965     r = MsiViewFetch(hview, &hrec);
5966     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5967
5968     MsiViewClose(hview);
5969     MsiCloseHandle(hview);
5970
5971     MsiCloseHandle(hdb);
5972     DeleteFileA(msifile);
5973 }
5974
5975 static void test_noquotes(void)
5976 {
5977     MSIHANDLE hdb, hview, hrec;
5978     const char *query;
5979     char buf[MAX_PATH];
5980     UINT r;
5981     DWORD size;
5982
5983     DeleteFile(msifile);
5984
5985     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
5986     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5987
5988     query = "CREATE TABLE Table ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
5989     r = run_query(hdb, 0, query);
5990     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5991
5992     query = "CREATE TABLE `Table` ( A CHAR(72) NOT NULL PRIMARY KEY `A` )";
5993     r = run_query(hdb, 0, query);
5994     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5995
5996     query = "CREATE TABLE `Table2` ( `A` CHAR(72) NOT NULL PRIMARY KEY A )";
5997     r = run_query(hdb, 0, query);
5998     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5999
6000     query = "CREATE TABLE `Table3` ( A CHAR(72) NOT NULL PRIMARY KEY A )";
6001     r = run_query(hdb, 0, query);
6002     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6003
6004     query = "SELECT * FROM `_Tables`";
6005     r = MsiDatabaseOpenView(hdb, query, &hview);
6006     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6007     r = MsiViewExecute(hview, 0);
6008     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6009
6010     r = MsiViewFetch(hview, &hrec);
6011     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6012
6013     size = MAX_PATH;
6014     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6015     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6016     ok(!lstrcmpA(buf, "Table"), "Expected \"Table\", got \"%s\"\n", buf);
6017
6018     MsiCloseHandle(hrec);
6019
6020     r = MsiViewFetch(hview, &hrec);
6021     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6022
6023     size = MAX_PATH;
6024     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6025     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6026     ok(!lstrcmpA(buf, "Table2"), "Expected \"Table2\", got \"%s\"\n", buf);
6027
6028     MsiCloseHandle(hrec);
6029
6030     r = MsiViewFetch(hview, &hrec);
6031     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6032
6033     size = MAX_PATH;
6034     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6035     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6036     ok(!lstrcmpA(buf, "Table3"), "Expected \"Table3\", got \"%s\"\n", buf);
6037
6038     MsiCloseHandle(hrec);
6039
6040     r = MsiViewFetch(hview, &hrec);
6041     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6042
6043     MsiViewClose(hview);
6044     MsiCloseHandle(hview);
6045
6046     query = "SELECT * FROM `_Columns`";
6047     r = MsiDatabaseOpenView(hdb, query, &hview);
6048     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6049     r = MsiViewExecute(hview, 0);
6050     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6051
6052     r = MsiViewFetch(hview, &hrec);
6053     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6054
6055     size = MAX_PATH;
6056     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6057     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6058     ok(!lstrcmpA(buf, "Table"), "Expected \"Table\", got \"%s\"\n", buf);
6059
6060     r = MsiRecordGetInteger(hrec, 2);
6061     ok(r == 1, "Expected 1, got %d\n", r);
6062
6063     size = MAX_PATH;
6064     r = MsiRecordGetStringA(hrec, 3, buf, &size);
6065     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6066     ok(!lstrcmpA(buf, "A"), "Expected \"A\", got \"%s\"\n", buf);
6067
6068     MsiCloseHandle(hrec);
6069
6070     r = MsiViewFetch(hview, &hrec);
6071     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6072
6073     size = MAX_PATH;
6074     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6075     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6076     ok(!lstrcmpA(buf, "Table2"), "Expected \"Table2\", got \"%s\"\n", buf);
6077
6078     r = MsiRecordGetInteger(hrec, 2);
6079     ok(r == 1, "Expected 1, got %d\n", r);
6080
6081     size = MAX_PATH;
6082     r = MsiRecordGetStringA(hrec, 3, buf, &size);
6083     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6084     ok(!lstrcmpA(buf, "A"), "Expected \"A\", got \"%s\"\n", buf);
6085
6086     MsiCloseHandle(hrec);
6087
6088     r = MsiViewFetch(hview, &hrec);
6089     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6090
6091     size = MAX_PATH;
6092     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6093     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6094     ok(!lstrcmpA(buf, "Table3"), "Expected \"Table3\", got \"%s\"\n", buf);
6095
6096     r = MsiRecordGetInteger(hrec, 2);
6097     ok(r == 1, "Expected 1, got %d\n", r);
6098
6099     size = MAX_PATH;
6100     r = MsiRecordGetStringA(hrec, 3, buf, &size);
6101     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6102     ok(!lstrcmpA(buf, "A"), "Expected \"A\", got \"%s\"\n", buf);
6103
6104     MsiCloseHandle(hrec);
6105
6106     r = MsiViewFetch(hview, &hrec);
6107     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6108
6109     MsiViewClose(hview);
6110     MsiCloseHandle(hview);
6111
6112     query = "INSERT INTO Table ( `A` ) VALUES ( 'hi' )";
6113     r = run_query(hdb, 0, query);
6114     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6115
6116     query = "INSERT INTO `Table` ( A ) VALUES ( 'hi' )";
6117     r = run_query(hdb, 0, query);
6118     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6119
6120     query = "INSERT INTO `Table` ( `A` ) VALUES ( hi )";
6121     r = run_query(hdb, 0, query);
6122     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6123
6124     query = "SELECT * FROM Table WHERE `A` = 'hi'";
6125     r = run_query(hdb, 0, query);
6126     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6127
6128     query = "SELECT * FROM `Table` WHERE `A` = hi";
6129     r = run_query(hdb, 0, query);
6130     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6131
6132     query = "SELECT * FROM Table";
6133     r = run_query(hdb, 0, query);
6134     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6135
6136     query = "SELECT * FROM Table2";
6137     r = MsiDatabaseOpenView(hdb, query, &hview);
6138     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6139     r = MsiViewExecute(hview, 0);
6140     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6141
6142     r = MsiViewFetch(hview, &hrec);
6143     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6144
6145     MsiViewClose(hview);
6146     MsiCloseHandle(hview);
6147
6148     query = "SELECT * FROM `Table` WHERE A = 'hi'";
6149     r = MsiDatabaseOpenView(hdb, query, &hview);
6150     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6151     r = MsiViewExecute(hview, 0);
6152     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6153
6154     r = MsiViewFetch(hview, &hrec);
6155     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6156
6157     size = MAX_PATH;
6158     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6159     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6160     ok(!lstrcmpA(buf, "hi"), "Expected \"hi\", got \"%s\"\n", buf);
6161
6162     MsiCloseHandle(hrec);
6163
6164     r = MsiViewFetch(hview, &hrec);
6165     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6166
6167     MsiViewClose(hview);
6168     MsiCloseHandle(hview);
6169     MsiCloseHandle(hdb);
6170     DeleteFileA(msifile);
6171 }
6172
6173 static void read_file_data(LPCSTR filename, LPSTR buffer)
6174 {
6175     HANDLE file;
6176     DWORD read;
6177
6178     file = CreateFileA( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
6179     ZeroMemory(buffer, MAX_PATH);
6180     ReadFile(file, buffer, MAX_PATH, &read, NULL);
6181     CloseHandle(file);
6182 }
6183
6184 static void test_forcecodepage(void)
6185 {
6186     MSIHANDLE hdb;
6187     const char *query;
6188     char buffer[MAX_PATH];
6189     UINT r;
6190
6191     DeleteFile(msifile);
6192
6193     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
6194     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6195
6196     query = "SELECT * FROM `_ForceCodepage`";
6197     r = run_query(hdb, 0, query);
6198     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6199
6200     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6201     r = run_query(hdb, 0, query);
6202     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6203
6204     query = "SELECT * FROM `_ForceCodepage`";
6205     r = run_query(hdb, 0, query);
6206     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6207
6208     r = MsiDatabaseCommit(hdb);
6209     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6210
6211     query = "SELECT * FROM `_ForceCodepage`";
6212     r = run_query(hdb, 0, query);
6213     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6214
6215     MsiCloseHandle(hdb);
6216
6217     r = MsiOpenDatabase(msifile, MSIDBOPEN_DIRECT, &hdb);
6218     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6219
6220     query = "SELECT * FROM `_ForceCodepage`";
6221     r = run_query(hdb, 0, query);
6222     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6223
6224     r = MsiDatabaseExport(hdb, "_ForceCodepage", CURR_DIR, "forcecodepage.idt");
6225     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6226
6227     read_file_data("forcecodepage.idt", buffer);
6228     ok(!lstrcmpA(buffer, "\r\n\r\n0\t_ForceCodepage\r\n"),
6229        "Expected \"\r\n\r\n0\t_ForceCodepage\r\n\", got \"%s\"", buffer);
6230
6231     MsiCloseHandle(hdb);
6232     DeleteFileA(msifile);
6233     DeleteFileA("forcecodepage.idt");
6234 }
6235
6236 static void test_viewmodify_refresh(void)
6237 {
6238     MSIHANDLE hdb, hview, hrec;
6239     const char *query;
6240     char buffer[MAX_PATH];
6241     UINT r;
6242     DWORD size;
6243
6244     DeleteFile(msifile);
6245
6246     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
6247     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6248
6249     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL, `B` INT PRIMARY KEY `A` )";
6250     r = run_query(hdb, 0, query);
6251     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6252
6253     query = "INSERT INTO `Table` ( `A`, `B` ) VALUES ( 'hi', 1 )";
6254     r = run_query(hdb, 0, query);
6255     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6256
6257     query = "SELECT * FROM `Table`";
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_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6265
6266     query = "UPDATE `Table` SET `B` = 2 WHERE `A` = 'hi'";
6267     r = run_query(hdb, 0, query);
6268     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6269
6270     r = MsiViewModify(hview, MSIMODIFY_REFRESH, hrec);
6271     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6272
6273     size = MAX_PATH;
6274     r = MsiRecordGetStringA(hrec, 1, buffer, &size);
6275     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6276     ok(!lstrcmpA(buffer, "hi"), "Expected \"hi\", got \"%s\"\n", buffer);
6277     ok(size == 2, "Expected 2, got %d\n", size);
6278
6279     r = MsiRecordGetInteger(hrec, 2);
6280     ok(r == 2, "Expected 2, got %d\n", r);
6281
6282     MsiCloseHandle(hrec);
6283     MsiViewClose(hview);
6284     MsiCloseHandle(hview);
6285
6286     query = "INSERT INTO `Table` ( `A`, `B` ) VALUES ( 'hello', 3 )";
6287     r = run_query(hdb, 0, query);
6288     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6289
6290     query = "SELECT * FROM `Table` WHERE `B` = 3";
6291     r = MsiDatabaseOpenView(hdb, query, &hview);
6292     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6293     r = MsiViewExecute(hview, 0);
6294     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6295
6296     r = MsiViewFetch(hview, &hrec);
6297     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6298
6299     query = "UPDATE `Table` SET `B` = 2 WHERE `A` = 'hello'";
6300     r = run_query(hdb, 0, query);
6301     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6302
6303     query = "INSERT INTO `Table` ( `A`, `B` ) VALUES ( 'hithere', 3 )";
6304     r = run_query(hdb, 0, query);
6305     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6306
6307     r = MsiViewModify(hview, MSIMODIFY_REFRESH, hrec);
6308     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6309
6310     size = MAX_PATH;
6311     r = MsiRecordGetStringA(hrec, 1, buffer, &size);
6312     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6313     ok(!lstrcmpA(buffer, "hello"), "Expected \"hello\", got \"%s\"\n", buffer);
6314     ok(size == 5, "Expected 5, got %d\n", size);
6315
6316     r = MsiRecordGetInteger(hrec, 2);
6317     ok(r == 2, "Expected 2, got %d\n", r);
6318
6319     MsiCloseHandle(hrec);
6320     MsiViewClose(hview);
6321     MsiCloseHandle(hview);
6322     MsiCloseHandle(hdb);
6323     DeleteFileA(msifile);
6324 }
6325
6326 static void test_where_viewmodify(void)
6327 {
6328     MSIHANDLE hdb, hview, hrec;
6329     const char *query;
6330     UINT r;
6331
6332     DeleteFile(msifile);
6333
6334     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
6335     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6336
6337     query = "CREATE TABLE `Table` ( `A` INT, `B` INT PRIMARY KEY `A` )";
6338     r = run_query(hdb, 0, query);
6339     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6340
6341     query = "INSERT INTO `Table` ( `A`, `B` ) VALUES ( 1, 2 )";
6342     r = run_query(hdb, 0, query);
6343     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6344
6345     query = "INSERT INTO `Table` ( `A`, `B` ) VALUES ( 3, 4 )";
6346     r = run_query(hdb, 0, query);
6347     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6348
6349     query = "INSERT INTO `Table` ( `A`, `B` ) VALUES ( 5, 6 )";
6350     r = run_query(hdb, 0, query);
6351     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6352
6353     /* `B` = 3 doesn't match, but the view shouldn't be executed */
6354     query = "SELECT * FROM `Table` WHERE `B` = 3";
6355     r = MsiDatabaseOpenView(hdb, query, &hview);
6356     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6357
6358     hrec = MsiCreateRecord(2);
6359     MsiRecordSetInteger(hrec, 1, 7);
6360     MsiRecordSetInteger(hrec, 2, 8);
6361
6362     r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec);
6363     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6364
6365     MsiCloseHandle(hrec);
6366     MsiViewClose(hview);
6367     MsiCloseHandle(hview);
6368
6369     query = "SELECT * FROM `Table` WHERE `A` = 7";
6370     r = MsiDatabaseOpenView(hdb, query, &hview);
6371     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6372     r = MsiViewExecute(hview, 0);
6373     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6374
6375     r = MsiViewFetch(hview, &hrec);
6376     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6377
6378     r = MsiRecordGetInteger(hrec, 1);
6379     ok(r == 7, "Expected 7, got %d\n", r);
6380
6381     r = MsiRecordGetInteger(hrec, 2);
6382     ok(r == 8, "Expected 8, got %d\n", r);
6383
6384     MsiRecordSetInteger(hrec, 2, 9);
6385
6386     r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
6387     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6388
6389     MsiCloseHandle(hrec);
6390     MsiViewClose(hview);
6391     MsiCloseHandle(hview);
6392
6393     query = "SELECT * FROM `Table` WHERE `A` = 7";
6394     r = MsiDatabaseOpenView(hdb, query, &hview);
6395     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6396     r = MsiViewExecute(hview, 0);
6397     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6398
6399     r = MsiViewFetch(hview, &hrec);
6400     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6401
6402     r = MsiRecordGetInteger(hrec, 1);
6403     ok(r == 7, "Expected 7, got %d\n", r);
6404
6405     r = MsiRecordGetInteger(hrec, 2);
6406     ok(r == 9, "Expected 9, got %d\n", r);
6407
6408     query = "UPDATE `Table` SET `B` = 10 WHERE `A` = 7";
6409     r = run_query(hdb, 0, query);
6410     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6411
6412     r = MsiViewModify(hview, MSIMODIFY_REFRESH, hrec);
6413     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6414
6415     r = MsiRecordGetInteger(hrec, 1);
6416     ok(r == 7, "Expected 7, got %d\n", r);
6417
6418     r = MsiRecordGetInteger(hrec, 2);
6419     ok(r == 10, "Expected 10, got %d\n", r);
6420
6421     MsiCloseHandle(hrec);
6422     MsiViewClose(hview);
6423     MsiCloseHandle(hview);
6424     MsiCloseHandle(hdb);
6425 }
6426
6427 static BOOL create_storage(LPCSTR name)
6428 {
6429     WCHAR nameW[MAX_PATH];
6430     IStorage *stg;
6431     IStream *stm;
6432     HRESULT hr;
6433     DWORD count;
6434     BOOL res = FALSE;
6435
6436     MultiByteToWideChar(CP_ACP, 0, name, -1, nameW, MAX_PATH);
6437     hr = StgCreateDocfile(nameW, STGM_CREATE | STGM_READWRITE |
6438                           STGM_DIRECT | STGM_SHARE_EXCLUSIVE, 0, &stg);
6439     if (FAILED(hr))
6440         return FALSE;
6441
6442     hr = IStorage_CreateStream(stg, nameW, STGM_WRITE | STGM_SHARE_EXCLUSIVE,
6443                                0, 0, &stm);
6444     if (FAILED(hr))
6445         goto done;
6446
6447     hr = IStream_Write(stm, "stgdata", 8, &count);
6448     if (SUCCEEDED(hr))
6449         res = TRUE;
6450
6451 done:
6452     IStream_Release(stm);
6453     IStorage_Release(stg);
6454
6455     return res;
6456 }
6457
6458 static void test_storages_table(void)
6459 {
6460     MSIHANDLE hdb, hview, hrec;
6461     IStorage *stg, *inner;
6462     IStream *stm;
6463     char file[MAX_PATH];
6464     char buf[MAX_PATH];
6465     WCHAR name[MAX_PATH];
6466     LPCSTR query;
6467     HRESULT hr;
6468     DWORD size;
6469     UINT r;
6470
6471     hdb = create_db();
6472     ok(hdb, "failed to create db\n");
6473
6474     r = MsiDatabaseCommit(hdb);
6475     ok(r == ERROR_SUCCESS , "Failed to commit database\n");
6476
6477     MsiCloseHandle(hdb);
6478
6479     r = MsiOpenDatabase(msifile, MSIDBOPEN_TRANSACT, &hdb);
6480     ok(r == ERROR_SUCCESS , "Failed to open database\n");
6481
6482     /* check the column types */
6483     hrec = get_column_info(hdb, "SELECT * FROM `_Storages`", MSICOLINFO_TYPES);
6484     ok(hrec, "failed to get column info hrecord\n");
6485     ok(check_record(hrec, 1, "s62"), "wrong hrecord type\n");
6486     ok(check_record(hrec, 2, "V0"), "wrong hrecord type\n");
6487
6488     MsiCloseHandle(hrec);
6489
6490     /* now try the names */
6491     hrec = get_column_info(hdb, "SELECT * FROM `_Storages`", MSICOLINFO_NAMES);
6492     ok(hrec, "failed to get column info hrecord\n");
6493     ok(check_record(hrec, 1, "Name"), "wrong hrecord type\n");
6494     ok(check_record(hrec, 2, "Data"), "wrong hrecord type\n");
6495
6496     MsiCloseHandle(hrec);
6497
6498     create_storage("storage.bin");
6499
6500     hrec = MsiCreateRecord(2);
6501     MsiRecordSetString(hrec, 1, "stgname");
6502
6503     r = MsiRecordSetStream(hrec, 2, "storage.bin");
6504     ok(r == ERROR_SUCCESS, "Failed to add stream data to the hrecord: %d\n", r);
6505
6506     DeleteFileA("storage.bin");
6507
6508     query = "INSERT INTO `_Storages` (`Name`, `Data`) VALUES (?, ?)";
6509     r = MsiDatabaseOpenView(hdb, query, &hview);
6510     ok(r == ERROR_SUCCESS, "Failed to open database hview: %d\n", r);
6511
6512     r = MsiViewExecute(hview, hrec);
6513     ok(r == ERROR_SUCCESS, "Failed to execute hview: %d\n", r);
6514
6515     MsiCloseHandle(hrec);
6516     MsiViewClose(hview);
6517     MsiCloseHandle(hview);
6518
6519     query = "SELECT `Name`, `Data` FROM `_Storages`";
6520     r = MsiDatabaseOpenView(hdb, query, &hview);
6521     ok(r == ERROR_SUCCESS, "Failed to open database hview: %d\n", r);
6522
6523     r = MsiViewExecute(hview, 0);
6524     ok(r == ERROR_SUCCESS, "Failed to execute hview: %d\n", r);
6525
6526     r = MsiViewFetch(hview, &hrec);
6527     ok(r == ERROR_SUCCESS, "Failed to fetch hrecord: %d\n", r);
6528
6529     size = MAX_PATH;
6530     r = MsiRecordGetString(hrec, 1, file, &size);
6531     ok(r == ERROR_SUCCESS, "Failed to get string: %d\n", r);
6532     ok(!lstrcmp(file, "stgname"), "Expected \"stgname\", got \"%s\"\n", file);
6533
6534     size = MAX_PATH;
6535     lstrcpyA(buf, "apple");
6536     r = MsiRecordReadStream(hrec, 2, buf, &size);
6537     ok(r == ERROR_INVALID_DATA, "Expected ERROR_INVALID_DATA, got %d\n", r);
6538     ok(!lstrcmp(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf);
6539     ok(size == 0, "Expected 0, got %d\n", size);
6540
6541     MsiCloseHandle(hrec);
6542
6543     r = MsiViewFetch(hview, &hrec);
6544     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6545
6546     MsiViewClose(hview);
6547     MsiCloseHandle(hview);
6548
6549     MsiDatabaseCommit(hdb);
6550     MsiCloseHandle(hdb);
6551
6552     MultiByteToWideChar(CP_ACP, 0, msifile, -1, name, MAX_PATH);
6553     hr = StgOpenStorage(name, NULL, STGM_DIRECT | STGM_READ |
6554                         STGM_SHARE_DENY_WRITE, NULL, 0, &stg);
6555     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
6556     ok(stg != NULL, "Expected non-NULL storage\n");
6557
6558     MultiByteToWideChar(CP_ACP, 0, "stgname", -1, name, MAX_PATH);
6559     hr = IStorage_OpenStorage(stg, name, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE,
6560                               NULL, 0, &inner);
6561     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
6562     ok(inner != NULL, "Expected non-NULL storage\n");
6563
6564     MultiByteToWideChar(CP_ACP, 0, "storage.bin", -1, name, MAX_PATH);
6565     hr = IStorage_OpenStream(inner, name, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm);
6566     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
6567     ok(stm != NULL, "Expected non-NULL stream\n");
6568
6569     hr = IStream_Read(stm, buf, MAX_PATH, &size);
6570     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
6571     ok(size == 8, "Expected 8, got %d\n", size);
6572     ok(!lstrcmpA(buf, "stgdata"), "Expected \"stgdata\", got \"%s\"\n", buf);
6573
6574     IStream_Release(stm);
6575     IStorage_Release(inner);
6576
6577     IStorage_Release(stg);
6578     DeleteFileA(msifile);
6579 }
6580
6581 static void test_dbtopackage(void)
6582 {
6583     MSIHANDLE hdb, hpkg;
6584     CHAR package[10];
6585     CHAR buf[MAX_PATH];
6586     DWORD size;
6587     UINT r;
6588
6589     /* create an empty database, transact mode */
6590     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
6591     ok(r == ERROR_SUCCESS, "Failed to create database\n");
6592
6593     set_summary_info(hdb);
6594
6595     r = create_directory_table(hdb);
6596     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6597
6598     r = create_custom_action_table(hdb);
6599     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6600
6601     r = add_custom_action_entry(hdb, "'SetProp', 51, 'MYPROP', 'grape'");
6602     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6603
6604     sprintf(package, "#%i", hdb);
6605     r = MsiOpenPackage(package, &hpkg);
6606     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6607
6608     /* property is not set yet */
6609     size = MAX_PATH;
6610     lstrcpyA(buf, "kiwi");
6611     r = MsiGetProperty(hpkg, "MYPROP", buf, &size);
6612     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6613     ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf);
6614     ok(size == 0, "Expected 0, got %d\n", size);
6615
6616     /* run the custom action to set the property */
6617     r = MsiDoAction(hpkg, "SetProp");
6618     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6619
6620     /* property is now set */
6621     size = MAX_PATH;
6622     lstrcpyA(buf, "kiwi");
6623     r = MsiGetProperty(hpkg, "MYPROP", buf, &size);
6624     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6625     ok(!lstrcmpA(buf, "grape"), "Expected \"grape\", got \"%s\"\n", buf);
6626     ok(size == 5, "Expected 5, got %d\n", size);
6627
6628     MsiCloseHandle(hpkg);
6629
6630     /* reset the package */
6631     r = MsiOpenPackage(package, &hpkg);
6632     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6633
6634     /* property is not set anymore */
6635     size = MAX_PATH;
6636     lstrcpyA(buf, "kiwi");
6637     r = MsiGetProperty(hpkg, "MYPROP", buf, &size);
6638     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6639     todo_wine
6640     {
6641         ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf);
6642         ok(size == 0, "Expected 0, got %d\n", size);
6643     }
6644
6645     MsiCloseHandle(hdb);
6646     MsiCloseHandle(hpkg);
6647
6648     /* create an empty database, direct mode */
6649     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATEDIRECT, &hdb);
6650     ok(r == ERROR_SUCCESS, "Failed to create database\n");
6651
6652     set_summary_info(hdb);
6653
6654     r = create_directory_table(hdb);
6655     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6656
6657     r = create_custom_action_table(hdb);
6658     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6659
6660     r = add_custom_action_entry(hdb, "'SetProp', 51, 'MYPROP', 'grape'");
6661     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6662
6663     sprintf(package, "#%i", hdb);
6664     r = MsiOpenPackage(package, &hpkg);
6665     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6666
6667     /* property is not set yet */
6668     size = MAX_PATH;
6669     lstrcpyA(buf, "kiwi");
6670     r = MsiGetProperty(hpkg, "MYPROP", buf, &size);
6671     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6672     ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf);
6673     ok(size == 0, "Expected 0, got %d\n", size);
6674
6675     /* run the custom action to set the property */
6676     r = MsiDoAction(hpkg, "SetProp");
6677     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6678
6679     /* property is now set */
6680     size = MAX_PATH;
6681     lstrcpyA(buf, "kiwi");
6682     r = MsiGetProperty(hpkg, "MYPROP", buf, &size);
6683     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6684     ok(!lstrcmpA(buf, "grape"), "Expected \"grape\", got \"%s\"\n", buf);
6685     ok(size == 5, "Expected 5, got %d\n", size);
6686
6687     MsiCloseHandle(hpkg);
6688
6689     /* reset the package */
6690     r = MsiOpenPackage(package, &hpkg);
6691     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6692
6693     /* property is not set anymore */
6694     size = MAX_PATH;
6695     lstrcpyA(buf, "kiwi");
6696     r = MsiGetProperty(hpkg, "MYPROP", buf, &size);
6697     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6698     todo_wine
6699     {
6700         ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf);
6701         ok(size == 0, "Expected 0, got %d\n", size);
6702     }
6703
6704     MsiCloseHandle(hdb);
6705     MsiCloseHandle(hpkg);
6706     DeleteFileA(msifile);
6707 }
6708
6709 static void test_droptable(void)
6710 {
6711     MSIHANDLE hdb, hview, hrec;
6712     CHAR buf[MAX_PATH];
6713     LPCSTR query;
6714     DWORD size;
6715     UINT r;
6716
6717     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
6718     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6719
6720     query = "CREATE TABLE `One` ( `A` INT PRIMARY KEY `A` )";
6721     r = run_query(hdb, 0, query);
6722     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6723
6724     query = "SELECT * FROM `One`";
6725     r = do_query(hdb, query, &hrec);
6726     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6727
6728     query = "SELECT * FROM `_Tables` WHERE `Name` = 'One'";
6729     r = MsiDatabaseOpenViewA(hdb, query, &hview);
6730     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6731     r = MsiViewExecute(hview, 0);
6732     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6733
6734     r = MsiViewFetch(hview, &hrec);
6735     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6736
6737     size = MAX_PATH;
6738     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6739     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6740     ok(!lstrcmpA(buf, "One"), "Expected \"One\", got \"%s\"\n", buf);
6741
6742     MsiCloseHandle(hrec);
6743     MsiViewClose(hview);
6744     MsiCloseHandle(hview);
6745
6746     query = "SELECT * FROM `_Columns` WHERE `Table` = 'One'";
6747     r = MsiDatabaseOpenViewA(hdb, query, &hview);
6748     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6749     r = MsiViewExecute(hview, 0);
6750     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6751
6752     r = MsiViewFetch(hview, &hrec);
6753     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6754
6755     size = MAX_PATH;
6756     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6757     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6758     ok(!lstrcmpA(buf, "One"), "Expected \"One\", got \"%s\"\n", buf);
6759
6760     r = MsiRecordGetInteger(hrec, 2);
6761     ok(r == 1, "Expected 1, got %d\n", r);
6762
6763     size = MAX_PATH;
6764     r = MsiRecordGetStringA(hrec, 3, buf, &size);
6765     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6766     ok(!lstrcmpA(buf, "A"), "Expected \"A\", got \"%s\"\n", buf);
6767
6768     MsiCloseHandle(hrec);
6769
6770     r = MsiViewFetch(hview, &hrec);
6771     ok(r == ERROR_NO_MORE_ITEMS,
6772        "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6773
6774     MsiViewClose(hview);
6775     MsiCloseHandle(hview);
6776
6777     query = "DROP `One`";
6778     r = run_query(hdb, 0, query);
6779     ok(r == ERROR_BAD_QUERY_SYNTAX,
6780        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6781
6782     query = "DROP TABLE";
6783     r = run_query(hdb, 0, query);
6784     ok(r == ERROR_BAD_QUERY_SYNTAX,
6785        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6786
6787     query = "DROP TABLE `One`";
6788     hview = 0;
6789     r = MsiDatabaseOpenViewA(hdb, query, &hview);
6790     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6791     r = MsiViewExecute(hview, 0);
6792     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6793
6794     r = MsiViewFetch(hview, &hrec);
6795     ok(r == ERROR_FUNCTION_FAILED,
6796        "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
6797
6798     MsiViewClose(hview);
6799     MsiCloseHandle(hview);
6800
6801     query = "SELECT * FROM `IDontExist`";
6802     r = do_query(hdb, query, &hrec);
6803     ok(r == ERROR_BAD_QUERY_SYNTAX,
6804        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6805
6806     query = "SELECT * FROM `One`";
6807     r = do_query(hdb, query, &hrec);
6808     ok(r == ERROR_BAD_QUERY_SYNTAX,
6809        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6810
6811     query = "CREATE TABLE `One` ( `A` INT PRIMARY KEY `A` )";
6812     r = run_query(hdb, 0, query);
6813     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6814
6815     query = "DROP TABLE One";
6816     r = run_query(hdb, 0, query);
6817     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6818
6819     query = "SELECT * FROM `One`";
6820     r = do_query(hdb, query, &hrec);
6821     ok(r == ERROR_BAD_QUERY_SYNTAX,
6822        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6823
6824     query = "SELECT * FROM `_Tables` WHERE `Name` = 'One'";
6825     r = do_query(hdb, query, &hrec);
6826     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6827
6828     query = "SELECT * FROM `_Columns` WHERE `Table` = 'One'";
6829     r = do_query(hdb, query, &hrec);
6830     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6831
6832     query = "CREATE TABLE `One` ( `B` INT, `C` INT PRIMARY KEY `B` )";
6833     r = run_query(hdb, 0, query);
6834     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6835
6836     query = "SELECT * FROM `One`";
6837     r = do_query(hdb, query, &hrec);
6838     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6839
6840     query = "SELECT * FROM `_Tables` WHERE `Name` = 'One'";
6841     r = MsiDatabaseOpenViewA(hdb, query, &hview);
6842     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6843     r = MsiViewExecute(hview, 0);
6844     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6845
6846     r = MsiViewFetch(hview, &hrec);
6847     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6848
6849     size = MAX_PATH;
6850     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6851     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6852     ok(!lstrcmpA(buf, "One"), "Expected \"One\", got \"%s\"\n", buf);
6853
6854     MsiCloseHandle(hrec);
6855     MsiViewClose(hview);
6856     MsiCloseHandle(hview);
6857
6858     query = "SELECT * FROM `_Columns` WHERE `Table` = 'One'";
6859     r = MsiDatabaseOpenViewA(hdb, query, &hview);
6860     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6861     r = MsiViewExecute(hview, 0);
6862     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6863
6864     r = MsiViewFetch(hview, &hrec);
6865     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6866
6867     size = MAX_PATH;
6868     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6869     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6870     ok(!lstrcmpA(buf, "One"), "Expected \"One\", got \"%s\"\n", buf);
6871
6872     r = MsiRecordGetInteger(hrec, 2);
6873     ok(r == 1, "Expected 1, got %d\n", r);
6874
6875     size = MAX_PATH;
6876     r = MsiRecordGetStringA(hrec, 3, buf, &size);
6877     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6878     ok(!lstrcmpA(buf, "B"), "Expected \"B\", got \"%s\"\n", buf);
6879
6880     MsiCloseHandle(hrec);
6881
6882     r = MsiViewFetch(hview, &hrec);
6883     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6884
6885     size = MAX_PATH;
6886     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6887     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6888     ok(!lstrcmpA(buf, "One"), "Expected \"One\", got \"%s\"\n", buf);
6889
6890     r = MsiRecordGetInteger(hrec, 2);
6891     ok(r == 2, "Expected 2, got %d\n", r);
6892
6893     size = MAX_PATH;
6894     r = MsiRecordGetStringA(hrec, 3, buf, &size);
6895     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6896     ok(!lstrcmpA(buf, "C"), "Expected \"C\", got \"%s\"\n", buf);
6897
6898     MsiCloseHandle(hrec);
6899
6900     r = MsiViewFetch(hview, &hrec);
6901     ok(r == ERROR_NO_MORE_ITEMS,
6902        "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6903
6904     MsiViewClose(hview);
6905     MsiCloseHandle(hview);
6906
6907     query = "DROP TABLE One";
6908     r = run_query(hdb, 0, query);
6909     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6910
6911     query = "SELECT * FROM `One`";
6912     r = do_query(hdb, query, &hrec);
6913     ok(r == ERROR_BAD_QUERY_SYNTAX,
6914        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6915
6916     query = "SELECT * FROM `_Tables` WHERE `Name` = 'One'";
6917     r = do_query(hdb, query, &hrec);
6918     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6919
6920     query = "SELECT * FROM `_Columns` WHERE `Table` = 'One'";
6921     r = do_query(hdb, query, &hrec);
6922     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6923
6924     MsiCloseHandle(hdb);
6925     DeleteFileA(msifile);
6926 }
6927
6928 static void test_dbmerge(void)
6929 {
6930     MSIHANDLE hdb, href, hview, hrec;
6931     CHAR buf[MAX_PATH];
6932     LPCSTR query;
6933     DWORD size;
6934     UINT r;
6935
6936     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
6937     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6938
6939     r = MsiOpenDatabase("refdb.msi", MSIDBOPEN_CREATE, &href);
6940     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6941
6942     /* hDatabase is invalid */
6943     r = MsiDatabaseMergeA(0, href, "MergeErrors");
6944     ok(r == ERROR_INVALID_HANDLE,
6945        "Expected ERROR_INVALID_HANDLE, got %d\n", r);
6946
6947     /* hDatabaseMerge is invalid */
6948     r = MsiDatabaseMergeA(hdb, 0, "MergeErrors");
6949     ok(r == ERROR_INVALID_HANDLE,
6950        "Expected ERROR_INVALID_HANDLE, got %d\n", r);
6951
6952     /* szTableName is NULL */
6953     r = MsiDatabaseMergeA(hdb, href, NULL);
6954     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6955
6956     /* szTableName is empty */
6957     r = MsiDatabaseMergeA(hdb, href, "");
6958     ok(r == ERROR_INVALID_TABLE, "Expected ERROR_INVALID_TABLE, got %d\n", r);
6959
6960     /* both DBs empty, szTableName is valid */
6961     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
6962     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6963
6964     query = "CREATE TABLE `One` ( `A` INT PRIMARY KEY `A` )";
6965     r = run_query(hdb, 0, query);
6966     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6967
6968     query = "CREATE TABLE `One` ( `A` CHAR(72) PRIMARY KEY `A` )";
6969     r = run_query(href, 0, query);
6970     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6971
6972     /* column types don't match */
6973     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
6974     ok(r == ERROR_DATATYPE_MISMATCH,
6975        "Expected ERROR_DATATYPE_MISMATCH, got %d\n", r);
6976
6977     /* nothing in MergeErrors */
6978     query = "SELECT * FROM `MergeErrors`";
6979     r = do_query(hdb, query, &hrec);
6980     ok(r == ERROR_BAD_QUERY_SYNTAX,
6981        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6982
6983     query = "DROP TABLE `One`";
6984     r = run_query(hdb, 0, query);
6985     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6986
6987     query = "DROP TABLE `One`";
6988     r = run_query(href, 0, query);
6989     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6990
6991     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A` )";
6992     r = run_query(hdb, 0, query);
6993     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6994
6995     query = "CREATE TABLE `One` ( `A` INT, `C` INT PRIMARY KEY `A` )";
6996     r = run_query(href, 0, query);
6997     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6998
6999     /* column names don't match */
7000     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7001     ok(r == ERROR_DATATYPE_MISMATCH,
7002        "Expected ERROR_DATATYPE_MISMATCH, got %d\n", r);
7003
7004     /* nothing in MergeErrors */
7005     query = "SELECT * FROM `MergeErrors`";
7006     r = do_query(hdb, query, &hrec);
7007     ok(r == ERROR_BAD_QUERY_SYNTAX,
7008        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7009
7010     query = "DROP TABLE `One`";
7011     r = run_query(hdb, 0, query);
7012     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7013
7014     query = "DROP TABLE `One`";
7015     r = run_query(href, 0, query);
7016     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7017
7018     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A` )";
7019     r = run_query(hdb, 0, query);
7020     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7021
7022     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `B` )";
7023     r = run_query(href, 0, query);
7024     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7025
7026     /* primary keys don't match */
7027     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7028     ok(r == ERROR_DATATYPE_MISMATCH,
7029        "Expected ERROR_DATATYPE_MISMATCH, got %d\n", r);
7030
7031     /* nothing in MergeErrors */
7032     query = "SELECT * FROM `MergeErrors`";
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 = "DROP TABLE `One`";
7038     r = run_query(hdb, 0, query);
7039     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7040
7041     query = "DROP TABLE `One`";
7042     r = run_query(href, 0, query);
7043     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7044
7045     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A` )";
7046     r = run_query(hdb, 0, query);
7047     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7048
7049     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A`, `B` )";
7050     r = run_query(href, 0, query);
7051     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7052
7053     /* number of primary keys doesn't match */
7054     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7055     ok(r == ERROR_DATATYPE_MISMATCH,
7056        "Expected ERROR_DATATYPE_MISMATCH, got %d\n", r);
7057
7058     /* nothing in MergeErrors */
7059     query = "SELECT * FROM `MergeErrors`";
7060     r = do_query(hdb, query, &hrec);
7061     ok(r == ERROR_BAD_QUERY_SYNTAX,
7062        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7063
7064     query = "DROP TABLE `One`";
7065     r = run_query(hdb, 0, query);
7066     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7067
7068     query = "DROP TABLE `One`";
7069     r = run_query(href, 0, query);
7070     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7071
7072     query = "CREATE TABLE `One` ( `A` INT, `B` INT, `C` INT PRIMARY KEY `A` )";
7073     r = run_query(hdb, 0, query);
7074     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7075
7076     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A` )";
7077     r = run_query(href, 0, query);
7078     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7079
7080     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 1, 2 )";
7081     r = run_query(href, 0, query);
7082     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7083
7084     /* number of columns doesn't match */
7085     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7086     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7087
7088     query = "SELECT * FROM `One`";
7089     r = do_query(hdb, query, &hrec);
7090     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7091
7092     r = MsiRecordGetInteger(hrec, 1);
7093     ok(r == 1, "Expected 1, got %d\n", r);
7094
7095     r = MsiRecordGetInteger(hrec, 2);
7096     ok(r == 2, "Expected 2, got %d\n", r);
7097
7098     r = MsiRecordGetInteger(hrec, 3);
7099     ok(r == MSI_NULL_INTEGER, "Expected MSI_NULL_INTEGER, got %d\n", r);
7100
7101     MsiCloseHandle(hrec);
7102
7103     /* nothing in MergeErrors */
7104     query = "SELECT * FROM `MergeErrors`";
7105     r = do_query(hdb, query, &hrec);
7106     ok(r == ERROR_BAD_QUERY_SYNTAX,
7107        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7108
7109     query = "DROP TABLE `One`";
7110     r = run_query(hdb, 0, query);
7111     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7112
7113     query = "DROP TABLE `One`";
7114     r = run_query(href, 0, query);
7115     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7116
7117     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A` )";
7118     r = run_query(hdb, 0, query);
7119     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7120
7121     query = "CREATE TABLE `One` ( `A` INT, `B` INT, `C` INT PRIMARY KEY `A` )";
7122     r = run_query(href, 0, query);
7123     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7124
7125     query = "INSERT INTO `One` ( `A`, `B`, `C` ) VALUES ( 1, 2, 3 )";
7126     r = run_query(href, 0, query);
7127     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7128
7129     /* number of columns doesn't match */
7130     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7131     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7132
7133     query = "SELECT * FROM `One`";
7134     r = do_query(hdb, query, &hrec);
7135     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7136
7137     r = MsiRecordGetInteger(hrec, 1);
7138     ok(r == 1, "Expected 1, got %d\n", r);
7139
7140     r = MsiRecordGetInteger(hrec, 2);
7141     ok(r == 2, "Expected 2, got %d\n", r);
7142
7143     r = MsiRecordGetInteger(hrec, 3);
7144     ok(r == MSI_NULL_INTEGER, "Expected MSI_NULL_INTEGER, got %d\n", r);
7145
7146     MsiCloseHandle(hrec);
7147
7148     /* nothing in MergeErrors */
7149     query = "SELECT * FROM `MergeErrors`";
7150     r = do_query(hdb, query, &hrec);
7151     ok(r == ERROR_BAD_QUERY_SYNTAX,
7152        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7153
7154     query = "DROP TABLE `One`";
7155     r = run_query(hdb, 0, query);
7156     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7157
7158     query = "DROP TABLE `One`";
7159     r = run_query(href, 0, query);
7160     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7161
7162     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A` )";
7163     r = run_query(hdb, 0, query);
7164     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7165
7166     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 1, 1 )";
7167     r = run_query(hdb, 0, query);
7168     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7169
7170     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 2, 2 )";
7171     r = run_query(hdb, 0, query);
7172     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7173
7174     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A` )";
7175     r = run_query(href, 0, query);
7176     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7177
7178     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 1, 2 )";
7179     r = run_query(href, 0, query);
7180     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7181
7182     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 2, 3 )";
7183     r = run_query(href, 0, query);
7184     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7185
7186     /* primary keys match, rows do not */
7187     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7188     ok(r == ERROR_FUNCTION_FAILED,
7189        "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
7190
7191     /* nothing in MergeErrors */
7192     query = "SELECT * FROM `MergeErrors`";
7193     r = do_query(hdb, query, &hrec);
7194     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7195
7196     size = MAX_PATH;
7197     r = MsiRecordGetStringA(hrec, 1, buf, &size);
7198     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7199     ok(!lstrcmpA(buf, "One"), "Expected \"One\", got \"%s\"\n", buf);
7200
7201     r = MsiRecordGetInteger(hrec, 2);
7202     ok(r == 2, "Expected 2, got %d\n", r);
7203
7204     MsiCloseHandle(hrec);
7205
7206     r = MsiDatabaseOpenViewA(hdb, "SELECT * FROM `MergeErrors`", &hview);
7207     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7208
7209     r = MsiViewGetColumnInfo(hview, MSICOLINFO_NAMES, &hrec);
7210     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7211
7212     size = MAX_PATH;
7213     r = MsiRecordGetString(hrec, 1, buf, &size);
7214     ok(!lstrcmpA(buf, "Table"), "Expected \"Table\", got \"%s\"\n", buf);
7215
7216     size = MAX_PATH;
7217     r = MsiRecordGetString(hrec, 2, buf, &size);
7218     ok(!lstrcmpA(buf, "NumRowMergeConflicts"),
7219        "Expected \"NumRowMergeConflicts\", got \"%s\"\n", buf);
7220
7221     MsiCloseHandle(hrec);
7222
7223     r = MsiViewGetColumnInfo(hview, MSICOLINFO_TYPES, &hrec);
7224     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7225
7226     size = MAX_PATH;
7227     r = MsiRecordGetString(hrec, 1, buf, &size);
7228     ok(!lstrcmpA(buf, "s255"), "Expected \"s255\", got \"%s\"\n", buf);
7229
7230     size = MAX_PATH;
7231     r = MsiRecordGetString(hrec, 2, buf, &size);
7232     ok(!lstrcmpA(buf, "i2"), "Expected \"i2\", got \"%s\"\n", buf);
7233
7234     MsiCloseHandle(hrec);
7235     MsiViewClose(hview);
7236     MsiCloseHandle(hview);
7237
7238     query = "DROP TABLE `MergeErrors`";
7239     r = run_query(hdb, 0, query);
7240     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7241
7242     query = "DROP TABLE `One`";
7243     r = run_query(hdb, 0, query);
7244     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7245
7246     query = "DROP TABLE `One`";
7247     r = run_query(href, 0, query);
7248     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7249
7250     query = "CREATE TABLE `One` ( `A` INT, `B` CHAR(72) PRIMARY KEY `A` )";
7251     r = run_query(href, 0, query);
7252     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7253
7254     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 1, 'hi' )";
7255     r = run_query(href, 0, query);
7256     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7257
7258     /* table from merged database is not in target database */
7259     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7260     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7261
7262     query = "SELECT * FROM `One`";
7263     r = do_query(hdb, query, &hrec);
7264     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7265
7266     r = MsiRecordGetInteger(hrec, 1);
7267     ok(r == 1, "Expected 1, got %d\n", r);
7268
7269     size = MAX_PATH;
7270     r = MsiRecordGetStringA(hrec, 2, buf, &size);
7271     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7272     ok(!lstrcmpA(buf, "hi"), "Expected \"hi\", got \"%s\"\n", buf);
7273
7274     MsiCloseHandle(hrec);
7275
7276     /* nothing in MergeErrors */
7277     query = "SELECT * FROM `MergeErrors`";
7278     r = do_query(hdb, query, &hrec);
7279     ok(r == ERROR_BAD_QUERY_SYNTAX,
7280        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7281
7282     query = "DROP TABLE `One`";
7283     r = run_query(hdb, 0, query);
7284     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7285
7286     query = "DROP TABLE `One`";
7287     r = run_query(href, 0, query);
7288     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7289
7290     query = "CREATE TABLE `One` ( "
7291             "`A` CHAR(72), `B` INT PRIMARY KEY `A` )";
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` ( "
7296             "`A` CHAR(72), `B` INT PRIMARY KEY `A` )";
7297     r = run_query(href, 0, query);
7298     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7299
7300     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 'hi', 1 )";
7301     r = run_query(href, 0, query);
7302     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7303
7304     /* primary key is string */
7305     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7306     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7307
7308     query = "SELECT * FROM `One`";
7309     r = do_query(hdb, query, &hrec);
7310     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7311
7312     size = MAX_PATH;
7313     r = MsiRecordGetStringA(hrec, 1, buf, &size);
7314     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7315     ok(!lstrcmpA(buf, "hi"), "Expected \"hi\", got \"%s\"\n", buf);
7316
7317     r = MsiRecordGetInteger(hrec, 2);
7318     ok(r == 1, "Expected 1, got %d\n", r);
7319
7320     MsiCloseHandle(hrec);
7321
7322     /* nothing in MergeErrors */
7323     query = "SELECT * FROM `MergeErrors`";
7324     r = do_query(hdb, query, &hrec);
7325     ok(r == ERROR_BAD_QUERY_SYNTAX,
7326        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7327
7328     create_file_data("codepage.idt", "\r\n\r\n850\t_ForceCodepage\r\n", 0);
7329
7330     GetCurrentDirectoryA(MAX_PATH, buf);
7331     r = MsiDatabaseImportA(hdb, buf, "codepage.idt");
7332     todo_wine
7333     {
7334         ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7335     }
7336
7337     query = "DROP TABLE `One`";
7338     r = run_query(hdb, 0, query);
7339     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7340
7341     query = "DROP TABLE `One`";
7342     r = run_query(href, 0, query);
7343     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7344
7345     query = "CREATE TABLE `One` ( "
7346             "`A` INT, `B` CHAR(72) LOCALIZABLE PRIMARY KEY `A` )";
7347     r = run_query(hdb, 0, query);
7348     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7349
7350     query = "CREATE TABLE `One` ( "
7351             "`A` INT, `B` CHAR(72) LOCALIZABLE PRIMARY KEY `A` )";
7352     r = run_query(href, 0, query);
7353     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7354
7355     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 1, 'hi' )";
7356     r = run_query(href, 0, query);
7357     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7358
7359     /* code page does not match */
7360     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7361     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7362
7363     query = "SELECT * FROM `One`";
7364     r = do_query(hdb, query, &hrec);
7365     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7366
7367     r = MsiRecordGetInteger(hrec, 1);
7368     ok(r == 1, "Expected 1, got %d\n", r);
7369
7370     size = MAX_PATH;
7371     r = MsiRecordGetStringA(hrec, 2, buf, &size);
7372     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7373     ok(!lstrcmpA(buf, "hi"), "Expected \"hi\", got \"%s\"\n", buf);
7374
7375     MsiCloseHandle(hrec);
7376
7377     /* nothing in MergeErrors */
7378     query = "SELECT * FROM `MergeErrors`";
7379     r = do_query(hdb, query, &hrec);
7380     ok(r == ERROR_BAD_QUERY_SYNTAX,
7381        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7382
7383     query = "DROP TABLE `One`";
7384     r = run_query(hdb, 0, query);
7385     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7386
7387     query = "DROP TABLE `One`";
7388     r = run_query(href, 0, query);
7389     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7390
7391     query = "CREATE TABLE `One` ( `A` INT, `B` OBJECT PRIMARY KEY `A` )";
7392     r = run_query(hdb, 0, query);
7393     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7394
7395     query = "CREATE TABLE `One` ( `A` INT, `B` OBJECT PRIMARY KEY `A` )";
7396     r = run_query(href, 0, query);
7397     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7398
7399     create_file("binary.dat");
7400     hrec = MsiCreateRecord(1);
7401     MsiRecordSetStreamA(hrec, 1, "binary.dat");
7402
7403     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 1, ? )";
7404     r = run_query(href, hrec, query);
7405     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7406
7407     MsiCloseHandle(hrec);
7408
7409     /* binary data to merge */
7410     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7411     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7412
7413     query = "SELECT * FROM `One`";
7414     r = do_query(hdb, query, &hrec);
7415     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7416
7417     r = MsiRecordGetInteger(hrec, 1);
7418     ok(r == 1, "Expected 1, got %d\n", r);
7419
7420     size = MAX_PATH;
7421     ZeroMemory(buf, MAX_PATH);
7422     r = MsiRecordReadStream(hrec, 2, buf, &size);
7423     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7424     ok(!lstrcmpA(buf, "binary.dat\n"),
7425        "Expected \"binary.dat\\n\", got \"%s\"\n", buf);
7426
7427     MsiCloseHandle(hrec);
7428
7429     /* nothing in MergeErrors */
7430     query = "SELECT * FROM `MergeErrors`";
7431     r = do_query(hdb, query, &hrec);
7432     ok(r == ERROR_BAD_QUERY_SYNTAX,
7433        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7434
7435     MsiCloseHandle(hdb);
7436     MsiCloseHandle(href);
7437     DeleteFileA(msifile);
7438     DeleteFileA("refdb.msi");
7439     DeleteFileA("codepage.idt");
7440     DeleteFileA("binary.dat");
7441 }
7442
7443 UINT ordervals[6][3] =
7444 {
7445     { MSI_NULL_INTEGER, 12, 13 },
7446     { 1, 2, 3 },
7447     { 6, 4, 5 },
7448     { 8, 9, 7 },
7449     { 10, 11, MSI_NULL_INTEGER },
7450     { 14, MSI_NULL_INTEGER, 15 }
7451 };
7452
7453 static void test_insertorder(void)
7454 {
7455     MSIHANDLE hdb, view, rec;
7456     LPCSTR query;
7457     UINT r;
7458     int i;
7459
7460     hdb = create_db();
7461     ok(hdb, "failed to create db\n");
7462
7463     query = "CREATE TABLE `T` ( `A` SHORT, `B` SHORT, `C` SHORT PRIMARY KEY `A`)";
7464     r = run_query(hdb, 0, query);
7465     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7466
7467     query = "INSERT INTO `T` ( `A`, `B`, `C` ) VALUES ( 1, 2, 3 )";
7468     r = run_query(hdb, 0, query);
7469     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7470
7471     query = "INSERT INTO `T` ( `B`, `C`, `A` ) VALUES ( 4, 5, 6 )";
7472     r = run_query(hdb, 0, query);
7473     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7474
7475     query = "INSERT INTO `T` ( `C`, `A`, `B` ) VALUES ( 7, 8, 9 )";
7476     r = run_query(hdb, 0, query);
7477     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7478
7479     query = "INSERT INTO `T` ( `A`, `B` ) VALUES ( 10, 11 )";
7480     r = run_query(hdb, 0, query);
7481     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7482
7483     query = "INSERT INTO `T` ( `B`, `C` ) VALUES ( 12, 13 )";
7484     r = run_query(hdb, 0, query);
7485     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7486
7487     /* fails because the primary key already
7488      * has an MSI_NULL_INTEGER value set above
7489      */
7490     query = "INSERT INTO `T` ( `C` ) VALUES ( 14 )";
7491     r = run_query(hdb, 0, query);
7492     ok(r == ERROR_FUNCTION_FAILED,
7493        "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
7494
7495     /* replicate the error where primary key is set twice */
7496     query = "INSERT INTO `T` ( `A`, `C` ) VALUES ( 1, 14 )";
7497     r = run_query(hdb, 0, query);
7498     ok(r == ERROR_FUNCTION_FAILED,
7499        "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
7500
7501     query = "INSERT INTO `T` ( `A`, `C` ) VALUES ( 14, 15 )";
7502     r = run_query(hdb, 0, query);
7503     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7504
7505     query = "INSERT INTO `T` VALUES ( 16 )";
7506     r = run_query(hdb, 0, query);
7507     ok(r == ERROR_BAD_QUERY_SYNTAX,
7508        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7509
7510     query = "INSERT INTO `T` VALUES ( 17, 18 )";
7511     r = run_query(hdb, 0, query);
7512     ok(r == ERROR_BAD_QUERY_SYNTAX,
7513        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7514
7515     query = "INSERT INTO `T` VALUES ( 19, 20, 21 )";
7516     r = run_query(hdb, 0, query);
7517     ok(r == ERROR_BAD_QUERY_SYNTAX,
7518        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7519
7520     query = "SELECT * FROM `T`";
7521     r = MsiDatabaseOpenView(hdb, query, &view);
7522     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7523     r = MsiViewExecute(view, 0);
7524     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7525
7526     for (i = 0; i < 6; i++)
7527     {
7528         r = MsiViewFetch(view, &rec);
7529         ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7530
7531         r = MsiRecordGetInteger(rec, 1);
7532         ok(r == ordervals[i][0], "Expected %d, got %d\n", ordervals[i][0], r);
7533
7534         r = MsiRecordGetInteger(rec, 2);
7535         ok(r == ordervals[i][1], "Expected %d, got %d\n", ordervals[i][1], r);
7536
7537         r = MsiRecordGetInteger(rec, 3);
7538         ok(r == ordervals[i][2], "Expected %d, got %d\n", ordervals[i][2], r);
7539
7540         MsiCloseHandle(rec);
7541     }
7542
7543     r = MsiViewFetch(view, &rec);
7544     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7545
7546     MsiViewClose(view);
7547     MsiCloseHandle(view);
7548
7549     query = "DELETE FROM `T` WHERE `A` IS NULL";
7550     r = run_query(hdb, 0, query);
7551     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7552
7553     query = "INSERT INTO `T` ( `B`, `C` ) VALUES ( 12, 13 ) TEMPORARY";
7554     r = run_query(hdb, 0, query);
7555     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7556
7557     query = "SELECT * FROM `T`";
7558     r = MsiDatabaseOpenView(hdb, query, &view);
7559     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7560     r = MsiViewExecute(view, 0);
7561     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7562
7563     for (i = 0; i < 6; i++)
7564     {
7565         r = MsiViewFetch(view, &rec);
7566         ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7567
7568         r = MsiRecordGetInteger(rec, 1);
7569         ok(r == ordervals[i][0], "Expected %d, got %d\n", ordervals[i][0], r);
7570
7571         r = MsiRecordGetInteger(rec, 2);
7572         ok(r == ordervals[i][1], "Expected %d, got %d\n", ordervals[i][1], r);
7573
7574         r = MsiRecordGetInteger(rec, 3);
7575         ok(r == ordervals[i][2], "Expected %d, got %d\n", ordervals[i][2], r);
7576
7577         MsiCloseHandle(rec);
7578     }
7579
7580     r = MsiViewFetch(view, &rec);
7581     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7582
7583     MsiViewClose(view);
7584     MsiCloseHandle(view);
7585     MsiCloseHandle(hdb);
7586     DeleteFileA(msifile);
7587 }
7588
7589 static void test_columnorder(void)
7590 {
7591     MSIHANDLE hdb, view, rec;
7592     char buf[MAX_PATH];
7593     LPCSTR query;
7594     DWORD sz;
7595     UINT r;
7596
7597     hdb = create_db();
7598     ok(hdb, "failed to create db\n");
7599
7600     /* Each column is a slot:
7601      * ---------------------
7602      * | B | C | A | E | D |
7603      * ---------------------
7604      *
7605      * When a column is selected as a primary key,
7606      * the column occupying the nth primary key slot is swapped
7607      * with the current position of the primary key in question:
7608      *
7609      * set primary key `D`
7610      * ---------------------    ---------------------
7611      * | B | C | A | E | D | -> | D | C | A | E | B |
7612      * ---------------------    ---------------------
7613      *
7614      * set primary key `E`
7615      * ---------------------    ---------------------
7616      * | D | C | A | E | B | -> | D | E | A | C | B |
7617      * ---------------------    ---------------------
7618      */
7619
7620     query = "CREATE TABLE `T` ( `B` SHORT NOT NULL, `C` SHORT NOT NULL, "
7621             "`A` CHAR(255), `E` INT, `D` CHAR(255) NOT NULL "
7622             "PRIMARY KEY `D`, `E`)";
7623     r = run_query(hdb, 0, query);
7624     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7625
7626     query = "SELECT * FROM `T`";
7627     r = MsiDatabaseOpenView(hdb, query, &view);
7628     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7629
7630     r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
7631     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7632
7633     sz = MAX_PATH;
7634     lstrcpyA(buf, "kiwi");
7635     r = MsiRecordGetString(rec, 1, buf, &sz);
7636     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7637     ok(!lstrcmpA("s255", buf), "Expected \"s255\", got \"%s\"\n", buf);
7638
7639     sz = MAX_PATH;
7640     lstrcpyA(buf, "kiwi");
7641     r = MsiRecordGetString(rec, 2, buf, &sz);
7642     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7643     ok(!lstrcmpA("I2", buf), "Expected \"I2\", got \"%s\"\n", buf);
7644
7645     sz = MAX_PATH;
7646     lstrcpyA(buf, "kiwi");
7647     r = MsiRecordGetString(rec, 3, buf, &sz);
7648     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7649     ok(!lstrcmpA("S255", buf), "Expected \"S255\", got \"%s\"\n", buf);
7650
7651     sz = MAX_PATH;
7652     lstrcpyA(buf, "kiwi");
7653     r = MsiRecordGetString(rec, 4, buf, &sz);
7654     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7655     ok(!lstrcmpA("i2", buf), "Expected \"i2\", got \"%s\"\n", buf);
7656
7657     sz = MAX_PATH;
7658     lstrcpyA(buf, "kiwi");
7659     r = MsiRecordGetString(rec, 5, buf, &sz);
7660     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7661     ok(!lstrcmpA("i2", buf), "Expected \"i2\", got \"%s\"\n", buf);
7662
7663     MsiCloseHandle(rec);
7664
7665     r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec);
7666     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7667
7668     sz = MAX_PATH;
7669     lstrcpyA(buf, "kiwi");
7670     r = MsiRecordGetString(rec, 1, buf, &sz);
7671     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7672     ok(!lstrcmpA("D", buf), "Expected \"D\", got \"%s\"\n", buf);
7673
7674     sz = MAX_PATH;
7675     lstrcpyA(buf, "kiwi");
7676     r = MsiRecordGetString(rec, 2, buf, &sz);
7677     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7678     ok(!lstrcmpA("E", buf), "Expected \"E\", got \"%s\"\n", buf);
7679
7680     sz = MAX_PATH;
7681     lstrcpyA(buf, "kiwi");
7682     r = MsiRecordGetString(rec, 3, buf, &sz);
7683     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7684     ok(!lstrcmpA("A", buf), "Expected \"A\", got \"%s\"\n", buf);
7685
7686     sz = MAX_PATH;
7687     lstrcpyA(buf, "kiwi");
7688     r = MsiRecordGetString(rec, 4, buf, &sz);
7689     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7690     ok(!lstrcmpA("C", buf), "Expected \"C\", got \"%s\"\n", buf);
7691
7692     sz = MAX_PATH;
7693     lstrcpyA(buf, "kiwi");
7694     r = MsiRecordGetString(rec, 5, buf, &sz);
7695     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7696     ok(!lstrcmpA("B", buf), "Expected \"B\", got \"%s\"\n", buf);
7697
7698     MsiCloseHandle(rec);
7699     MsiViewClose(view);
7700     MsiCloseHandle(view);
7701
7702     query = "INSERT INTO `T` ( `B`, `C`, `A`, `E`, `D` ) "
7703             "VALUES ( 1, 2, 'a', 3, 'bc' )";
7704     r = run_query(hdb, 0, query);
7705     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7706
7707     query = "SELECT * FROM `T`";
7708     r = do_query(hdb, query, &rec);
7709
7710     sz = MAX_PATH;
7711     lstrcpyA(buf, "kiwi");
7712     r = MsiRecordGetString(rec, 1, buf, &sz);
7713     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7714     ok(!lstrcmpA("bc", buf), "Expected \"bc\", got \"%s\"\n", buf);
7715
7716     r = MsiRecordGetInteger(rec, 2);
7717     ok(r == 3, "Expected 3, got %d\n", r);
7718
7719     sz = MAX_PATH;
7720     lstrcpyA(buf, "kiwi");
7721     r = MsiRecordGetString(rec, 3, buf, &sz);
7722     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7723     ok(!lstrcmpA("a", buf), "Expected \"a\", got \"%s\"\n", buf);
7724
7725     r = MsiRecordGetInteger(rec, 4);
7726     ok(r == 2, "Expected 2, got %d\n", r);
7727
7728     r = MsiRecordGetInteger(rec, 5);
7729     ok(r == 1, "Expected 1, got %d\n", r);
7730
7731     MsiCloseHandle(rec);
7732
7733     query = "SELECT * FROM `_Columns` WHERE `Table` = 'T'";
7734     r = MsiDatabaseOpenView(hdb, query, &view);
7735     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7736     r = MsiViewExecute(view, 0);
7737     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7738
7739     r = MsiViewFetch(view, &rec);
7740     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7741
7742     sz = MAX_PATH;
7743     lstrcpyA(buf, "kiwi");
7744     r = MsiRecordGetString(rec, 1, buf, &sz);
7745     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7746     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
7747
7748     r = MsiRecordGetInteger(rec, 2);
7749     ok(r == 1, "Expected 1, got %d\n", r);
7750
7751     sz = MAX_PATH;
7752     lstrcpyA(buf, "kiwi");
7753     r = MsiRecordGetString(rec, 3, buf, &sz);
7754     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7755     ok(!lstrcmpA("D", buf), "Expected \"D\", got \"%s\"\n", buf);
7756
7757     MsiCloseHandle(rec);
7758
7759     r = MsiViewFetch(view, &rec);
7760     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7761
7762     sz = MAX_PATH;
7763     lstrcpyA(buf, "kiwi");
7764     r = MsiRecordGetString(rec, 1, buf, &sz);
7765     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7766     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
7767
7768     r = MsiRecordGetInteger(rec, 2);
7769     ok(r == 2, "Expected 2, got %d\n", r);
7770
7771     sz = MAX_PATH;
7772     lstrcpyA(buf, "kiwi");
7773     r = MsiRecordGetString(rec, 3, buf, &sz);
7774     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7775     ok(!lstrcmpA("E", buf), "Expected \"E\", got \"%s\"\n", buf);
7776
7777     MsiCloseHandle(rec);
7778
7779     r = MsiViewFetch(view, &rec);
7780     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7781
7782     sz = MAX_PATH;
7783     lstrcpyA(buf, "kiwi");
7784     r = MsiRecordGetString(rec, 1, buf, &sz);
7785     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7786     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
7787
7788     r = MsiRecordGetInteger(rec, 2);
7789     ok(r == 3, "Expected 3, got %d\n", r);
7790
7791     sz = MAX_PATH;
7792     lstrcpyA(buf, "kiwi");
7793     r = MsiRecordGetString(rec, 3, buf, &sz);
7794     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7795     ok(!lstrcmpA("A", buf), "Expected \"A\", got \"%s\"\n", buf);
7796
7797     MsiCloseHandle(rec);
7798
7799     r = MsiViewFetch(view, &rec);
7800     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7801
7802     sz = MAX_PATH;
7803     lstrcpyA(buf, "kiwi");
7804     r = MsiRecordGetString(rec, 1, buf, &sz);
7805     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7806     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
7807
7808     r = MsiRecordGetInteger(rec, 2);
7809     ok(r == 4, "Expected 4, got %d\n", r);
7810
7811     sz = MAX_PATH;
7812     lstrcpyA(buf, "kiwi");
7813     r = MsiRecordGetString(rec, 3, buf, &sz);
7814     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7815     ok(!lstrcmpA("C", buf), "Expected \"C\", got \"%s\"\n", buf);
7816
7817     MsiCloseHandle(rec);
7818
7819     r = MsiViewFetch(view, &rec);
7820     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7821
7822     sz = MAX_PATH;
7823     lstrcpyA(buf, "kiwi");
7824     r = MsiRecordGetString(rec, 1, buf, &sz);
7825     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7826     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
7827
7828     r = MsiRecordGetInteger(rec, 2);
7829     ok(r == 5, "Expected 5, got %d\n", r);
7830
7831     sz = MAX_PATH;
7832     lstrcpyA(buf, "kiwi");
7833     r = MsiRecordGetString(rec, 3, buf, &sz);
7834     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7835     ok(!lstrcmpA("B", buf), "Expected \"B\", got \"%s\"\n", buf);
7836
7837     MsiCloseHandle(rec);
7838
7839     r = MsiViewFetch(view, &rec);
7840     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7841
7842     MsiViewClose(view);
7843     MsiCloseHandle(view);
7844
7845     query = "CREATE TABLE `Z` ( `B` SHORT NOT NULL, `C` SHORT NOT NULL, "
7846             "`A` CHAR(255), `E` INT, `D` CHAR(255) NOT NULL "
7847             "PRIMARY KEY `C`, `A`, `D`)";
7848     r = run_query(hdb, 0, query);
7849     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7850
7851     query = "SELECT * FROM `Z`";
7852     r = MsiDatabaseOpenView(hdb, query, &view);
7853     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7854
7855     r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
7856     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7857
7858     sz = MAX_PATH;
7859     lstrcpyA(buf, "kiwi");
7860     r = MsiRecordGetString(rec, 1, buf, &sz);
7861     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7862     ok(!lstrcmpA("i2", buf), "Expected \"i2\", got \"%s\"\n", buf);
7863
7864     sz = MAX_PATH;
7865     lstrcpyA(buf, "kiwi");
7866     r = MsiRecordGetString(rec, 2, buf, &sz);
7867     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7868     ok(!lstrcmpA("S255", buf), "Expected \"S255\", got \"%s\"\n", buf);
7869
7870     sz = MAX_PATH;
7871     lstrcpyA(buf, "kiwi");
7872     r = MsiRecordGetString(rec, 3, buf, &sz);
7873     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7874     ok(!lstrcmpA("s255", buf), "Expected \"s255\", got \"%s\"\n", buf);
7875
7876     sz = MAX_PATH;
7877     lstrcpyA(buf, "kiwi");
7878     r = MsiRecordGetString(rec, 4, buf, &sz);
7879     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7880     ok(!lstrcmpA("I2", buf), "Expected \"I2\", got \"%s\"\n", buf);
7881
7882     sz = MAX_PATH;
7883     lstrcpyA(buf, "kiwi");
7884     r = MsiRecordGetString(rec, 5, buf, &sz);
7885     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7886     ok(!lstrcmpA("i2", buf), "Expected \"i2\", got \"%s\"\n", buf);
7887
7888     MsiCloseHandle(rec);
7889
7890     r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec);
7891     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7892
7893     sz = MAX_PATH;
7894     lstrcpyA(buf, "kiwi");
7895     r = MsiRecordGetString(rec, 1, buf, &sz);
7896     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7897     ok(!lstrcmpA("C", buf), "Expected \"C\", got \"%s\"\n", buf);
7898
7899     sz = MAX_PATH;
7900     lstrcpyA(buf, "kiwi");
7901     r = MsiRecordGetString(rec, 2, buf, &sz);
7902     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7903     ok(!lstrcmpA("A", buf), "Expected \"A\", got \"%s\"\n", buf);
7904
7905     sz = MAX_PATH;
7906     lstrcpyA(buf, "kiwi");
7907     r = MsiRecordGetString(rec, 3, buf, &sz);
7908     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7909     ok(!lstrcmpA("D", buf), "Expected \"D\", got \"%s\"\n", buf);
7910
7911     sz = MAX_PATH;
7912     lstrcpyA(buf, "kiwi");
7913     r = MsiRecordGetString(rec, 4, buf, &sz);
7914     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7915     ok(!lstrcmpA("E", buf), "Expected \"E\", got \"%s\"\n", buf);
7916
7917     sz = MAX_PATH;
7918     lstrcpyA(buf, "kiwi");
7919     r = MsiRecordGetString(rec, 5, buf, &sz);
7920     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7921     ok(!lstrcmpA("B", buf), "Expected \"B\", got \"%s\"\n", buf);
7922
7923     MsiCloseHandle(rec);
7924     MsiViewClose(view);
7925     MsiCloseHandle(view);
7926
7927     query = "INSERT INTO `Z` ( `B`, `C`, `A`, `E`, `D` ) "
7928             "VALUES ( 1, 2, 'a', 3, 'bc' )";
7929     r = run_query(hdb, 0, query);
7930     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7931
7932     query = "SELECT * FROM `Z`";
7933     r = do_query(hdb, query, &rec);
7934
7935     r = MsiRecordGetInteger(rec, 1);
7936     ok(r == 2, "Expected 2, got %d\n", r);
7937
7938     sz = MAX_PATH;
7939     lstrcpyA(buf, "kiwi");
7940     r = MsiRecordGetString(rec, 2, buf, &sz);
7941     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7942     ok(!lstrcmpA("a", buf), "Expected \"a\", got \"%s\"\n", buf);
7943
7944     sz = MAX_PATH;
7945     lstrcpyA(buf, "kiwi");
7946     r = MsiRecordGetString(rec, 3, buf, &sz);
7947     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7948     ok(!lstrcmpA("bc", buf), "Expected \"bc\", got \"%s\"\n", buf);
7949
7950     r = MsiRecordGetInteger(rec, 4);
7951     ok(r == 3, "Expected 3, got %d\n", r);
7952
7953     r = MsiRecordGetInteger(rec, 5);
7954     ok(r == 1, "Expected 1, got %d\n", r);
7955
7956     MsiCloseHandle(rec);
7957
7958     query = "SELECT * FROM `_Columns` WHERE `Table` = 'T'";
7959     r = MsiDatabaseOpenView(hdb, query, &view);
7960     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7961     r = MsiViewExecute(view, 0);
7962     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7963
7964     r = MsiViewFetch(view, &rec);
7965     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7966
7967     sz = MAX_PATH;
7968     lstrcpyA(buf, "kiwi");
7969     r = MsiRecordGetString(rec, 1, buf, &sz);
7970     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7971     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
7972
7973     r = MsiRecordGetInteger(rec, 2);
7974     ok(r == 1, "Expected 1, got %d\n", r);
7975
7976     sz = MAX_PATH;
7977     lstrcpyA(buf, "kiwi");
7978     r = MsiRecordGetString(rec, 3, buf, &sz);
7979     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7980     ok(!lstrcmpA("D", buf), "Expected \"D\", got \"%s\"\n", buf);
7981
7982     MsiCloseHandle(rec);
7983
7984     r = MsiViewFetch(view, &rec);
7985     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7986
7987     sz = MAX_PATH;
7988     lstrcpyA(buf, "kiwi");
7989     r = MsiRecordGetString(rec, 1, buf, &sz);
7990     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7991     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
7992
7993     r = MsiRecordGetInteger(rec, 2);
7994     ok(r == 2, "Expected 2, got %d\n", r);
7995
7996     sz = MAX_PATH;
7997     lstrcpyA(buf, "kiwi");
7998     r = MsiRecordGetString(rec, 3, buf, &sz);
7999     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8000     ok(!lstrcmpA("E", buf), "Expected \"E\", got \"%s\"\n", buf);
8001
8002     MsiCloseHandle(rec);
8003
8004     r = MsiViewFetch(view, &rec);
8005     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8006
8007     sz = MAX_PATH;
8008     lstrcpyA(buf, "kiwi");
8009     r = MsiRecordGetString(rec, 1, buf, &sz);
8010     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8011     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
8012
8013     r = MsiRecordGetInteger(rec, 2);
8014     ok(r == 3, "Expected 3, got %d\n", r);
8015
8016     sz = MAX_PATH;
8017     lstrcpyA(buf, "kiwi");
8018     r = MsiRecordGetString(rec, 3, buf, &sz);
8019     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8020     ok(!lstrcmpA("A", buf), "Expected \"A\", got \"%s\"\n", buf);
8021
8022     MsiCloseHandle(rec);
8023
8024     r = MsiViewFetch(view, &rec);
8025     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8026
8027     sz = MAX_PATH;
8028     lstrcpyA(buf, "kiwi");
8029     r = MsiRecordGetString(rec, 1, buf, &sz);
8030     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8031     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
8032
8033     r = MsiRecordGetInteger(rec, 2);
8034     ok(r == 4, "Expected 4, got %d\n", r);
8035
8036     sz = MAX_PATH;
8037     lstrcpyA(buf, "kiwi");
8038     r = MsiRecordGetString(rec, 3, buf, &sz);
8039     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8040     ok(!lstrcmpA("C", buf), "Expected \"C\", got \"%s\"\n", buf);
8041
8042     MsiCloseHandle(rec);
8043
8044     r = MsiViewFetch(view, &rec);
8045     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8046
8047     sz = MAX_PATH;
8048     lstrcpyA(buf, "kiwi");
8049     r = MsiRecordGetString(rec, 1, buf, &sz);
8050     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8051     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
8052
8053     r = MsiRecordGetInteger(rec, 2);
8054     ok(r == 5, "Expected 5, got %d\n", r);
8055
8056     sz = MAX_PATH;
8057     lstrcpyA(buf, "kiwi");
8058     r = MsiRecordGetString(rec, 3, buf, &sz);
8059     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8060     ok(!lstrcmpA("B", buf), "Expected \"B\", got \"%s\"\n", buf);
8061
8062     MsiCloseHandle(rec);
8063
8064     r = MsiViewFetch(view, &rec);
8065     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
8066
8067     MsiViewClose(view);
8068     MsiCloseHandle(view);
8069
8070     MsiCloseHandle(hdb);
8071     DeleteFileA(msifile);
8072 }
8073
8074 START_TEST(db)
8075 {
8076     test_msidatabase();
8077     test_msiinsert();
8078     test_msidecomposedesc();
8079     test_msibadqueries();
8080     test_viewmodify();
8081     test_viewgetcolumninfo();
8082     test_getcolinfo();
8083     test_msiexport();
8084     test_longstrings();
8085     test_streamtable();
8086     test_binary();
8087     test_where();
8088     test_msiimport();
8089     test_binary_import();
8090     test_markers();
8091     test_handle_limit();
8092     test_try_transform();
8093     test_join();
8094     test_temporary_table();
8095     test_alter();
8096     test_integers();
8097     test_update();
8098     test_special_tables();
8099     test_tables_order();
8100     test_select_markers();
8101     test_viewmodify_update();
8102     test_stringtable();
8103     test_viewmodify_delete();
8104     test_defaultdatabase();
8105     test_order();
8106     test_viewmodify_delete_temporary();
8107     test_deleterow();
8108     test_quotes();
8109     test_carriagereturn();
8110     test_noquotes();
8111     test_forcecodepage();
8112     test_viewmodify_refresh();
8113     test_where_viewmodify();
8114     test_storages_table();
8115     test_dbtopackage();
8116     test_droptable();
8117     test_dbmerge();
8118     test_insertorder();
8119     test_columnorder();
8120     test_suminfo_import();
8121 }