msi: Don't set the ALLUSERS property.
[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_not_in_selected(void)
1570 {
1571     MSIHANDLE hdb = 0, rec, view;
1572     LPCSTR query;
1573     UINT r;
1574
1575     hdb = create_db();
1576     ok( hdb, "failed to create db\n");
1577
1578     r = run_query(hdb, 0,
1579             "CREATE TABLE `IESTable` ("
1580             "`Action` CHAR(64), "
1581             "`Condition` CHAR(64), "
1582             "`Sequence` LONG PRIMARY KEY `Sequence`)");
1583     ok( r == S_OK, "Cannot create IESTable table: %d\n", r);
1584
1585     r = run_query(hdb, 0,
1586             "CREATE TABLE `CATable` ("
1587             "`Action` CHAR(64), "
1588             "`Type` LONG PRIMARY KEY `Type`)");
1589     ok( r == S_OK, "Cannot create CATable table: %d\n", r);
1590
1591     r = run_query(hdb, 0, "INSERT INTO `IESTable` "
1592             "( `Action`, `Condition`, `Sequence`) "
1593             "VALUES ( 'clean', 'cond4', 4)");
1594     ok( r == S_OK, "cannot add entry to IESTable table:%d\n", r );
1595
1596     r = run_query(hdb, 0, "INSERT INTO `IESTable` "
1597             "( `Action`, `Condition`, `Sequence`) "
1598             "VALUES ( 'depends', 'cond1', 1)");
1599     ok( r == S_OK, "cannot add entry to IESTable table:%d\n", r );
1600
1601     r = run_query(hdb, 0, "INSERT INTO `IESTable` "
1602             "( `Action`, `Condition`, `Sequence`) "
1603             "VALUES ( 'build', 'cond2', 2)");
1604     ok( r == S_OK, "cannot add entry to IESTable table:%d\n", r );
1605
1606     r = run_query(hdb, 0, "INSERT INTO `IESTable` "
1607             "( `Action`, `Condition`, `Sequence`) "
1608             "VALUES ( 'build2', 'cond6', 6)");
1609     ok( r == S_OK, "cannot add entry to IESTable table:%d\n", r );
1610
1611     r = run_query(hdb, 0, "INSERT INTO `IESTable` "
1612             "( `Action`, `Condition`, `Sequence`) "
1613             "VALUES ( 'build', 'cond3', 3)");
1614     ok(r == S_OK, "cannot add entry to IESTable table:%d\n", r );
1615
1616     r = run_query(hdb, 0, "INSERT INTO `CATable` "
1617             "( `Action`, `Type` ) "
1618             "VALUES ( 'build', 32)");
1619     ok(r == S_OK, "cannot add entry to CATable table:%d\n", r );
1620
1621     r = run_query(hdb, 0, "INSERT INTO `CATable` "
1622             "( `Action`, `Type` ) "
1623             "VALUES ( 'depends', 64)");
1624     ok(r == S_OK, "cannot add entry to CATable table:%d\n", r );
1625
1626     r = run_query(hdb, 0, "INSERT INTO `CATable` "
1627             "( `Action`, `Type` ) "
1628             "VALUES ( 'clean', 63)");
1629     ok(r == S_OK, "cannot add entry to CATable table:%d\n", r );
1630
1631     r = run_query(hdb, 0, "INSERT INTO `CATable` "
1632             "( `Action`, `Type` ) "
1633             "VALUES ( 'build2', 34)");
1634     ok(r == S_OK, "cannot add entry to CATable table:%d\n", r );
1635     query = "Select IESTable.Condition from CATable, IESTable where "
1636             "CATable.Action = IESTable.Action and CATable.Type = 32";
1637     r = MsiDatabaseOpenView(hdb, query, &view);
1638     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
1639
1640     r = MsiViewExecute(view, 0);
1641     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
1642
1643     r = MsiViewFetch(view, &rec);
1644     ok( r == ERROR_SUCCESS, "failed to fetch view: %d\n", r );
1645
1646     ok( check_record( rec, 1, "cond2"), "wrong condition\n");
1647
1648     MsiCloseHandle( rec );
1649     r = MsiViewFetch(view, &rec);
1650     ok( r == ERROR_SUCCESS, "failed to fetch view: %d\n", r );
1651
1652     ok( check_record( rec, 1, "cond3"), "wrong condition\n");
1653
1654     MsiCloseHandle( rec );
1655     MsiViewClose(view);
1656     MsiCloseHandle(view);
1657
1658     MsiCloseHandle( hdb );
1659     DeleteFile(msifile);
1660
1661 }
1662
1663
1664 static void test_where(void)
1665 {
1666     MSIHANDLE hdb = 0, rec, view;
1667     LPCSTR query;
1668     UINT r;
1669     DWORD size;
1670     CHAR buf[MAX_PATH];
1671     UINT count;
1672
1673     hdb = create_db();
1674     ok( hdb, "failed to create db\n");
1675
1676     r = run_query( hdb, 0,
1677             "CREATE TABLE `Media` ("
1678             "`DiskId` SHORT NOT NULL, "
1679             "`LastSequence` LONG, "
1680             "`DiskPrompt` CHAR(64) LOCALIZABLE, "
1681             "`Cabinet` CHAR(255), "
1682             "`VolumeLabel` CHAR(32), "
1683             "`Source` CHAR(72) "
1684             "PRIMARY KEY `DiskId`)" );
1685     ok( r == S_OK, "cannot create Media table: %d\n", r );
1686
1687     r = run_query( hdb, 0, "INSERT INTO `Media` "
1688             "( `DiskId`, `LastSequence`, `DiskPrompt`, `Cabinet`, `VolumeLabel`, `Source` ) "
1689             "VALUES ( 1, 0, '', 'zero.cab', '', '' )" );
1690     ok( r == S_OK, "cannot add file to the Media table: %d\n", r );
1691
1692     r = run_query( hdb, 0, "INSERT INTO `Media` "
1693             "( `DiskId`, `LastSequence`, `DiskPrompt`, `Cabinet`, `VolumeLabel`, `Source` ) "
1694             "VALUES ( 2, 1, '', 'one.cab', '', '' )" );
1695     ok( r == S_OK, "cannot add file to the Media table: %d\n", r );
1696
1697     r = run_query( hdb, 0, "INSERT INTO `Media` "
1698             "( `DiskId`, `LastSequence`, `DiskPrompt`, `Cabinet`, `VolumeLabel`, `Source` ) "
1699             "VALUES ( 3, 2, '', 'two.cab', '', '' )" );
1700     ok( r == S_OK, "cannot add file to the Media table: %d\n", r );
1701
1702     query = "SELECT * FROM `Media`";
1703     r = do_query(hdb, query, &rec);
1704     ok(r == ERROR_SUCCESS, "MsiViewFetch failed: %d\n", r);
1705     ok( check_record( rec, 4, "zero.cab"), "wrong cabinet\n");
1706     MsiCloseHandle( rec );
1707
1708     query = "SELECT * FROM `Media` WHERE `LastSequence` >= 1";
1709     r = do_query(hdb, query, &rec);
1710     ok(r == ERROR_SUCCESS, "MsiViewFetch failed: %d\n", r);
1711     ok( check_record( rec, 4, "one.cab"), "wrong cabinet\n");
1712
1713     r = MsiRecordGetInteger(rec, 1);
1714     ok( 2 == r, "field wrong\n");
1715     r = MsiRecordGetInteger(rec, 2);
1716     ok( 1 == r, "field wrong\n");
1717     MsiCloseHandle( rec );
1718
1719     query = "SELECT `DiskId` FROM `Media` WHERE `LastSequence` >= 1 AND DiskId >= 0";
1720     r = MsiDatabaseOpenView(hdb, query, &view);
1721     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
1722
1723     r = MsiViewExecute(view, 0);
1724     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
1725
1726     r = MsiViewFetch(view, &rec);
1727     ok( r == ERROR_SUCCESS, "failed to fetch view: %d\n", r );
1728
1729     count = MsiRecordGetFieldCount( rec );
1730     ok( count == 1, "Expected 1 record fields, got %d\n", count );
1731
1732     size = MAX_PATH;
1733     r = MsiRecordGetString( rec, 1, buf, &size );
1734     ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
1735     ok( !lstrcmp( buf, "2" ),
1736         "For (row %d, column 1) expected '%d', got %s\n", 0, 2, buf );
1737     MsiCloseHandle( rec );
1738
1739     r = MsiViewFetch(view, &rec);
1740     ok( r == ERROR_SUCCESS, "failed to fetch view: %d\n", r );
1741
1742     size = MAX_PATH;
1743     r = MsiRecordGetString( rec, 1, buf, &size );
1744     ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
1745     ok( !lstrcmp( buf, "3" ),
1746         "For (row %d, column 1) expected '%d', got %s\n", 1, 3, buf );
1747     MsiCloseHandle( rec );
1748
1749     r = MsiViewFetch(view, &rec);
1750     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
1751
1752     MsiViewClose(view);
1753     MsiCloseHandle(view);
1754
1755     MsiCloseHandle( rec );
1756
1757     rec = 0;
1758     query = "SELECT * FROM `Media` WHERE `DiskPrompt` IS NULL";
1759     r = do_query(hdb, query, &rec);
1760     ok( r == ERROR_SUCCESS, "query failed: %d\n", r );
1761     MsiCloseHandle( rec );
1762
1763     rec = MsiCreateRecord(1);
1764     MsiRecordSetString(rec, 1, "");
1765
1766     query = "SELECT * FROM `Media` WHERE `DiskPrompt` = ?";
1767     r = MsiDatabaseOpenView(hdb, query, &view);
1768     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1769     r = MsiViewExecute(view, rec);
1770     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1771
1772     MsiCloseHandle(rec);
1773
1774     r = MsiViewFetch(view, &rec);
1775     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1776
1777     MsiCloseHandle(rec);
1778     MsiViewClose(view);
1779     MsiCloseHandle(view);
1780
1781     MsiCloseHandle( hdb );
1782     DeleteFile(msifile);
1783 }
1784
1785 static CHAR CURR_DIR[MAX_PATH];
1786
1787 static const CHAR test_data[] = "FirstPrimaryColumn\tSecondPrimaryColumn\tShortInt\tShortIntNullable\tLongInt\tLongIntNullable\tString\tLocalizableString\tLocalizableStringNullable\n"
1788                                 "s255\ti2\ti2\tI2\ti4\tI4\tS255\tS0\ts0\n"
1789                                 "TestTable\tFirstPrimaryColumn\n"
1790                                 "stringage\t5\t2\t\t2147483640\t-2147483640\tanother string\tlocalizable\tduh\n";
1791
1792 static const CHAR two_primary[] = "PrimaryOne\tPrimaryTwo\n"
1793                                   "s255\ts255\n"
1794                                   "TwoPrimary\tPrimaryOne\tPrimaryTwo\n"
1795                                   "papaya\tleaf\n"
1796                                   "papaya\tflower\n";
1797
1798 static const CHAR endlines1[] = "A\tB\tC\tD\tE\tF\r\n"
1799                                 "s72\ts72\ts72\ts72\ts72\ts72\n"
1800                                 "Table\tA\r\n"
1801                                 "a\tb\tc\td\te\tf\n"
1802                                 "g\th\ti\t\rj\tk\tl\r\n";
1803
1804 static const CHAR endlines2[] = "A\tB\tC\tD\tE\tF\r"
1805                                 "s72\ts72\ts72\ts72\ts72\ts72\n"
1806                                 "Table2\tA\r\n"
1807                                 "a\tb\tc\td\te\tf\n"
1808                                 "g\th\ti\tj\tk\tl\r\n";
1809
1810 static const CHAR suminfo[] = "PropertyId\tValue\n"
1811                               "i2\tl255\n"
1812                               "_SummaryInformation\tPropertyId\n"
1813                               "1\t1252\n"
1814                               "2\tInstaller Database\n"
1815                               "3\tInstaller description\n"
1816                               "4\tWineHQ\n"
1817                               "5\tInstaller\n"
1818                               "6\tInstaller comments\n"
1819                               "7\tIntel;1033\n"
1820                               "9\t{12345678-1234-1234-1234-123456789012}\n"
1821                               "12\t2009/04/12 15:46:11\n"
1822                               "13\t2009/04/12 15:46:11\n"
1823                               "14\t200\n"
1824                               "15\t2\n"
1825                               "18\tVim\n"
1826                               "19\t2\n";
1827
1828 static void write_file(const CHAR *filename, const char *data, int data_size)
1829 {
1830     DWORD size;
1831
1832     HANDLE hf = CreateFile(filename, GENERIC_WRITE, 0, NULL,
1833                            CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1834
1835     WriteFile(hf, data, data_size, &size, NULL);
1836     CloseHandle(hf);
1837 }
1838
1839 static UINT add_table_to_db(MSIHANDLE hdb, LPCSTR table_data)
1840 {
1841     UINT r;
1842
1843     write_file("temp_file", table_data, (lstrlen(table_data) - 1) * sizeof(char));
1844     r = MsiDatabaseImportA(hdb, CURR_DIR, "temp_file");
1845     DeleteFileA("temp_file");
1846
1847     return r;
1848 }
1849
1850 static void test_suminfo_import(void)
1851 {
1852     MSIHANDLE hdb, hsi, view = 0;
1853     LPCSTR query;
1854     UINT r, count, size, type;
1855     char str_value[50];
1856     INT int_value;
1857     FILETIME ft_value;
1858
1859     GetCurrentDirectoryA(MAX_PATH, CURR_DIR);
1860
1861     r = MsiOpenDatabaseA(msifile, MSIDBOPEN_CREATE, &hdb);
1862     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
1863
1864     r = add_table_to_db(hdb, suminfo);
1865     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
1866
1867     /* _SummaryInformation is not imported as a regular table... */
1868
1869     query = "SELECT * FROM `_SummaryInformation`";
1870     r = MsiDatabaseOpenViewA(hdb, query, &view);
1871     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %u\n", r);
1872     MsiCloseHandle(view);
1873
1874     /* ...its data is added to the special summary information stream */
1875
1876     r = MsiGetSummaryInformationA(hdb, NULL, 0, &hsi);
1877     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
1878
1879     r = MsiSummaryInfoGetPropertyCount(hsi, &count);
1880     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
1881     ok(count == 14, "Expected 14, got %u\n", count);
1882
1883     r = MsiSummaryInfoGetPropertyA(hsi, PID_CODEPAGE, &type, &int_value, NULL, NULL, NULL);
1884     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
1885     ok(type ==  VT_I2, "Expected VT_I2, got %u\n", type);
1886     ok(int_value == 1252, "Expected 1252, got %d\n", int_value);
1887
1888     size = sizeof(str_value);
1889     r = MsiSummaryInfoGetPropertyA(hsi, PID_TITLE, &type, NULL, NULL, str_value, &size);
1890     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
1891     ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
1892     ok(size == 18, "Expected 18, got %u\n", size);
1893     ok(!strcmp(str_value, "Installer Database"),
1894        "Expected \"Installer Database\", got %s\n", str_value);
1895
1896     size = sizeof(str_value);
1897     r = MsiSummaryInfoGetPropertyA(hsi, PID_SUBJECT, &type, NULL, NULL, str_value, &size);
1898     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
1899     ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
1900     ok(!strcmp(str_value, "Installer description"),
1901        "Expected \"Installer description\", got %s\n", str_value);
1902
1903     size = sizeof(str_value);
1904     r = MsiSummaryInfoGetPropertyA(hsi, PID_AUTHOR, &type, NULL, NULL, str_value, &size);
1905     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
1906     ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
1907     ok(!strcmp(str_value, "WineHQ"),
1908        "Expected \"WineHQ\", got %s\n", str_value);
1909
1910     size = sizeof(str_value);
1911     r = MsiSummaryInfoGetPropertyA(hsi, PID_KEYWORDS, &type, NULL, NULL, str_value, &size);
1912     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
1913     ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
1914     ok(!strcmp(str_value, "Installer"),
1915        "Expected \"Installer\", got %s\n", str_value);
1916
1917     size = sizeof(str_value);
1918     r = MsiSummaryInfoGetPropertyA(hsi, PID_COMMENTS, &type, NULL, NULL, str_value, &size);
1919     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
1920     ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
1921     ok(!strcmp(str_value, "Installer comments"),
1922        "Expected \"Installer comments\", got %s\n", str_value);
1923
1924     size = sizeof(str_value);
1925     r = MsiSummaryInfoGetPropertyA(hsi, PID_TEMPLATE, &type, NULL, NULL, str_value, &size);
1926     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
1927     ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
1928     ok(!strcmp(str_value, "Intel;1033"),
1929        "Expected \"Intel;1033\", got %s\n", str_value);
1930
1931     size = sizeof(str_value);
1932     r = MsiSummaryInfoGetPropertyA(hsi, PID_REVNUMBER, &type, NULL, NULL, str_value, &size);
1933     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
1934     ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
1935     ok(!strcmp(str_value, "{12345678-1234-1234-1234-123456789012}"),
1936        "Expected \"{12345678-1234-1234-1234-123456789012}\", got %s\n", str_value);
1937
1938     r = MsiSummaryInfoGetPropertyA(hsi, PID_CREATE_DTM, &type, NULL, &ft_value, NULL, NULL);
1939     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
1940     ok(type == VT_FILETIME, "Expected VT_FILETIME, got %u\n", type);
1941
1942     r = MsiSummaryInfoGetPropertyA(hsi, PID_LASTSAVE_DTM, &type, NULL, &ft_value, NULL, NULL);
1943     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
1944     ok(type == VT_FILETIME, "Expected VT_FILETIME, got %u\n", type);
1945
1946     r = MsiSummaryInfoGetPropertyA(hsi, PID_PAGECOUNT, &type, &int_value, NULL, NULL, NULL);
1947     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
1948     ok(type ==  VT_I4, "Expected VT_I4, got %u\n", type);
1949     ok(int_value == 200, "Expected 200, got %d\n", int_value);
1950
1951     r = MsiSummaryInfoGetPropertyA(hsi, PID_WORDCOUNT, &type, &int_value, NULL, NULL, NULL);
1952     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
1953     ok(type ==  VT_I4, "Expected VT_I4, got %u\n", type);
1954     ok(int_value == 2, "Expected 2, got %d\n", int_value);
1955
1956     r = MsiSummaryInfoGetPropertyA(hsi, PID_SECURITY, &type, &int_value, NULL, NULL, NULL);
1957     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
1958     ok(type ==  VT_I4, "Expected VT_I4, got %u\n", type);
1959     ok(int_value == 2, "Expected 2, got %d\n", int_value);
1960
1961     size = sizeof(str_value);
1962     r = MsiSummaryInfoGetPropertyA(hsi, PID_APPNAME, &type, NULL, NULL, str_value, &size);
1963     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
1964     ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
1965     ok(!strcmp(str_value, "Vim"), "Expected \"Vim\", got %s\n", str_value);
1966
1967     MsiCloseHandle(hsi);
1968     MsiCloseHandle(hdb);
1969     DeleteFileA(msifile);
1970 }
1971
1972 static void test_msiimport(void)
1973 {
1974     MSIHANDLE hdb, view, rec;
1975     LPCSTR query;
1976     UINT r, count;
1977     signed int i;
1978
1979     GetCurrentDirectoryA(MAX_PATH, CURR_DIR);
1980
1981     r = MsiOpenDatabaseA(msifile, MSIDBOPEN_CREATE, &hdb);
1982     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1983
1984     r = add_table_to_db(hdb, test_data);
1985     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1986
1987     r = add_table_to_db(hdb, two_primary);
1988     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1989
1990     r = add_table_to_db(hdb, endlines1);
1991     if (r == ERROR_FUNCTION_FAILED)
1992     {
1993         /* win9x doesn't handle this case */
1994         skip("endlines not handled correctly.\n");
1995         MsiCloseHandle(hdb);
1996         DeleteFileA(msifile);
1997         return;
1998     }
1999
2000     r = add_table_to_db(hdb, endlines2);
2001     ok(r == ERROR_FUNCTION_FAILED,
2002        "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
2003
2004     query = "SELECT * FROM `TestTable`";
2005     r = MsiDatabaseOpenView(hdb, query, &view);
2006     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2007
2008     r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec);
2009     count = MsiRecordGetFieldCount(rec);
2010     ok(count == 9, "Expected 9, got %d\n", count);
2011     ok(check_record(rec, 1, "FirstPrimaryColumn"), "Expected FirstPrimaryColumn\n");
2012     ok(check_record(rec, 2, "SecondPrimaryColumn"), "Expected SecondPrimaryColumn\n");
2013     ok(check_record(rec, 3, "ShortInt"), "Expected ShortInt\n");
2014     ok(check_record(rec, 4, "ShortIntNullable"), "Expected ShortIntNullalble\n");
2015     ok(check_record(rec, 5, "LongInt"), "Expected LongInt\n");
2016     ok(check_record(rec, 6, "LongIntNullable"), "Expected LongIntNullalble\n");
2017     ok(check_record(rec, 7, "String"), "Expected String\n");
2018     ok(check_record(rec, 8, "LocalizableString"), "Expected LocalizableString\n");
2019     ok(check_record(rec, 9, "LocalizableStringNullable"), "Expected LocalizableStringNullable\n");
2020     MsiCloseHandle(rec);
2021
2022     r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
2023     count = MsiRecordGetFieldCount(rec);
2024     ok(count == 9, "Expected 9, got %d\n", count);
2025     ok(check_record(rec, 1, "s255"), "Expected s255\n");
2026     ok(check_record(rec, 2, "i2"), "Expected i2\n");
2027     ok(check_record(rec, 3, "i2"), "Expected i2\n");
2028     ok(check_record(rec, 4, "I2"), "Expected I2\n");
2029     ok(check_record(rec, 5, "i4"), "Expected i4\n");
2030     ok(check_record(rec, 6, "I4"), "Expected I4\n");
2031     ok(check_record(rec, 7, "S255"), "Expected S255\n");
2032     ok(check_record(rec, 8, "S0"), "Expected S0\n");
2033     ok(check_record(rec, 9, "s0"), "Expected s0\n");
2034     MsiCloseHandle(rec);
2035
2036     query = "SELECT * FROM `TestTable`";
2037     r = do_query(hdb, query, &rec);
2038     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2039     ok(check_record(rec, 1, "stringage"), "Expected 'stringage'\n");
2040     ok(check_record(rec, 7, "another string"), "Expected 'another string'\n");
2041     ok(check_record(rec, 8, "localizable"), "Expected 'localizable'\n");
2042     ok(check_record(rec, 9, "duh"), "Expected 'duh'\n");
2043
2044     i = MsiRecordGetInteger(rec, 2);
2045     ok(i == 5, "Expected 5, got %d\n", i);
2046
2047     i = MsiRecordGetInteger(rec, 3);
2048     ok(i == 2, "Expected 2, got %d\n", i);
2049
2050     i = MsiRecordGetInteger(rec, 4);
2051     ok(i == MSI_NULL_INTEGER, "Expected MSI_NULL_INTEGER, got %d\n", i);
2052
2053     i = MsiRecordGetInteger(rec, 5);
2054     ok(i == 2147483640, "Expected 2147483640, got %d\n", i);
2055
2056     i = MsiRecordGetInteger(rec, 6);
2057     ok(i == -2147483640, "Expected -2147483640, got %d\n", i);
2058
2059     MsiCloseHandle(rec);
2060     MsiViewClose(view);
2061     MsiCloseHandle(view);
2062
2063     query = "SELECT * FROM `TwoPrimary`";
2064     r = MsiDatabaseOpenView(hdb, query, &view);
2065     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2066
2067     r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec);
2068     count = MsiRecordGetFieldCount(rec);
2069     ok(count == 2, "Expected 2, got %d\n", count);
2070     ok(check_record(rec, 1, "PrimaryOne"), "Expected PrimaryOne\n");
2071     ok(check_record(rec, 2, "PrimaryTwo"), "Expected PrimaryTwo\n");
2072
2073     MsiCloseHandle(rec);
2074
2075     r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
2076     count = MsiRecordGetFieldCount(rec);
2077     ok(count == 2, "Expected 2, got %d\n", count);
2078     ok(check_record(rec, 1, "s255"), "Expected s255\n");
2079     ok(check_record(rec, 2, "s255"), "Expected s255\n");
2080     MsiCloseHandle(rec);
2081
2082     r = MsiViewExecute(view, 0);
2083     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2084
2085     r = MsiViewFetch(view, &rec);
2086     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2087
2088     ok(check_record(rec, 1, "papaya"), "Expected 'papaya'\n");
2089     ok(check_record(rec, 2, "leaf"), "Expected 'leaf'\n");
2090
2091     MsiCloseHandle(rec);
2092
2093     r = MsiViewFetch(view, &rec);
2094     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2095
2096     ok(check_record(rec, 1, "papaya"), "Expected 'papaya'\n");
2097     ok(check_record(rec, 2, "flower"), "Expected 'flower'\n");
2098
2099     MsiCloseHandle(rec);
2100
2101     r = MsiViewFetch(view, &rec);
2102     ok(r == ERROR_NO_MORE_ITEMS,
2103        "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
2104
2105     r = MsiViewClose(view);
2106     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2107
2108     MsiCloseHandle(view);
2109
2110     query = "SELECT * FROM `Table`";
2111     r = MsiDatabaseOpenView(hdb, query, &view);
2112     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2113
2114     r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec);
2115     count = MsiRecordGetFieldCount(rec);
2116     ok(count == 6, "Expected 6, got %d\n", count);
2117     ok(check_record(rec, 1, "A"), "Expected A\n");
2118     ok(check_record(rec, 2, "B"), "Expected B\n");
2119     ok(check_record(rec, 3, "C"), "Expected C\n");
2120     ok(check_record(rec, 4, "D"), "Expected D\n");
2121     ok(check_record(rec, 5, "E"), "Expected E\n");
2122     ok(check_record(rec, 6, "F"), "Expected F\n");
2123     MsiCloseHandle(rec);
2124
2125     r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
2126     count = MsiRecordGetFieldCount(rec);
2127     ok(count == 6, "Expected 6, got %d\n", count);
2128     ok(check_record(rec, 1, "s72"), "Expected s72\n");
2129     ok(check_record(rec, 2, "s72"), "Expected s72\n");
2130     ok(check_record(rec, 3, "s72"), "Expected s72\n");
2131     ok(check_record(rec, 4, "s72"), "Expected s72\n");
2132     ok(check_record(rec, 5, "s72"), "Expected s72\n");
2133     ok(check_record(rec, 6, "s72"), "Expected s72\n");
2134     MsiCloseHandle(rec);
2135
2136     MsiViewClose(view);
2137     MsiCloseHandle(view);
2138
2139     query = "SELECT * FROM `Table`";
2140     r = MsiDatabaseOpenView(hdb, query, &view);
2141     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2142
2143     r = MsiViewExecute(view, 0);
2144     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2145
2146     r = MsiViewFetch(view, &rec);
2147     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2148     ok(check_record(rec, 1, "a"), "Expected 'a'\n");
2149     ok(check_record(rec, 2, "b"), "Expected 'b'\n");
2150     ok(check_record(rec, 3, "c"), "Expected 'c'\n");
2151     ok(check_record(rec, 4, "d"), "Expected 'd'\n");
2152     ok(check_record(rec, 5, "e"), "Expected 'e'\n");
2153     ok(check_record(rec, 6, "f"), "Expected 'f'\n");
2154
2155     MsiCloseHandle(rec);
2156
2157     r = MsiViewFetch(view, &rec);
2158     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2159     ok(check_record(rec, 1, "g"), "Expected 'g'\n");
2160     ok(check_record(rec, 2, "h"), "Expected 'h'\n");
2161     ok(check_record(rec, 3, "i"), "Expected 'i'\n");
2162     ok(check_record(rec, 4, "j"), "Expected 'j'\n");
2163     ok(check_record(rec, 5, "k"), "Expected 'k'\n");
2164     ok(check_record(rec, 6, "l"), "Expected 'l'\n");
2165
2166     MsiCloseHandle(rec);
2167
2168     r = MsiViewFetch(view, &rec);
2169     ok(r == ERROR_NO_MORE_ITEMS,
2170        "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
2171
2172     MsiViewClose(view);
2173     MsiCloseHandle(view);
2174     MsiCloseHandle(hdb);
2175     DeleteFileA(msifile);
2176 }
2177
2178 static const CHAR bin_import_dat[] = "Name\tData\r\n"
2179                                      "s72\tV0\r\n"
2180                                      "Binary\tName\r\n"
2181                                      "filename1\tfilename1.ibd\r\n";
2182
2183 static void test_binary_import(void)
2184 {
2185     MSIHANDLE hdb = 0, rec;
2186     char file[MAX_PATH];
2187     char buf[MAX_PATH];
2188     char path[MAX_PATH];
2189     DWORD size;
2190     LPCSTR query;
2191     UINT r;
2192
2193     /* create files to import */
2194     write_file("bin_import.idt", bin_import_dat,
2195           (sizeof(bin_import_dat) - 1) * sizeof(char));
2196     CreateDirectory("bin_import", NULL);
2197     create_file_data("bin_import/filename1.ibd", "just some words", 15);
2198
2199     /* import files into database */
2200     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
2201     ok( r == ERROR_SUCCESS , "Failed to open database\n");
2202
2203     GetCurrentDirectory(MAX_PATH, path);
2204     r = MsiDatabaseImport(hdb, path, "bin_import.idt");
2205     ok(r == ERROR_SUCCESS , "Failed to import Binary table\n");
2206
2207     /* read file from the Binary table */
2208     query = "SELECT * FROM `Binary`";
2209     r = do_query(hdb, query, &rec);
2210     ok(r == ERROR_SUCCESS, "SELECT query failed: %d\n", r);
2211
2212     size = MAX_PATH;
2213     r = MsiRecordGetString(rec, 1, file, &size);
2214     ok(r == ERROR_SUCCESS, "Failed to get string: %d\n", r);
2215     ok(!lstrcmp(file, "filename1"), "Expected 'filename1', got %s\n", file);
2216
2217     size = MAX_PATH;
2218     memset(buf, 0, MAX_PATH);
2219     r = MsiRecordReadStream(rec, 2, buf, &size);
2220     ok(r == ERROR_SUCCESS, "Failed to get stream: %d\n", r);
2221     ok(!lstrcmp(buf, "just some words"),
2222         "Expected 'just some words', got %s\n", buf);
2223
2224     r = MsiCloseHandle(rec);
2225     ok(r == ERROR_SUCCESS , "Failed to close record handle\n");
2226
2227     r = MsiCloseHandle(hdb);
2228     ok(r == ERROR_SUCCESS , "Failed to close database\n");
2229
2230     DeleteFile("bin_import/filename1.ibd");
2231     RemoveDirectory("bin_import");
2232     DeleteFile("bin_import.idt");
2233 }
2234
2235 static void test_markers(void)
2236 {
2237     MSIHANDLE hdb, rec;
2238     LPCSTR query;
2239     UINT r;
2240
2241     hdb = create_db();
2242     ok( hdb, "failed to create db\n");
2243
2244     rec = MsiCreateRecord(3);
2245     MsiRecordSetString(rec, 1, "Table");
2246     MsiRecordSetString(rec, 2, "Apples");
2247     MsiRecordSetString(rec, 3, "Oranges");
2248
2249     /* try a legit create */
2250     query = "CREATE TABLE `Table` ( `One` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`)";
2251     r = run_query(hdb, 0, query);
2252     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2253     MsiCloseHandle(rec);
2254
2255     /* try table name as marker */
2256     rec = MsiCreateRecord(1);
2257     MsiRecordSetString(rec, 1, "Fable");
2258     query = "CREATE TABLE `?` ( `One` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`)";
2259     r = run_query(hdb, rec, query);
2260     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2261
2262     /* verify that we just created a table called '?', not 'Fable' */
2263     r = try_query(hdb, "SELECT * from `Fable`");
2264     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2265
2266     r = try_query(hdb, "SELECT * from `?`");
2267     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2268
2269     /* try table name as marker without backticks */
2270     MsiRecordSetString(rec, 1, "Mable");
2271     query = "CREATE TABLE ? ( `One` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`)";
2272     r = run_query(hdb, rec, query);
2273     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2274
2275     /* try one column name as marker */
2276     MsiRecordSetString(rec, 1, "One");
2277     query = "CREATE TABLE `Mable` ( `?` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`)";
2278     r = run_query(hdb, rec, query);
2279     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2280     MsiCloseHandle(rec);
2281
2282     /* try column names as markers */
2283     rec = MsiCreateRecord(2);
2284     MsiRecordSetString(rec, 1, "One");
2285     MsiRecordSetString(rec, 2, "Two");
2286     query = "CREATE TABLE `Mable` ( `?` SHORT NOT NULL, `?` CHAR(255) PRIMARY KEY `One`)";
2287     r = run_query(hdb, rec, query);
2288     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2289     MsiCloseHandle(rec);
2290
2291     /* try names with backticks */
2292     rec = MsiCreateRecord(3);
2293     MsiRecordSetString(rec, 1, "One");
2294     MsiRecordSetString(rec, 2, "Two");
2295     MsiRecordSetString(rec, 3, "One");
2296     query = "CREATE TABLE `Mable` ( `?` SHORT NOT NULL, `?` CHAR(255) PRIMARY KEY `?`)";
2297     r = run_query(hdb, rec, query);
2298     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2299
2300     /* try names with backticks, minus definitions */
2301     query = "CREATE TABLE `Mable` ( `?`, `?` PRIMARY KEY `?`)";
2302     r = run_query(hdb, rec, query);
2303     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2304
2305     /* try names without backticks */
2306     query = "CREATE TABLE `Mable` ( ? SHORT NOT NULL, ? CHAR(255) PRIMARY KEY ?)";
2307     r = run_query(hdb, rec, query);
2308     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2309     MsiCloseHandle(rec);
2310
2311     /* try one long marker */
2312     rec = MsiCreateRecord(1);
2313     MsiRecordSetString(rec, 1, "`One` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`");
2314     query = "CREATE TABLE `Mable` ( ? )";
2315     r = run_query(hdb, rec, query);
2316     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2317     MsiCloseHandle(rec);
2318
2319     /* try all names as markers */
2320     rec = MsiCreateRecord(4);
2321     MsiRecordSetString(rec, 1, "Mable");
2322     MsiRecordSetString(rec, 2, "One");
2323     MsiRecordSetString(rec, 3, "Two");
2324     MsiRecordSetString(rec, 4, "One");
2325     query = "CREATE TABLE `?` ( `?` SHORT NOT NULL, `?` CHAR(255) PRIMARY KEY `?`)";
2326     r = run_query(hdb, rec, query);
2327     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2328     MsiCloseHandle(rec);
2329
2330     /* try a legit insert */
2331     query = "INSERT INTO `Table` ( `One`, `Two` ) VALUES ( 5, 'hello' )";
2332     r = run_query(hdb, 0, query);
2333     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2334
2335     r = try_query(hdb, "SELECT * from `Table`");
2336     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2337
2338     /* try values as markers */
2339     rec = MsiCreateRecord(2);
2340     MsiRecordSetInteger(rec, 1, 4);
2341     MsiRecordSetString(rec, 2, "hi");
2342     query = "INSERT INTO `Table` ( `One`, `Two` ) VALUES ( ?, '?' )";
2343     r = run_query(hdb, rec, query);
2344     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2345     MsiCloseHandle(rec);
2346
2347     /* try column names and values as markers */
2348     rec = MsiCreateRecord(4);
2349     MsiRecordSetString(rec, 1, "One");
2350     MsiRecordSetString(rec, 2, "Two");
2351     MsiRecordSetInteger(rec, 3, 5);
2352     MsiRecordSetString(rec, 4, "hi");
2353     query = "INSERT INTO `Table` ( `?`, `?` ) VALUES ( ?, '?' )";
2354     r = run_query(hdb, rec, query);
2355     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2356     MsiCloseHandle(rec);
2357
2358     /* try column names as markers */
2359     rec = MsiCreateRecord(2);
2360     MsiRecordSetString(rec, 1, "One");
2361     MsiRecordSetString(rec, 2, "Two");
2362     query = "INSERT INTO `Table` ( `?`, `?` ) VALUES ( 3, 'yellow' )";
2363     r = run_query(hdb, rec, query);
2364     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2365     MsiCloseHandle(rec);
2366
2367     /* try table name as a marker */
2368     rec = MsiCreateRecord(1);
2369     MsiRecordSetString(rec, 1, "Table");
2370     query = "INSERT INTO `?` ( `One`, `Two` ) VALUES ( 2, 'green' )";
2371     r = run_query(hdb, rec, query);
2372     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2373     MsiCloseHandle(rec);
2374
2375     /* try table name and values as markers */
2376     rec = MsiCreateRecord(3);
2377     MsiRecordSetString(rec, 1, "Table");
2378     MsiRecordSetInteger(rec, 2, 10);
2379     MsiRecordSetString(rec, 3, "haha");
2380     query = "INSERT INTO `?` ( `One`, `Two` ) VALUES ( ?, '?' )";
2381     r = run_query(hdb, rec, query);
2382     ok(r == ERROR_FUNCTION_FAILED, "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
2383     MsiCloseHandle(rec);
2384
2385     /* try all markers */
2386     rec = MsiCreateRecord(5);
2387     MsiRecordSetString(rec, 1, "Table");
2388     MsiRecordSetString(rec, 1, "One");
2389     MsiRecordSetString(rec, 1, "Two");
2390     MsiRecordSetInteger(rec, 2, 10);
2391     MsiRecordSetString(rec, 3, "haha");
2392     query = "INSERT INTO `?` ( `?`, `?` ) VALUES ( ?, '?' )";
2393     r = run_query(hdb, rec, query);
2394     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2395     MsiCloseHandle(rec);
2396
2397     /* insert an integer as a string */
2398     rec = MsiCreateRecord(2);
2399     MsiRecordSetString(rec, 1, "11");
2400     MsiRecordSetString(rec, 2, "hi");
2401     query = "INSERT INTO `Table` ( `One`, `Two` ) VALUES ( ?, '?' )";
2402     r = run_query(hdb, rec, query);
2403     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2404     MsiCloseHandle(rec);
2405
2406     /* leave off the '' for the string */
2407     rec = MsiCreateRecord(2);
2408     MsiRecordSetInteger(rec, 1, 12);
2409     MsiRecordSetString(rec, 2, "hi");
2410     query = "INSERT INTO `Table` ( `One`, `Two` ) VALUES ( ?, ? )";
2411     r = run_query(hdb, rec, query);
2412     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2413     MsiCloseHandle(rec);
2414
2415     MsiCloseHandle(hdb);
2416     DeleteFileA(msifile);
2417 }
2418
2419 #define MY_NVIEWS 4000    /* Largest installer I've seen uses < 2k */
2420 static void test_handle_limit(void)
2421 {
2422     int i;
2423     MSIHANDLE hdb;
2424     MSIHANDLE hviews[MY_NVIEWS];
2425     UINT r;
2426
2427     /* create an empty db */
2428     hdb = create_db();
2429     ok( hdb, "failed to create db\n");
2430
2431     memset(hviews, 0, sizeof(hviews));
2432
2433     for (i=0; i<MY_NVIEWS; i++) {
2434         static char szQueryBuf[256] = "SELECT * from `_Tables`";
2435         hviews[i] = 0xdeadbeeb;
2436         r = MsiDatabaseOpenView(hdb, szQueryBuf, &hviews[i]);
2437         if( r != ERROR_SUCCESS || hviews[i] == 0xdeadbeeb || 
2438             hviews[i] == 0 || (i && (hviews[i] == hviews[i-1])))
2439             break;
2440     }
2441
2442     ok( i == MY_NVIEWS, "problem opening views\n");
2443
2444     for (i=0; i<MY_NVIEWS; i++) {
2445         if (hviews[i] != 0 && hviews[i] != 0xdeadbeeb) {
2446             MsiViewClose(hviews[i]);
2447             r = MsiCloseHandle(hviews[i]);
2448             if (r != ERROR_SUCCESS)
2449                 break;
2450         }
2451     }
2452
2453     ok( i == MY_NVIEWS, "problem closing views\n");
2454
2455     r = MsiCloseHandle(hdb);
2456     ok( r == ERROR_SUCCESS, "failed to close database\n");
2457 }
2458
2459 static void generate_transform(void)
2460 {
2461     MSIHANDLE hdb1, hdb2, hrec;
2462     LPCSTR query;
2463     UINT r;
2464
2465     /* start with two identical databases */
2466     CopyFile(msifile2, msifile, FALSE);
2467
2468     r = MsiOpenDatabase(msifile, MSIDBOPEN_TRANSACT, &hdb1 );
2469     ok( r == ERROR_SUCCESS , "Failed to create database\n" );
2470
2471     r = MsiDatabaseCommit( hdb1 );
2472     ok( r == ERROR_SUCCESS , "Failed to commit database\n" );
2473
2474     r = MsiOpenDatabase(msifile2, MSIDBOPEN_READONLY, &hdb2 );
2475     ok( r == ERROR_SUCCESS , "Failed to create database\n" );
2476
2477     /* the transform between two identical database should be empty */
2478     r = MsiDatabaseGenerateTransform(hdb1, hdb2, NULL, 0, 0);
2479     todo_wine {
2480     ok( r == ERROR_NO_DATA, "return code %d, should be ERROR_NO_DATA\n", r );
2481     }
2482
2483     query = "CREATE TABLE `AAR` ( `BAR` SHORT NOT NULL, `CAR` CHAR(255) PRIMARY KEY `CAR`)";
2484     r = run_query(hdb1, 0, query);
2485     ok(r == ERROR_SUCCESS, "failed to add table\n");
2486
2487     query = "INSERT INTO `AAR` ( `BAR`, `CAR` ) VALUES ( 1, 'vw' )";
2488     r = run_query(hdb1, 0, query);
2489     ok(r == ERROR_SUCCESS, "failed to add row 1\n");
2490
2491     query = "INSERT INTO `AAR` ( `BAR`, `CAR` ) VALUES ( 2, 'bmw' )";
2492     r = run_query(hdb1, 0, query);
2493     ok(r == ERROR_SUCCESS, "failed to add row 2\n");
2494
2495     query = "UPDATE `MOO` SET `OOO` = 'c' WHERE `NOO` = 1";
2496     r = run_query(hdb1, 0, query);
2497     ok(r == ERROR_SUCCESS, "failed to modify row\n");
2498
2499     query = "DELETE FROM `MOO` WHERE `NOO` = 3";
2500     r = run_query(hdb1, 0, query);
2501     ok(r == ERROR_SUCCESS, "failed to delete row\n");
2502
2503     hrec = MsiCreateRecord(2);
2504     r = MsiRecordSetInteger(hrec, 1, 1);
2505     ok(r == ERROR_SUCCESS, "failed to set integer\n");
2506
2507     write_file("testdata.bin", "naengmyon", 9);
2508     r = MsiRecordSetStream(hrec, 2, "testdata.bin");
2509     ok(r == ERROR_SUCCESS, "failed to set stream\n");
2510
2511     query = "INSERT INTO `BINARY` ( `ID`, `BLOB` ) VALUES ( ?, ? )";
2512     r = run_query(hdb1, hrec, query);
2513     ok(r == ERROR_SUCCESS, "failed to add row with blob\n");
2514
2515     MsiCloseHandle(hrec);
2516
2517     query = "ALTER TABLE `MOO` ADD `COW` INTEGER";
2518     r = run_query(hdb1, 0, query);
2519     ok(r == ERROR_SUCCESS, "failed to add column\n");
2520
2521     query = "ALTER TABLE `MOO` ADD `PIG` INTEGER";
2522     r = run_query(hdb1, 0, query);
2523     ok(r == ERROR_SUCCESS, "failed to add column\n");
2524
2525     query = "UPDATE `MOO` SET `PIG` = 5 WHERE `NOO` = 1";
2526     r = run_query(hdb1, 0, query);
2527     ok(r == ERROR_SUCCESS, "failed to modify row\n");
2528
2529     query = "CREATE TABLE `Property` ( `Property` CHAR(72) NOT NULL, "
2530             "`Value` CHAR(0) PRIMARY KEY `Property`)";
2531     r = run_query(hdb1, 0, query);
2532     ok(r == ERROR_SUCCESS, "failed to add property table\n");
2533
2534     query = "INSERT INTO `Property` ( `Property`, `Value` ) VALUES ( 'prop', 'val' )";
2535     r = run_query(hdb1, 0, query);
2536     ok(r == ERROR_SUCCESS, "failed to add property\n");
2537
2538     /* database needs to be committed */
2539     MsiDatabaseCommit(hdb1);
2540
2541     r = MsiDatabaseGenerateTransform(hdb1, hdb2, mstfile, 0, 0);
2542     ok( r == ERROR_SUCCESS, "return code %d, should be ERROR_SUCCESS\n", r );
2543
2544     MsiCloseHandle( hdb1 );
2545     MsiCloseHandle( hdb2 );
2546
2547     DeleteFile("testdata.bin");
2548 }
2549
2550 /* data for generating a transform */
2551
2552 /* tables transform names - encoded as they would be in an msi database file */
2553 static const WCHAR name1[] = { 0x4840, 0x3a8a, 0x481b, 0 }; /* AAR */
2554 static const WCHAR name2[] = { 0x4840, 0x3b3f, 0x43f2, 0x4438, 0x45b1, 0 }; /* _Columns */
2555 static const WCHAR name3[] = { 0x4840, 0x3f7f, 0x4164, 0x422f, 0x4836, 0 }; /* _Tables */
2556 static const WCHAR name4[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0 }; /* _StringData */
2557 static const WCHAR name5[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0 }; /* _StringPool */
2558 static const WCHAR name6[] = { 0x4840, 0x3e16, 0x4818, 0}; /* MOO */
2559 static const WCHAR name7[] = { 0x4840, 0x3c8b, 0x3a97, 0x409b, 0 }; /* BINARY */
2560 static const WCHAR name8[] = { 0x3c8b, 0x3a97, 0x409b, 0x387e, 0 }; /* BINARY.1 */
2561 static const WCHAR name9[] = { 0x4840, 0x4559, 0x44f2, 0x4568, 0x4737, 0 }; /* Property */
2562
2563 /* data in each table */
2564 static const WCHAR data1[] = { /* AAR */
2565     0x0201, 0x0008, 0x8001,  /* 0x0201 = add row (1), two shorts */
2566     0x0201, 0x0009, 0x8002,
2567 };
2568 static const WCHAR data2[] = { /* _Columns */
2569     0x0401, 0x0001, 0x8003, 0x0002, 0x9502,
2570     0x0401, 0x0001, 0x8004, 0x0003, 0x9502,
2571     0x0401, 0x0005, 0x0000, 0x0006, 0xbdff,  /* 0x0401 = add row (1), 4 shorts */
2572     0x0401, 0x0005, 0x0000, 0x0007, 0x8502,
2573     0x0401, 0x000a, 0x0000, 0x000a, 0xad48,
2574     0x0401, 0x000a, 0x0000, 0x000b, 0x9d00,
2575 };
2576 static const WCHAR data3[] = { /* _Tables */
2577     0x0101, 0x0005, /* 0x0101 = add row (1), 1 short */
2578     0x0101, 0x000a,
2579 };
2580 static const char data4[] = /* _StringData */
2581     "MOOCOWPIGcAARCARBARvwbmwPropertyValuepropval";  /* all the strings squashed together */
2582 static const WCHAR data5[] = { /* _StringPool */
2583 /*  len, refs */
2584     0,   0,    /* string 0 ''    */
2585     3,   2,    /* string 1 'MOO' */
2586     3,   1,    /* string 2 'COW' */
2587     3,   1,    /* string 3 'PIG' */
2588     1,   1,    /* string 4 'c'   */
2589     3,   3,    /* string 5 'AAR' */
2590     3,   1,    /* string 6 'CAR' */
2591     3,   1,    /* string 7 'BAR' */
2592     2,   1,    /* string 8 'vw'  */
2593     3,   1,    /* string 9 'bmw' */
2594     8,   4,    /* string 10 'Property' */
2595     5,   1,    /* string 11 'Value' */
2596     4,   1,    /* string 12 'prop' */
2597     3,   1,    /* string 13 'val' */
2598 };
2599 /* update row, 0x0002 is a bitmask of present column data, keys are excluded */
2600 static const WCHAR data6[] = { /* MOO */
2601     0x000a, 0x8001, 0x0004, 0x8005, /* update row */
2602     0x0000, 0x8003,         /* delete row */
2603 };
2604
2605 static const WCHAR data7[] = { /* BINARY */
2606     0x0201, 0x8001, 0x0001,
2607 };
2608
2609 static const char data8[] =  /* stream data for the BINARY table */
2610     "naengmyon";
2611
2612 static const WCHAR data9[] = { /* Property */
2613     0x0201, 0x000c, 0x000d,
2614 };
2615
2616 static const struct {
2617     LPCWSTR name;
2618     const void *data;
2619     DWORD size;
2620 } table_transform_data[] =
2621 {
2622     { name1, data1, sizeof data1 },
2623     { name2, data2, sizeof data2 },
2624     { name3, data3, sizeof data3 },
2625     { name4, data4, sizeof data4 - 1 },
2626     { name5, data5, sizeof data5 },
2627     { name6, data6, sizeof data6 },
2628     { name7, data7, sizeof data7 },
2629     { name8, data8, sizeof data8 - 1 },
2630     { name9, data9, sizeof data9 },
2631 };
2632
2633 #define NUM_TRANSFORM_TABLES (sizeof table_transform_data/sizeof table_transform_data[0])
2634
2635 static void generate_transform_manual(void)
2636 {
2637     IStorage *stg = NULL;
2638     IStream *stm;
2639     WCHAR name[0x20];
2640     HRESULT r;
2641     DWORD i, count;
2642     const DWORD mode = STGM_CREATE|STGM_READWRITE|STGM_DIRECT|STGM_SHARE_EXCLUSIVE;
2643
2644     const CLSID CLSID_MsiTransform = { 0xc1082,0,0,{0xc0,0,0,0,0,0,0,0x46}};
2645
2646     MultiByteToWideChar(CP_ACP, 0, mstfile, -1, name, 0x20);
2647
2648     r = StgCreateDocfile(name, mode, 0, &stg);
2649     ok(r == S_OK, "failed to create storage\n");
2650     if (!stg)
2651         return;
2652
2653     r = IStorage_SetClass( stg, &CLSID_MsiTransform );
2654     ok(r == S_OK, "failed to set storage type\n");
2655
2656     for (i=0; i<NUM_TRANSFORM_TABLES; i++)
2657     {
2658         r = IStorage_CreateStream( stg, table_transform_data[i].name,
2659                             STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stm );
2660         if (FAILED(r))
2661         {
2662             ok(0, "failed to create stream %08x\n", r);
2663             continue;
2664         }
2665
2666         r = IStream_Write( stm, table_transform_data[i].data,
2667                           table_transform_data[i].size, &count );
2668         if (FAILED(r) || count != table_transform_data[i].size)
2669             ok(0, "failed to write stream\n");
2670         IStream_Release(stm);
2671     }
2672
2673     IStorage_Release(stg);
2674 }
2675
2676 static UINT set_summary_info(MSIHANDLE hdb)
2677 {
2678     UINT res;
2679     MSIHANDLE suminfo;
2680
2681     /* build summary info */
2682     res = MsiGetSummaryInformation(hdb, NULL, 7, &suminfo);
2683     ok( res == ERROR_SUCCESS , "Failed to open summaryinfo\n" );
2684
2685     res = MsiSummaryInfoSetProperty(suminfo,2, VT_LPSTR, 0,NULL,
2686                         "Installation Database");
2687     ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
2688
2689     res = MsiSummaryInfoSetProperty(suminfo,3, VT_LPSTR, 0,NULL,
2690                         "Installation Database");
2691     ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
2692
2693     res = MsiSummaryInfoSetProperty(suminfo,4, VT_LPSTR, 0,NULL,
2694                         "Wine Hackers");
2695     ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
2696
2697     res = MsiSummaryInfoSetProperty(suminfo,7, VT_LPSTR, 0,NULL,
2698                     ";1033");
2699     ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
2700
2701     res = MsiSummaryInfoSetProperty(suminfo,9, VT_LPSTR, 0,NULL,
2702                     "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}");
2703     ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
2704
2705     res = MsiSummaryInfoSetProperty(suminfo, 14, VT_I4, 100, NULL, NULL);
2706     ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
2707
2708     res = MsiSummaryInfoSetProperty(suminfo, 15, VT_I4, 0, NULL, NULL);
2709     ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
2710
2711     res = MsiSummaryInfoPersist(suminfo);
2712     ok( res == ERROR_SUCCESS , "Failed to make summary info persist\n" );
2713
2714     res = MsiCloseHandle( suminfo);
2715     ok( res == ERROR_SUCCESS , "Failed to close suminfo\n" );
2716
2717     return res;
2718 }
2719
2720 static MSIHANDLE create_package_db(LPCSTR filename)
2721 {
2722     MSIHANDLE hdb = 0;
2723     UINT res;
2724
2725     DeleteFile(msifile);
2726
2727     /* create an empty database */
2728     res = MsiOpenDatabase(filename, MSIDBOPEN_CREATE, &hdb );
2729     ok( res == ERROR_SUCCESS , "Failed to create database\n" );
2730     if( res != ERROR_SUCCESS )
2731         return hdb;
2732
2733     res = MsiDatabaseCommit( hdb );
2734     ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
2735
2736     res = set_summary_info(hdb);
2737
2738     res = create_directory_table(hdb);
2739     ok( res == ERROR_SUCCESS , "Failed to create directory table\n" );
2740
2741     return hdb;
2742 }
2743
2744 static MSIHANDLE package_from_db(MSIHANDLE hdb)
2745 {
2746     UINT res;
2747     CHAR szPackage[10];
2748     MSIHANDLE hPackage;
2749
2750     sprintf(szPackage,"#%i",hdb);
2751     res = MsiOpenPackage(szPackage,&hPackage);
2752     if (res != ERROR_SUCCESS)
2753         return 0;
2754
2755     res = MsiCloseHandle(hdb);
2756     if (res != ERROR_SUCCESS)
2757         return 0;
2758
2759     return hPackage;
2760 }
2761
2762 static void test_try_transform(void)
2763 {
2764     MSIHANDLE hdb, hview, hrec, hpkg;
2765     LPCSTR query;
2766     UINT r;
2767     DWORD sz;
2768     char buffer[MAX_PATH];
2769
2770     DeleteFile(msifile);
2771     DeleteFile(mstfile);
2772
2773     /* create the database */
2774     hdb = create_package_db(msifile);
2775     ok(hdb, "Failed to create package db\n");
2776
2777     query = "CREATE TABLE `MOO` ( `NOO` SHORT NOT NULL, `OOO` CHAR(255) PRIMARY KEY `NOO`)";
2778     r = run_query(hdb, 0, query);
2779     ok(r == ERROR_SUCCESS, "failed to add table\n");
2780
2781     query = "INSERT INTO `MOO` ( `NOO`, `OOO` ) VALUES ( 1, 'a' )";
2782     r = run_query(hdb, 0, query);
2783     ok(r == ERROR_SUCCESS, "failed to add row\n");
2784
2785     query = "INSERT INTO `MOO` ( `NOO`, `OOO` ) VALUES ( 2, 'b' )";
2786     r = run_query(hdb, 0, query);
2787     ok(r == ERROR_SUCCESS, "failed to add row\n");
2788
2789     query = "INSERT INTO `MOO` ( `NOO`, `OOO` ) VALUES ( 3, 'c' )";
2790     r = run_query(hdb, 0, query);
2791     ok(r == ERROR_SUCCESS, "failed to add row\n");
2792
2793     query = "CREATE TABLE `BINARY` ( `ID` SHORT NOT NULL, `BLOB` OBJECT PRIMARY KEY `ID`)";
2794     r = run_query(hdb, 0, query);
2795     ok(r == ERROR_SUCCESS, "failed to add table\n");
2796
2797     hrec = MsiCreateRecord(2);
2798     r = MsiRecordSetInteger(hrec, 1, 2);
2799     ok(r == ERROR_SUCCESS, "failed to set integer\n");
2800
2801     write_file("testdata.bin", "lamyon", 6);
2802     r = MsiRecordSetStream(hrec, 2, "testdata.bin");
2803     ok(r == ERROR_SUCCESS, "failed to set stream\n");
2804
2805     query = "INSERT INTO `BINARY` ( `ID`, `BLOB` ) VALUES ( ?, ? )";
2806     r = run_query(hdb, hrec, query);
2807     ok(r == ERROR_SUCCESS, "failed to add row with blob\n");
2808
2809     MsiCloseHandle(hrec);
2810
2811     r = MsiDatabaseCommit( hdb );
2812     ok( r == ERROR_SUCCESS , "Failed to commit database\n" );
2813
2814     MsiCloseHandle( hdb );
2815     DeleteFileA("testdata.bin");
2816
2817     /*
2818      * Both these generate an equivalent transform,
2819      *  but the first doesn't work in Wine yet
2820      *  because MsiDatabaseGenerateTransform is unimplemented.
2821      */
2822     if (0)
2823         generate_transform();
2824     else
2825         generate_transform_manual();
2826
2827     r = MsiOpenDatabase(msifile, MSIDBOPEN_DIRECT, &hdb );
2828     ok( r == ERROR_SUCCESS , "Failed to create database\n" );
2829
2830     r = MsiDatabaseApplyTransform( hdb, mstfile, 0 );
2831     ok( r == ERROR_SUCCESS, "return code %d, should be ERROR_SUCCESS\n", r );
2832
2833     MsiDatabaseCommit( hdb );
2834
2835     /* check new values */
2836     hrec = 0;
2837     query = "select `BAR`,`CAR` from `AAR` where `BAR` = 1 AND `CAR` = 'vw'";
2838     r = do_query(hdb, query, &hrec);
2839     ok(r == ERROR_SUCCESS, "select query failed\n");
2840     MsiCloseHandle(hrec);
2841
2842     query = "select `BAR`,`CAR` from `AAR` where `BAR` = 2 AND `CAR` = 'bmw'";
2843     hrec = 0;
2844     r = do_query(hdb, query, &hrec);
2845     ok(r == ERROR_SUCCESS, "select query failed\n");
2846     MsiCloseHandle(hrec);
2847
2848     /* check updated values */
2849     hrec = 0;
2850     query = "select `NOO`,`OOO` from `MOO` where `NOO` = 1 AND `OOO` = 'c'";
2851     r = do_query(hdb, query, &hrec);
2852     ok(r == ERROR_SUCCESS, "select query failed\n");
2853     MsiCloseHandle(hrec);
2854
2855     /* check unchanged value */
2856     hrec = 0;
2857     query = "select `NOO`,`OOO` from `MOO` where `NOO` = 2 AND `OOO` = 'b'";
2858     r = do_query(hdb, query, &hrec);
2859     ok(r == ERROR_SUCCESS, "select query failed\n");
2860     MsiCloseHandle(hrec);
2861
2862     /* check deleted value */
2863     hrec = 0;
2864     query = "select * from `MOO` where `NOO` = 3";
2865     r = do_query(hdb, query, &hrec);
2866     ok(r == ERROR_NO_MORE_ITEMS, "select query failed\n");
2867     if (hrec) MsiCloseHandle(hrec);
2868
2869     /* check added stream */
2870     hrec = 0;
2871     query = "select `BLOB` from `BINARY` where `ID` = 1";
2872     r = do_query(hdb, query, &hrec);
2873     ok(r == ERROR_SUCCESS, "select query failed\n");
2874
2875     /* check the contents of the stream */
2876     sz = sizeof buffer;
2877     r = MsiRecordReadStream( hrec, 1, buffer, &sz );
2878     ok(r == ERROR_SUCCESS, "read stream failed\n");
2879     ok(!memcmp(buffer, "naengmyon", 9), "stream data was wrong\n");
2880     ok(sz == 9, "stream data was wrong size\n");
2881     if (hrec) MsiCloseHandle(hrec);
2882
2883     /* check the validity of the table with a deleted row */
2884     hrec = 0;
2885     query = "select * from `MOO`";
2886     r = MsiDatabaseOpenView(hdb, query, &hview);
2887     ok(r == ERROR_SUCCESS, "open view failed\n");
2888
2889     r = MsiViewExecute(hview, 0);
2890     ok(r == ERROR_SUCCESS, "view execute failed\n");
2891
2892     r = MsiViewFetch(hview, &hrec);
2893     ok(r == ERROR_SUCCESS, "view fetch failed\n");
2894
2895     r = MsiRecordGetInteger(hrec, 1);
2896     ok(r == 1, "Expected 1, got %d\n", r);
2897
2898     sz = sizeof buffer;
2899     r = MsiRecordGetString(hrec, 2, buffer, &sz);
2900     ok(r == ERROR_SUCCESS, "record get string failed\n");
2901     ok(!lstrcmpA(buffer, "c"), "Expected c, got %s\n", buffer);
2902
2903     r = MsiRecordGetInteger(hrec, 3);
2904     ok(r == 0x80000000, "Expected 0x80000000, got %d\n", r);
2905
2906     r = MsiRecordGetInteger(hrec, 4);
2907     ok(r == 5, "Expected 5, got %d\n", r);
2908
2909     MsiCloseHandle(hrec);
2910
2911     r = MsiViewFetch(hview, &hrec);
2912     ok(r == ERROR_SUCCESS, "view fetch failed\n");
2913
2914     r = MsiRecordGetInteger(hrec, 1);
2915     ok(r == 2, "Expected 2, got %d\n", r);
2916
2917     sz = sizeof buffer;
2918     r = MsiRecordGetString(hrec, 2, buffer, &sz);
2919     ok(r == ERROR_SUCCESS, "record get string failed\n");
2920     ok(!lstrcmpA(buffer, "b"), "Expected b, got %s\n", buffer);
2921
2922     r = MsiRecordGetInteger(hrec, 3);
2923     ok(r == 0x80000000, "Expected 0x80000000, got %d\n", r);
2924
2925     r = MsiRecordGetInteger(hrec, 4);
2926     ok(r == 0x80000000, "Expected 0x80000000, got %d\n", r);
2927
2928     MsiCloseHandle(hrec);
2929
2930     r = MsiViewFetch(hview, &hrec);
2931     ok(r == ERROR_NO_MORE_ITEMS, "view fetch succeeded\n");
2932
2933     MsiCloseHandle(hrec);
2934     MsiViewClose(hview);
2935     MsiCloseHandle(hview);
2936
2937     /* check that the property was added */
2938     hpkg = package_from_db(hdb);
2939     ok(hpkg != 0, "Expected non-NULL hpkg\n");
2940
2941     sz = MAX_PATH;
2942     r = MsiGetProperty(hpkg, "prop", buffer, &sz);
2943     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2944     ok(!lstrcmp(buffer, "val"), "Expected val, got %s\n", buffer);
2945
2946     MsiCloseHandle(hpkg);
2947     MsiCloseHandle(hdb);
2948
2949     DeleteFile(msifile);
2950     DeleteFile(mstfile);
2951 }
2952
2953 struct join_res
2954 {
2955     const CHAR one[MAX_PATH];
2956     const CHAR two[MAX_PATH];
2957 };
2958
2959 struct join_res_4col
2960 {
2961     const CHAR one[MAX_PATH];
2962     const CHAR two[MAX_PATH];
2963     const CHAR three[MAX_PATH];
2964     const CHAR four[MAX_PATH];
2965 };
2966
2967 struct join_res_uint
2968 {
2969     UINT one;
2970     UINT two;
2971     UINT three;
2972     UINT four;
2973     UINT five;
2974     UINT six;
2975 };
2976
2977 static const struct join_res join_res_first[] =
2978 {
2979     { "alveolar", "procerus" },
2980     { "septum", "procerus" },
2981     { "septum", "nasalis" },
2982     { "ramus", "nasalis" },
2983     { "malar", "mentalis" },
2984 };
2985
2986 static const struct join_res join_res_second[] =
2987 {
2988     { "nasal", "septum" },
2989     { "mandible", "ramus" },
2990 };
2991
2992 static const struct join_res join_res_third[] =
2993 {
2994     { "msvcp.dll", "abcdefgh" },
2995     { "msvcr.dll", "ijklmnop" },
2996 };
2997
2998 static const struct join_res join_res_fourth[] =
2999 {
3000     { "msvcp.dll.01234", "single.dll.31415" },
3001 };
3002
3003 static const struct join_res join_res_fifth[] =
3004 {
3005     { "malar", "procerus" },
3006 };
3007
3008 static const struct join_res join_res_sixth[] =
3009 {
3010     { "malar", "procerus" },
3011     { "malar", "procerus" },
3012     { "malar", "nasalis" },
3013     { "malar", "nasalis" },
3014     { "malar", "nasalis" },
3015     { "malar", "mentalis" },
3016 };
3017
3018 static const struct join_res join_res_seventh[] =
3019 {
3020     { "malar", "nasalis" },
3021     { "malar", "nasalis" },
3022     { "malar", "nasalis" },
3023 };
3024
3025 static const struct join_res_4col join_res_eighth[] =
3026 {
3027     { "msvcp.dll", "msvcp.dll.01234", "msvcp.dll.01234", "abcdefgh" },
3028     { "msvcr.dll", "msvcr.dll.56789", "msvcp.dll.01234", "abcdefgh" },
3029     { "msvcp.dll", "msvcp.dll.01234", "msvcr.dll.56789", "ijklmnop" },
3030     { "msvcr.dll", "msvcr.dll.56789", "msvcr.dll.56789", "ijklmnop" },
3031     { "msvcp.dll", "msvcp.dll.01234", "single.dll.31415", "msvcp.dll" },
3032     { "msvcr.dll", "msvcr.dll.56789", "single.dll.31415", "msvcp.dll" },
3033 };
3034
3035 static const struct join_res_uint join_res_ninth[] =
3036 {
3037     { 1, 2, 3, 4, 7, 8 },
3038     { 1, 2, 5, 6, 7, 8 },
3039     { 1, 2, 3, 4, 9, 10 },
3040     { 1, 2, 5, 6, 9, 10 },
3041     { 1, 2, 3, 4, 11, 12 },
3042     { 1, 2, 5, 6, 11, 12 },
3043 };
3044
3045 static void test_join(void)
3046 {
3047     MSIHANDLE hdb, hview, hrec;
3048     LPCSTR query;
3049     CHAR buf[MAX_PATH];
3050     UINT r, count;
3051     DWORD size, i;
3052     BOOL data_correct;
3053
3054     hdb = create_db();
3055     ok( hdb, "failed to create db\n");
3056
3057     r = create_component_table( hdb );
3058     ok( r == ERROR_SUCCESS, "cannot create Component table: %d\n", r );
3059
3060     r = add_component_entry( hdb, "'zygomatic', 'malar', 'INSTALLDIR', 0, '', ''" );
3061     ok( r == ERROR_SUCCESS, "cannot add component: %d\n", r );
3062
3063     r = add_component_entry( hdb, "'maxilla', 'alveolar', 'INSTALLDIR', 0, '', ''" );
3064     ok( r == ERROR_SUCCESS, "cannot add component: %d\n", r );
3065
3066     r = add_component_entry( hdb, "'nasal', 'septum', 'INSTALLDIR', 0, '', ''" );
3067     ok( r == ERROR_SUCCESS, "cannot add component: %d\n", r );
3068
3069     r = add_component_entry( hdb, "'mandible', 'ramus', 'INSTALLDIR', 0, '', ''" );
3070     ok( r == ERROR_SUCCESS, "cannot add component: %d\n", r );
3071
3072     r = create_feature_components_table( hdb );
3073     ok( r == ERROR_SUCCESS, "cannot create FeatureComponents table: %d\n", r );
3074
3075     r = add_feature_components_entry( hdb, "'procerus', 'maxilla'" );
3076     ok( r == ERROR_SUCCESS, "cannot add feature components: %d\n", r );
3077
3078     r = add_feature_components_entry( hdb, "'procerus', 'nasal'" );
3079     ok( r == ERROR_SUCCESS, "cannot add feature components: %d\n", r );
3080
3081     r = add_feature_components_entry( hdb, "'nasalis', 'nasal'" );
3082     ok( r == ERROR_SUCCESS, "cannot add feature components: %d\n", r );
3083
3084     r = add_feature_components_entry( hdb, "'nasalis', 'mandible'" );
3085     ok( r == ERROR_SUCCESS, "cannot add feature components: %d\n", r );
3086
3087     r = add_feature_components_entry( hdb, "'nasalis', 'notacomponent'" );
3088     ok( r == ERROR_SUCCESS, "cannot add feature components: %d\n", r );
3089
3090     r = add_feature_components_entry( hdb, "'mentalis', 'zygomatic'" );
3091     ok( r == ERROR_SUCCESS, "cannot add feature components: %d\n", r );
3092
3093     r = create_std_dlls_table( hdb );
3094     ok( r == ERROR_SUCCESS, "cannot create StdDlls table: %d\n", r );
3095
3096     r = add_std_dlls_entry( hdb, "'msvcp.dll', 'msvcp.dll.01234'" );
3097     ok( r == ERROR_SUCCESS, "cannot add std dlls: %d\n", r );
3098
3099     r = add_std_dlls_entry( hdb, "'msvcr.dll', 'msvcr.dll.56789'" );
3100     ok( r == ERROR_SUCCESS, "cannot add std dlls: %d\n", r );
3101
3102     r = create_binary_table( hdb );
3103     ok( r == ERROR_SUCCESS, "cannot create Binary table: %d\n", r );
3104
3105     r = add_binary_entry( hdb, "'msvcp.dll.01234', 'abcdefgh'" );
3106     ok( r == ERROR_SUCCESS, "cannot add binary: %d\n", r );
3107
3108     r = add_binary_entry( hdb, "'msvcr.dll.56789', 'ijklmnop'" );
3109     ok( r == ERROR_SUCCESS, "cannot add binary: %d\n", r );
3110
3111     r = add_binary_entry( hdb, "'single.dll.31415', 'msvcp.dll'" );
3112     ok( r == ERROR_SUCCESS, "cannot add binary: %d\n", r );
3113
3114     query = "CREATE TABLE `One` (`A` SHORT, `B` SHORT PRIMARY KEY `A`)";
3115     r = run_query( hdb, 0, query);
3116     ok(r == ERROR_SUCCESS, "cannot create table: %d\n", r );
3117
3118     query = "CREATE TABLE `Two` (`C` SHORT, `D` SHORT PRIMARY KEY `C`)";
3119     r = run_query( hdb, 0, query);
3120     ok(r == ERROR_SUCCESS, "cannot create table: %d\n", r );
3121
3122     query = "CREATE TABLE `Three` (`E` SHORT, `F` SHORT PRIMARY KEY `E`)";
3123     r = run_query( hdb, 0, query);
3124     ok(r == ERROR_SUCCESS, "cannot create table: %d\n", r );
3125
3126     query = "INSERT INTO `One` (`A`, `B`) VALUES (1, 2)";
3127     r = run_query( hdb, 0, query);
3128     ok(r == ERROR_SUCCESS, "cannot insert into table: %d\n", r );
3129
3130     query = "INSERT INTO `Two` (`C`, `D`) VALUES (3, 4)";
3131     r = run_query( hdb, 0, query);
3132     ok(r == ERROR_SUCCESS, "cannot insert into table: %d\n", r );
3133
3134     query = "INSERT INTO `Two` (`C`, `D`) VALUES (5, 6)";
3135     r = run_query( hdb, 0, query);
3136     ok(r == ERROR_SUCCESS, "cannot insert into table: %d\n", r );
3137
3138     query = "INSERT INTO `Three` (`E`, `F`) VALUES (7, 8)";
3139     r = run_query( hdb, 0, query);
3140     ok(r == ERROR_SUCCESS, "cannot insert into table: %d\n", r );
3141
3142     query = "INSERT INTO `Three` (`E`, `F`) VALUES (9, 10)";
3143     r = run_query( hdb, 0, query);
3144     ok(r == ERROR_SUCCESS, "cannot insert into table: %d\n", r );
3145
3146     query = "INSERT INTO `Three` (`E`, `F`) VALUES (11, 12)";
3147     r = run_query( hdb, 0, query);
3148     ok(r == ERROR_SUCCESS, "cannot insert into table: %d\n", r );
3149
3150     query = "CREATE TABLE `Four` (`G` SHORT, `H` SHORT PRIMARY KEY `G`)";
3151     r = run_query( hdb, 0, query);
3152     ok(r == ERROR_SUCCESS, "cannot create table: %d\n", r );
3153
3154     query = "CREATE TABLE `Five` (`I` SHORT, `J` SHORT PRIMARY KEY `I`)";
3155     r = run_query( hdb, 0, query);
3156     ok(r == ERROR_SUCCESS, "cannot create table: %d\n", r );
3157
3158     query = "INSERT INTO `Five` (`I`, `J`) VALUES (13, 14)";
3159     r = run_query( hdb, 0, query);
3160     ok(r == ERROR_SUCCESS, "cannot insert into table: %d\n", r );
3161
3162     query = "INSERT INTO `Five` (`I`, `J`) VALUES (15, 16)";
3163     r = run_query( hdb, 0, query);
3164     ok(r == ERROR_SUCCESS, "cannot insert into table: %d\n", r );
3165
3166     query = "SELECT `Component`.`ComponentId`, `FeatureComponents`.`Feature_` "
3167             "FROM `Component`, `FeatureComponents` "
3168             "WHERE `Component`.`Component` = `FeatureComponents`.`Component_` "
3169             "ORDER BY `Feature_`";
3170     r = MsiDatabaseOpenView(hdb, query, &hview);
3171     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3172
3173     r = MsiViewExecute(hview, 0);
3174     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3175
3176     i = 0;
3177     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3178     {
3179         count = MsiRecordGetFieldCount( hrec );
3180         ok( count == 2, "Expected 2 record fields, got %d\n", count );
3181
3182         size = MAX_PATH;
3183         r = MsiRecordGetString( hrec, 1, buf, &size );
3184         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3185         ok( !lstrcmp( buf, join_res_first[i].one ),
3186             "For (row %d, column 1) expected '%s', got %s\n", i, join_res_first[i].one, buf );
3187
3188         size = MAX_PATH;
3189         r = MsiRecordGetString( hrec, 2, buf, &size );
3190         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3191         ok( !lstrcmp( buf, join_res_first[i].two ),
3192             "For (row %d, column 2) expected '%s', got %s\n", i, join_res_first[i].two, buf );
3193
3194         i++;
3195         MsiCloseHandle(hrec);
3196     }
3197
3198     ok( i == 5, "Expected 5 rows, got %d\n", i );
3199     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3200
3201     MsiViewClose(hview);
3202     MsiCloseHandle(hview);
3203
3204     /* try a join without a WHERE condition */
3205     query = "SELECT `Component`.`ComponentId`, `FeatureComponents`.`Feature_` "
3206             "FROM `Component`, `FeatureComponents` ";
3207     r = MsiDatabaseOpenView(hdb, query, &hview);
3208     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3209
3210     r = MsiViewExecute(hview, 0);
3211     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3212
3213     i = 0;
3214     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3215     {
3216         i++;
3217         MsiCloseHandle(hrec);
3218     }
3219     ok( i == 24, "Expected 24 rows, got %d\n", i );
3220
3221     MsiViewClose(hview);
3222     MsiCloseHandle(hview);
3223
3224     query = "SELECT DISTINCT Component, ComponentId FROM FeatureComponents, Component "
3225             "WHERE FeatureComponents.Component_=Component.Component "
3226             "AND (Feature_='nasalis') ORDER BY Feature_";
3227     r = MsiDatabaseOpenView(hdb, query, &hview);
3228     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3229
3230     r = MsiViewExecute(hview, 0);
3231     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3232
3233     i = 0;
3234     data_correct = TRUE;
3235     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3236     {
3237         count = MsiRecordGetFieldCount( hrec );
3238         ok( count == 2, "Expected 2 record fields, got %d\n", count );
3239
3240         size = MAX_PATH;
3241         r = MsiRecordGetString( hrec, 1, buf, &size );
3242         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3243         if( lstrcmp( buf, join_res_second[i].one ))
3244             data_correct = FALSE;
3245
3246         size = MAX_PATH;
3247         r = MsiRecordGetString( hrec, 2, buf, &size );
3248         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3249         if( lstrcmp( buf, join_res_second[i].two ))
3250             data_correct = FALSE;
3251
3252         i++;
3253         MsiCloseHandle(hrec);
3254     }
3255
3256     ok( data_correct, "data returned in the wrong order\n");
3257
3258     ok( i == 2, "Expected 2 rows, got %d\n", i );
3259     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3260
3261     MsiViewClose(hview);
3262     MsiCloseHandle(hview);
3263
3264     query = "SELECT `StdDlls`.`File`, `Binary`.`Data` "
3265             "FROM `StdDlls`, `Binary` "
3266             "WHERE `StdDlls`.`Binary_` = `Binary`.`Name` "
3267             "ORDER BY `File`";
3268     r = MsiDatabaseOpenView(hdb, query, &hview);
3269     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3270
3271     r = MsiViewExecute(hview, 0);
3272     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3273
3274     i = 0;
3275     data_correct = TRUE;
3276     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3277     {
3278         count = MsiRecordGetFieldCount( hrec );
3279         ok( count == 2, "Expected 2 record fields, got %d\n", count );
3280
3281         size = MAX_PATH;
3282         r = MsiRecordGetString( hrec, 1, buf, &size );
3283         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3284         if( lstrcmp( buf, join_res_third[i].one ) )
3285             data_correct = FALSE;
3286
3287         size = MAX_PATH;
3288         r = MsiRecordGetString( hrec, 2, buf, &size );
3289         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3290         if( lstrcmp( buf, join_res_third[i].two ) )
3291             data_correct = FALSE;
3292
3293         i++;
3294         MsiCloseHandle(hrec);
3295     }
3296     ok( data_correct, "data returned in the wrong order\n");
3297
3298     ok( i == 2, "Expected 2 rows, got %d\n", i );
3299
3300     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3301
3302     MsiViewClose(hview);
3303     MsiCloseHandle(hview);
3304
3305     query = "SELECT `StdDlls`.`Binary_`, `Binary`.`Name` "
3306             "FROM `StdDlls`, `Binary` "
3307             "WHERE `StdDlls`.`File` = `Binary`.`Data` "
3308             "ORDER BY `Name`";
3309     r = MsiDatabaseOpenView(hdb, query, &hview);
3310     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3311
3312     r = MsiViewExecute(hview, 0);
3313     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3314
3315     i = 0;
3316     data_correct = TRUE;
3317     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3318     {
3319         count = MsiRecordGetFieldCount( hrec );
3320         ok( count == 2, "Expected 2 record fields, got %d\n", count );
3321
3322         size = MAX_PATH;
3323         r = MsiRecordGetString( hrec, 1, buf, &size );
3324         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3325         if( lstrcmp( buf, join_res_fourth[i].one ))
3326             data_correct = FALSE;
3327
3328         size = MAX_PATH;
3329         r = MsiRecordGetString( hrec, 2, buf, &size );
3330         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3331         if( lstrcmp( buf, join_res_fourth[i].two ))
3332             data_correct = FALSE;
3333
3334         i++;
3335         MsiCloseHandle(hrec);
3336     }
3337     ok( data_correct, "data returned in the wrong order\n");
3338
3339     ok( i == 1, "Expected 1 rows, got %d\n", i );
3340     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3341
3342     MsiViewClose(hview);
3343     MsiCloseHandle(hview);
3344
3345     query = "SELECT `Component`.`ComponentId`, `FeatureComponents`.`Feature_` "
3346             "FROM `Component`, `FeatureComponents` "
3347             "WHERE `Component`.`Component` = 'zygomatic' "
3348             "AND `FeatureComponents`.`Component_` = 'maxilla' "
3349             "ORDER BY `Feature_`";
3350     r = MsiDatabaseOpenView(hdb, query, &hview);
3351     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3352
3353     r = MsiViewExecute(hview, 0);
3354     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3355
3356     i = 0;
3357     data_correct = TRUE;
3358     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3359     {
3360         count = MsiRecordGetFieldCount( hrec );
3361         ok( count == 2, "Expected 2 record fields, got %d\n", count );
3362
3363         size = MAX_PATH;
3364         r = MsiRecordGetString( hrec, 1, buf, &size );
3365         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3366         if( lstrcmp( buf, join_res_fifth[i].one ))
3367             data_correct = FALSE;
3368
3369         size = MAX_PATH;
3370         r = MsiRecordGetString( hrec, 2, buf, &size );
3371         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3372         if( lstrcmp( buf, join_res_fifth[i].two ))
3373             data_correct = FALSE;
3374
3375         i++;
3376         MsiCloseHandle(hrec);
3377     }
3378     ok( data_correct, "data returned in the wrong order\n");
3379
3380     ok( i == 1, "Expected 1 rows, got %d\n", i );
3381     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3382
3383     MsiViewClose(hview);
3384     MsiCloseHandle(hview);
3385
3386     query = "SELECT `Component`.`ComponentId`, `FeatureComponents`.`Feature_` "
3387             "FROM `Component`, `FeatureComponents` "
3388             "WHERE `Component` = 'zygomatic' "
3389             "ORDER BY `Feature_`";
3390     r = MsiDatabaseOpenView(hdb, query, &hview);
3391     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3392
3393     r = MsiViewExecute(hview, 0);
3394     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3395
3396     i = 0;
3397     data_correct = TRUE;
3398     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3399     {
3400         count = MsiRecordGetFieldCount( hrec );
3401         ok( count == 2, "Expected 2 record fields, got %d\n", count );
3402
3403         size = MAX_PATH;
3404         r = MsiRecordGetString( hrec, 1, buf, &size );
3405         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3406         if( lstrcmp( buf, join_res_sixth[i].one ))
3407             data_correct = FALSE;
3408
3409         size = MAX_PATH;
3410         r = MsiRecordGetString( hrec, 2, buf, &size );
3411         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3412         if( lstrcmp( buf, join_res_sixth[i].two ))
3413             data_correct = FALSE;
3414
3415         i++;
3416         MsiCloseHandle(hrec);
3417     }
3418     ok( data_correct, "data returned in the wrong order\n");
3419
3420     ok( i == 6, "Expected 6 rows, got %d\n", i );
3421     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3422
3423     MsiViewClose(hview);
3424     MsiCloseHandle(hview);
3425
3426     query = "SELECT `Component`.`ComponentId`, `FeatureComponents`.`Feature_` "
3427             "FROM `Component`, `FeatureComponents` "
3428             "WHERE `Component` = 'zygomatic' "
3429             "AND `Feature_` = 'nasalis' "
3430             "ORDER BY `Feature_`";
3431     r = MsiDatabaseOpenView(hdb, query, &hview);
3432     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3433
3434     r = MsiViewExecute(hview, 0);
3435     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3436
3437     i = 0;
3438     data_correct = TRUE;
3439     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3440     {
3441         count = MsiRecordGetFieldCount( hrec );
3442         ok( count == 2, "Expected 2 record fields, got %d\n", count );
3443
3444         size = MAX_PATH;
3445         r = MsiRecordGetString( hrec, 1, buf, &size );
3446         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3447         if( lstrcmp( buf, join_res_seventh[i].one ))
3448             data_correct = FALSE;
3449
3450         size = MAX_PATH;
3451         r = MsiRecordGetString( hrec, 2, buf, &size );
3452         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3453         if( lstrcmp( buf, join_res_seventh[i].two ))
3454             data_correct = FALSE;
3455
3456         i++;
3457         MsiCloseHandle(hrec);
3458     }
3459
3460     ok( data_correct, "data returned in the wrong order\n");
3461     ok( i == 3, "Expected 3 rows, got %d\n", i );
3462     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3463
3464     MsiViewClose(hview);
3465     MsiCloseHandle(hview);
3466
3467     query = "SELECT `StdDlls`.`File`, `Binary`.`Data` "
3468             "FROM `StdDlls`, `Binary` ";
3469     r = MsiDatabaseOpenView(hdb, query, &hview);
3470     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3471
3472     r = MsiViewExecute(hview, 0);
3473     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3474
3475     i = 0;
3476     data_correct = TRUE;
3477     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3478     {
3479         count = MsiRecordGetFieldCount( hrec );
3480         ok( count == 2, "Expected 2 record fields, got %d\n", count );
3481
3482         size = MAX_PATH;
3483         r = MsiRecordGetString( hrec, 1, buf, &size );
3484         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3485         if( lstrcmp( buf, join_res_eighth[i].one ))
3486             data_correct = FALSE;
3487
3488         size = MAX_PATH;
3489         r = MsiRecordGetString( hrec, 2, buf, &size );
3490         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3491         if( lstrcmp( buf, join_res_eighth[i].four ))
3492             data_correct = FALSE;
3493
3494         i++;
3495         MsiCloseHandle(hrec);
3496     }
3497
3498     ok( data_correct, "data returned in the wrong order\n");
3499     ok( i == 6, "Expected 6 rows, got %d\n", i );
3500     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3501
3502     MsiViewClose(hview);
3503     MsiCloseHandle(hview);
3504
3505     query = "SELECT * FROM `StdDlls`, `Binary` ";
3506     r = MsiDatabaseOpenView(hdb, query, &hview);
3507     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3508
3509     r = MsiViewExecute(hview, 0);
3510     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3511
3512     i = 0;
3513     data_correct = TRUE;
3514     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3515     {
3516         count = MsiRecordGetFieldCount( hrec );
3517         ok( count == 4, "Expected 4 record fields, got %d\n", count );
3518
3519         size = MAX_PATH;
3520         r = MsiRecordGetString( hrec, 1, buf, &size );
3521         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3522         if( lstrcmp( buf, join_res_eighth[i].one ))
3523             data_correct = FALSE;
3524
3525         size = MAX_PATH;
3526         r = MsiRecordGetString( hrec, 2, buf, &size );
3527         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3528         if( lstrcmp( buf, join_res_eighth[i].two ))
3529             data_correct = FALSE;
3530
3531         size = MAX_PATH;
3532         r = MsiRecordGetString( hrec, 3, buf, &size );
3533         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3534         if( lstrcmp( buf, join_res_eighth[i].three ))
3535             data_correct = FALSE;
3536
3537         size = MAX_PATH;
3538         r = MsiRecordGetString( hrec, 4, buf, &size );
3539         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3540         if( lstrcmp( buf, join_res_eighth[i].four ))
3541             data_correct = FALSE;
3542
3543         i++;
3544         MsiCloseHandle(hrec);
3545     }
3546     ok( data_correct, "data returned in the wrong order\n");
3547
3548     ok( i == 6, "Expected 6 rows, got %d\n", i );
3549     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3550
3551     MsiViewClose(hview);
3552     MsiCloseHandle(hview);
3553
3554     query = "SELECT * FROM `One`, `Two`, `Three` ";
3555     r = MsiDatabaseOpenView(hdb, query, &hview);
3556     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3557
3558     r = MsiViewExecute(hview, 0);
3559     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3560
3561     i = 0;
3562     data_correct = TRUE;
3563     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3564     {
3565         count = MsiRecordGetFieldCount( hrec );
3566         ok( count == 6, "Expected 6 record fields, got %d\n", count );
3567
3568         r = MsiRecordGetInteger( hrec, 1 );
3569         if( r != join_res_ninth[i].one )
3570             data_correct = FALSE;
3571
3572         r = MsiRecordGetInteger( hrec, 2 );
3573         if( r != join_res_ninth[i].two )
3574             data_correct = FALSE;
3575
3576         r = MsiRecordGetInteger( hrec, 3 );
3577         if( r != join_res_ninth[i].three )
3578             data_correct = FALSE;
3579
3580         r = MsiRecordGetInteger( hrec, 4 );
3581         if( r != join_res_ninth[i].four )
3582             data_correct = FALSE;
3583
3584         r = MsiRecordGetInteger( hrec, 5 );
3585         if( r != join_res_ninth[i].five )
3586             data_correct = FALSE;
3587
3588         r = MsiRecordGetInteger( hrec, 6);
3589         if( r != join_res_ninth[i].six )
3590             data_correct = FALSE;
3591
3592         i++;
3593         MsiCloseHandle(hrec);
3594     }
3595     ok( data_correct, "data returned in the wrong order\n");
3596
3597     ok( i == 6, "Expected 6 rows, got %d\n", i );
3598     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3599
3600     MsiViewClose(hview);
3601     MsiCloseHandle(hview);
3602
3603     query = "SELECT * FROM `Four`, `Five`";
3604     r = MsiDatabaseOpenView(hdb, query, &hview);
3605     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3606
3607     r = MsiViewExecute(hview, 0);
3608     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3609
3610     r = MsiViewFetch(hview, &hrec);
3611     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
3612
3613     MsiViewClose(hview);
3614     MsiCloseHandle(hview);
3615
3616     query = "SELECT * FROM `Nonexistent`, `One`";
3617     r = MsiDatabaseOpenView(hdb, query, &hview);
3618     ok( r == ERROR_BAD_QUERY_SYNTAX,
3619         "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r );
3620
3621     MsiCloseHandle(hdb);
3622     DeleteFile(msifile);
3623 }
3624
3625 static void test_temporary_table(void)
3626 {
3627     MSICONDITION cond;
3628     MSIHANDLE hdb = 0, view = 0, rec;
3629     const char *query;
3630     UINT r;
3631     char buf[0x10];
3632     DWORD sz;
3633
3634     cond = MsiDatabaseIsTablePersistent(0, NULL);
3635     ok( cond == MSICONDITION_ERROR, "wrong return condition\n");
3636
3637     hdb = create_db();
3638     ok( hdb, "failed to create db\n");
3639
3640     cond = MsiDatabaseIsTablePersistent(hdb, NULL);
3641     ok( cond == MSICONDITION_ERROR, "wrong return condition\n");
3642
3643     cond = MsiDatabaseIsTablePersistent(hdb, "_Tables");
3644     ok( cond == MSICONDITION_NONE, "wrong return condition\n");
3645
3646     cond = MsiDatabaseIsTablePersistent(hdb, "_Columns");
3647     ok( cond == MSICONDITION_NONE, "wrong return condition\n");
3648
3649     cond = MsiDatabaseIsTablePersistent(hdb, "_Storages");
3650     ok( cond == MSICONDITION_NONE, "wrong return condition\n");
3651
3652     cond = MsiDatabaseIsTablePersistent(hdb, "_Streams");
3653     ok( cond == MSICONDITION_NONE, "wrong return condition\n");
3654
3655     query = "CREATE TABLE `P` ( `B` SHORT NOT NULL, `C` CHAR(255) PRIMARY KEY `C`)";
3656     r = run_query(hdb, 0, query);
3657     ok(r == ERROR_SUCCESS, "failed to add table\n");
3658
3659     cond = MsiDatabaseIsTablePersistent(hdb, "P");
3660     ok( cond == MSICONDITION_TRUE, "wrong return condition\n");
3661
3662     query = "CREATE TABLE `P2` ( `B` SHORT NOT NULL, `C` CHAR(255) 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, "P2");
3667     ok( cond == MSICONDITION_TRUE, "wrong return condition\n");
3668
3669     query = "CREATE TABLE `T` ( `B` SHORT NOT NULL TEMPORARY, `C` CHAR(255) TEMPORARY PRIMARY KEY `C`) HOLD";
3670     r = run_query(hdb, 0, query);
3671     ok(r == ERROR_SUCCESS, "failed to add table\n");
3672
3673     cond = MsiDatabaseIsTablePersistent(hdb, "T");
3674     ok( cond == MSICONDITION_FALSE, "wrong return condition\n");
3675
3676     query = "CREATE TABLE `T2` ( `B` SHORT NOT NULL TEMPORARY, `C` CHAR(255) TEMPORARY PRIMARY KEY `C`)";
3677     r = run_query(hdb, 0, query);
3678     ok(r == ERROR_SUCCESS, "failed to add table\n");
3679
3680     query = "SELECT * FROM `T2`";
3681     r = MsiDatabaseOpenView(hdb, query, &view);
3682     ok(r == ERROR_BAD_QUERY_SYNTAX,
3683        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
3684
3685     cond = MsiDatabaseIsTablePersistent(hdb, "T2");
3686     ok( cond == MSICONDITION_NONE, "wrong return condition\n");
3687
3688     query = "CREATE TABLE `T3` ( `B` SHORT NOT NULL TEMPORARY, `C` CHAR(255) PRIMARY KEY `C`)";
3689     r = run_query(hdb, 0, query);
3690     ok(r == ERROR_SUCCESS, "failed to add table\n");
3691
3692     cond = MsiDatabaseIsTablePersistent(hdb, "T3");
3693     ok( cond == MSICONDITION_TRUE, "wrong return condition\n");
3694
3695     query = "CREATE TABLE `T4` ( `B` SHORT NOT NULL, `C` CHAR(255) TEMPORARY PRIMARY KEY `C`)";
3696     r = run_query(hdb, 0, query);
3697     ok(r == ERROR_FUNCTION_FAILED, "failed to add table\n");
3698
3699     cond = MsiDatabaseIsTablePersistent(hdb, "T4");
3700     ok( cond == MSICONDITION_NONE, "wrong return condition\n");
3701
3702     query = "CREATE TABLE `T5` ( `B` SHORT NOT NULL TEMP, `C` CHAR(255) TEMP PRIMARY KEY `C`) HOLD";
3703     r = run_query(hdb, 0, query);
3704     ok(r == ERROR_BAD_QUERY_SYNTAX, "failed to add table\n");
3705
3706     query = "select * from `T`";
3707     r = MsiDatabaseOpenView(hdb, query, &view);
3708     ok(r == ERROR_SUCCESS, "failed to query table\n");
3709     r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
3710     ok(r == ERROR_SUCCESS, "failed to get column info\n");
3711
3712     sz = sizeof buf;
3713     r = MsiRecordGetString(rec, 1, buf, &sz);
3714     ok(r == ERROR_SUCCESS, "failed to get string\n");
3715     ok( 0 == strcmp("G255", buf), "wrong column type\n");
3716
3717     sz = sizeof buf;
3718     r = MsiRecordGetString(rec, 2, buf, &sz);
3719     ok(r == ERROR_SUCCESS, "failed to get string\n");
3720     ok( 0 == strcmp("j2", buf), "wrong column type\n");
3721
3722     MsiCloseHandle( rec );
3723     MsiViewClose( view );
3724     MsiCloseHandle( view );
3725
3726     /* query the table data */
3727     rec = 0;
3728     r = do_query(hdb, "select * from `_Tables` where `Name` = 'T'", &rec);
3729     ok( r == ERROR_SUCCESS, "temporary table exists in _Tables\n");
3730     MsiCloseHandle( rec );
3731
3732     /* query the column data */
3733     rec = 0;
3734     r = do_query(hdb, "select * from `_Columns` where `Table` = 'T' AND `Name` = 'B'", &rec);
3735     ok( r == ERROR_NO_MORE_ITEMS, "temporary table exists in _Columns\n");
3736     if (rec) MsiCloseHandle( rec );
3737
3738     r = do_query(hdb, "select * from `_Columns` where `Table` = 'T' AND `Name` = 'C'", &rec);
3739     ok( r == ERROR_NO_MORE_ITEMS, "temporary table exists in _Columns\n");
3740     if (rec) MsiCloseHandle( rec );
3741
3742     MsiCloseHandle( hdb );
3743
3744     DeleteFile(msifile);
3745 }
3746
3747 static void test_alter(void)
3748 {
3749     MSICONDITION cond;
3750     MSIHANDLE hdb = 0;
3751     const char *query;
3752     UINT r;
3753
3754     hdb = create_db();
3755     ok( hdb, "failed to create db\n");
3756
3757     query = "CREATE TABLE `T` ( `B` SHORT NOT NULL TEMPORARY, `C` CHAR(255) TEMPORARY PRIMARY KEY `C`) HOLD";
3758     r = run_query(hdb, 0, query);
3759     ok(r == ERROR_SUCCESS, "failed to add table\n");
3760
3761     cond = MsiDatabaseIsTablePersistent(hdb, "T");
3762     ok( cond == MSICONDITION_FALSE, "wrong return condition\n");
3763
3764     query = "ALTER TABLE `T` HOLD";
3765     r = run_query(hdb, 0, query);
3766     ok(r == ERROR_SUCCESS, "failed to hold table %d\n", r);
3767
3768     query = "ALTER TABLE `T` FREE";
3769     r = run_query(hdb, 0, query);
3770     ok(r == ERROR_SUCCESS, "failed to free table\n");
3771
3772     query = "ALTER TABLE `T` FREE";
3773     r = run_query(hdb, 0, query);
3774     ok(r == ERROR_SUCCESS, "failed to free table\n");
3775
3776     query = "ALTER TABLE `T` FREE";
3777     r = run_query(hdb, 0, query);
3778     ok(r == ERROR_BAD_QUERY_SYNTAX, "failed to free table\n");
3779
3780     query = "ALTER TABLE `T` HOLD";
3781     r = run_query(hdb, 0, query);
3782     ok(r == ERROR_BAD_QUERY_SYNTAX, "failed to hold table %d\n", r);
3783
3784     /* table T is removed */
3785     query = "SELECT * FROM `T`";
3786     r = run_query(hdb, 0, query);
3787     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
3788
3789     /* create the table again */
3790     query = "CREATE TABLE `U` ( `A` INTEGER, `B` INTEGER PRIMARY KEY `B`)";
3791     r = run_query(hdb, 0, query);
3792     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3793
3794     /* up the ref count */
3795     query = "ALTER TABLE `U` HOLD";
3796     r = run_query(hdb, 0, query);
3797     ok(r == ERROR_SUCCESS, "failed to free table\n");
3798
3799     /* add column, no data type */
3800     query = "ALTER TABLE `U` ADD `C`";
3801     r = run_query(hdb, 0, query);
3802     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
3803
3804     query = "ALTER TABLE `U` ADD `C` INTEGER";
3805     r = run_query(hdb, 0, query);
3806     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3807
3808     /* add column C again */
3809     query = "ALTER TABLE `U` ADD `C` INTEGER";
3810     r = run_query(hdb, 0, query);
3811     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
3812
3813     query = "ALTER TABLE `U` ADD `D` INTEGER TEMPORARY";
3814     r = run_query(hdb, 0, query);
3815     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3816
3817     query = "INSERT INTO `U` ( `A`, `B`, `C`, `D` ) VALUES ( 1, 2, 3, 4 )";
3818     r = run_query(hdb, 0, query);
3819     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3820
3821     query = "ALTER TABLE `U` ADD `D` INTEGER TEMPORARY HOLD";
3822     r = run_query(hdb, 0, query);
3823     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
3824
3825     query = "INSERT INTO `U` ( `A`, `B`, `C`, `D` ) VALUES ( 5, 6, 7, 8 )";
3826     r = run_query(hdb, 0, query);
3827     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3828
3829     query = "SELECT * FROM `U` WHERE `D` = 8";
3830     r = run_query(hdb, 0, query);
3831     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3832
3833     query = "ALTER TABLE `U` ADD `D` INTEGER TEMPORARY FREE";
3834     r = run_query(hdb, 0, query);
3835     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
3836
3837     query = "ALTER COLUMN `D` FREE";
3838     r = run_query(hdb, 0, query);
3839     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
3840
3841     /* drop the ref count */
3842     query = "ALTER TABLE `U` FREE";
3843     r = run_query(hdb, 0, query);
3844     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3845
3846     /* table is not empty */
3847     query = "SELECT * FROM `U`";
3848     r = run_query(hdb, 0, query);
3849     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3850
3851     /* column D is removed */
3852     query = "SELECT * FROM `U` WHERE `D` = 8";
3853     r = run_query(hdb, 0, query);
3854     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
3855
3856     query = "INSERT INTO `U` ( `A`, `B`, `C`, `D` ) VALUES ( 9, 10, 11, 12 )";
3857     r = run_query(hdb, 0, query);
3858     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
3859
3860     /* add the column again */
3861     query = "ALTER TABLE `U` ADD `E` INTEGER TEMPORARY HOLD";
3862     r = run_query(hdb, 0, query);
3863     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3864
3865     /* up the ref count */
3866     query = "ALTER TABLE `U` HOLD";
3867     r = run_query(hdb, 0, query);
3868     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3869
3870     query = "INSERT INTO `U` ( `A`, `B`, `C`, `E` ) VALUES ( 13, 14, 15, 16 )";
3871     r = run_query(hdb, 0, query);
3872     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3873
3874     query = "SELECT * FROM `U` WHERE `E` = 16";
3875     r = run_query(hdb, 0, query);
3876     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3877
3878     /* drop the ref count */
3879     query = "ALTER TABLE `U` FREE";
3880     r = run_query(hdb, 0, query);
3881     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3882
3883     query = "INSERT INTO `U` ( `A`, `B`, `C`, `E` ) VALUES ( 17, 18, 19, 20 )";
3884     r = run_query(hdb, 0, query);
3885     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3886
3887     query = "SELECT * FROM `U` WHERE `E` = 20";
3888     r = run_query(hdb, 0, query);
3889     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3890
3891     /* drop the ref count */
3892     query = "ALTER TABLE `U` FREE";
3893     r = run_query(hdb, 0, query);
3894     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3895
3896     /* table still exists */
3897     query = "SELECT * FROM `U`";
3898     r = run_query(hdb, 0, query);
3899     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3900
3901     /* col E is removed */
3902     query = "SELECT * FROM `U` WHERE `E` = 20";
3903     r = run_query(hdb, 0, query);
3904     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
3905
3906     query = "INSERT INTO `U` ( `A`, `B`, `C`, `E` ) VALUES ( 20, 21, 22, 23 )";
3907     r = run_query(hdb, 0, query);
3908     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
3909
3910     /* drop the ref count once more */
3911     query = "ALTER TABLE `U` FREE";
3912     r = run_query(hdb, 0, query);
3913     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3914
3915     /* table still exists */
3916     query = "SELECT * FROM `U`";
3917     r = run_query(hdb, 0, query);
3918     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3919
3920     MsiCloseHandle( hdb );
3921     DeleteFile(msifile);
3922 }
3923
3924 static void test_integers(void)
3925 {
3926     MSIHANDLE hdb = 0, view = 0, rec = 0;
3927     DWORD count, i;
3928     const char *query;
3929     UINT r;
3930
3931     /* just MsiOpenDatabase should not create a file */
3932     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
3933     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
3934
3935     /* create a table */
3936     query = "CREATE TABLE `integers` ( "
3937             "`one` SHORT, `two` INT, `three` INTEGER, `four` LONG, "
3938             "`five` SHORT NOT NULL, `six` INT NOT NULL, "
3939             "`seven` INTEGER NOT NULL, `eight` LONG NOT NULL "
3940             "PRIMARY KEY `one`)";
3941     r = MsiDatabaseOpenView(hdb, query, &view);
3942     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
3943     r = MsiViewExecute(view, 0);
3944     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
3945     r = MsiViewClose(view);
3946     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
3947     r = MsiCloseHandle(view);
3948     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
3949
3950     query = "SELECT * FROM `integers`";
3951     r = MsiDatabaseOpenView(hdb, query, &view);
3952     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3953
3954     r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec);
3955     count = MsiRecordGetFieldCount(rec);
3956     ok(count == 8, "Expected 8, got %d\n", count);
3957     ok(check_record(rec, 1, "one"), "Expected one\n");
3958     ok(check_record(rec, 2, "two"), "Expected two\n");
3959     ok(check_record(rec, 3, "three"), "Expected three\n");
3960     ok(check_record(rec, 4, "four"), "Expected four\n");
3961     ok(check_record(rec, 5, "five"), "Expected five\n");
3962     ok(check_record(rec, 6, "six"), "Expected six\n");
3963     ok(check_record(rec, 7, "seven"), "Expected seven\n");
3964     ok(check_record(rec, 8, "eight"), "Expected eight\n");
3965     MsiCloseHandle(rec);
3966
3967     r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
3968     count = MsiRecordGetFieldCount(rec);
3969     ok(count == 8, "Expected 8, got %d\n", count);
3970     ok(check_record(rec, 1, "I2"), "Expected I2\n");
3971     ok(check_record(rec, 2, "I2"), "Expected I2\n");
3972     ok(check_record(rec, 3, "I2"), "Expected I2\n");
3973     ok(check_record(rec, 4, "I4"), "Expected I4\n");
3974     ok(check_record(rec, 5, "i2"), "Expected i2\n");
3975     ok(check_record(rec, 6, "i2"), "Expected i2\n");
3976     ok(check_record(rec, 7, "i2"), "Expected i2\n");
3977     ok(check_record(rec, 8, "i4"), "Expected i4\n");
3978     MsiCloseHandle(rec);
3979
3980     MsiViewClose(view);
3981     MsiCloseHandle(view);
3982
3983     /* insert values into it, NULL where NOT NULL is specified */
3984     query = "INSERT INTO `integers` ( `one`, `two`, `three`, `four`, `five`, `six`, `seven`, `eight` )"
3985         "VALUES('', '', '', '', '', '', '', '')";
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_FUNCTION_FAILED, "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
3990
3991     MsiViewClose(view);
3992     MsiCloseHandle(view);
3993
3994     query = "SELECT * FROM `integers`";
3995     r = do_query(hdb, query, &rec);
3996     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
3997
3998     r = MsiRecordGetFieldCount(rec);
3999     ok(r == -1, "record count wrong: %d\n", r);
4000
4001     MsiCloseHandle(rec);
4002
4003     /* insert legitimate values into it */
4004     query = "INSERT INTO `integers` ( `one`, `two`, `three`, `four`, `five`, `six`, `seven`, `eight` )"
4005         "VALUES('', '2', '', '4', '5', '6', '7', '8')";
4006     r = MsiDatabaseOpenView(hdb, query, &view);
4007     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4008     r = MsiViewExecute(view, 0);
4009     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4010
4011     query = "SELECT * FROM `integers`";
4012     r = do_query(hdb, query, &rec);
4013     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4014
4015     r = MsiRecordGetFieldCount(rec);
4016     ok(r == 8, "record count wrong: %d\n", r);
4017
4018     i = MsiRecordGetInteger(rec, 1);
4019     ok(i == MSI_NULL_INTEGER, "Expected MSI_NULL_INTEGER, got %d\n", i);
4020     i = MsiRecordGetInteger(rec, 3);
4021     ok(i == MSI_NULL_INTEGER, "Expected MSI_NULL_INTEGER, got %d\n", i);
4022     i = MsiRecordGetInteger(rec, 2);
4023     ok(i == 2, "Expected 2, got %d\n", i);
4024     i = MsiRecordGetInteger(rec, 4);
4025     ok(i == 4, "Expected 4, got %d\n", i);
4026     i = MsiRecordGetInteger(rec, 5);
4027     ok(i == 5, "Expected 5, got %d\n", i);
4028     i = MsiRecordGetInteger(rec, 6);
4029     ok(i == 6, "Expected 6, got %d\n", i);
4030     i = MsiRecordGetInteger(rec, 7);
4031     ok(i == 7, "Expected 7, got %d\n", i);
4032     i = MsiRecordGetInteger(rec, 8);
4033     ok(i == 8, "Expected 8, got %d\n", i);
4034
4035     MsiCloseHandle(rec);
4036     MsiViewClose(view);
4037     MsiCloseHandle(view);
4038
4039     r = MsiDatabaseCommit(hdb);
4040     ok(r == ERROR_SUCCESS, "MsiDatabaseCommit failed\n");
4041
4042     r = MsiCloseHandle(hdb);
4043     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4044
4045     r = DeleteFile(msifile);
4046     ok(r == TRUE, "file didn't exist after commit\n");
4047 }
4048
4049 static void test_update(void)
4050 {
4051     MSIHANDLE hdb = 0, view = 0, rec = 0;
4052     CHAR result[MAX_PATH];
4053     const char *query;
4054     DWORD size;
4055     UINT r;
4056
4057     /* just MsiOpenDatabase should not create a file */
4058     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
4059     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
4060
4061     /* create the Control table */
4062     query = "CREATE TABLE `Control` ( "
4063         "`Dialog_` CHAR(72) NOT NULL, `Control` CHAR(50) NOT NULL, `Type` SHORT NOT NULL, "
4064         "`X` SHORT NOT NULL, `Y` SHORT NOT NULL, `Width` SHORT NOT NULL, `Height` SHORT NOT NULL,"
4065         "`Attributes` LONG, `Property` CHAR(50), `Text` CHAR(0) LOCALIZABLE, "
4066         "`Control_Next` CHAR(50), `Help` CHAR(50) LOCALIZABLE PRIMARY KEY `Dialog_`, `Control`)";
4067     r = MsiDatabaseOpenView(hdb, query, &view);
4068     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
4069     r = MsiViewExecute(view, 0);
4070     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
4071     r = MsiViewClose(view);
4072     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4073     r = MsiCloseHandle(view);
4074     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4075
4076     /* add a control */
4077     query = "INSERT INTO `Control` ( "
4078         "`Dialog_`, `Control`, `Type`, `X`, `Y`, `Width`, `Height`, "
4079         "`Property`, `Text`, `Control_Next`, `Help` )"
4080         "VALUES('ErrorDialog', 'ErrorText', '1', '5', '5', '5', '5', '', '', '', '')";
4081     r = MsiDatabaseOpenView(hdb, query, &view);
4082     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4083     r = MsiViewExecute(view, 0);
4084     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4085     r = MsiViewClose(view);
4086     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4087     r = MsiCloseHandle(view);
4088     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4089
4090     /* add a second control */
4091     query = "INSERT INTO `Control` ( "
4092         "`Dialog_`, `Control`, `Type`, `X`, `Y`, `Width`, `Height`, "
4093         "`Property`, `Text`, `Control_Next`, `Help` )"
4094         "VALUES('ErrorDialog', 'Button', '1', '5', '5', '5', '5', '', '', '', '')";
4095     r = MsiDatabaseOpenView(hdb, query, &view);
4096     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4097     r = MsiViewExecute(view, 0);
4098     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4099     r = MsiViewClose(view);
4100     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4101     r = MsiCloseHandle(view);
4102     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4103
4104     /* add a third control */
4105     query = "INSERT INTO `Control` ( "
4106         "`Dialog_`, `Control`, `Type`, `X`, `Y`, `Width`, `Height`, "
4107         "`Property`, `Text`, `Control_Next`, `Help` )"
4108         "VALUES('AnotherDialog', 'ErrorText', '1', '5', '5', '5', '5', '', '', '', '')";
4109     r = MsiDatabaseOpenView(hdb, query, &view);
4110     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4111     r = MsiViewExecute(view, 0);
4112     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4113     r = MsiViewClose(view);
4114     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4115     r = MsiCloseHandle(view);
4116     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4117
4118     /* bad table */
4119     query = "UPDATE `NotATable` SET `Text` = 'this is text' WHERE `Dialog_` = 'ErrorDialog'";
4120     r = MsiDatabaseOpenView(hdb, query, &view);
4121     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
4122
4123     /* bad set column */
4124     query = "UPDATE `Control` SET `NotAColumn` = 'this is text' WHERE `Dialog_` = 'ErrorDialog'";
4125     r = MsiDatabaseOpenView(hdb, query, &view);
4126     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
4127
4128     /* bad where condition */
4129     query = "UPDATE `Control` SET `Text` = 'this is text' WHERE `NotAColumn` = 'ErrorDialog'";
4130     r = MsiDatabaseOpenView(hdb, query, &view);
4131     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
4132
4133     /* just the dialog_ specified */
4134     query = "UPDATE `Control` SET `Text` = 'this is text' WHERE `Dialog_` = 'ErrorDialog'";
4135     r = MsiDatabaseOpenView(hdb, query, &view);
4136     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4137     r = MsiViewExecute(view, 0);
4138     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4139     r = MsiViewClose(view);
4140     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4141     r = MsiCloseHandle(view);
4142     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4143
4144     /* check the modified text */
4145     query = "SELECT `Text` FROM `Control` WHERE `Control` = 'ErrorText'";
4146     r = MsiDatabaseOpenView(hdb, query, &view);
4147     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4148     r = MsiViewExecute(view, 0);
4149     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4150
4151     r = MsiViewFetch(view, &rec);
4152     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4153
4154     size = MAX_PATH;
4155     r = MsiRecordGetString(rec, 1, result, &size);
4156     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4157     ok(!lstrcmp(result, "this is text"), "Expected `this is text`, got %s\n", result);
4158
4159     MsiCloseHandle(rec);
4160
4161     r = MsiViewFetch(view, &rec);
4162     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4163
4164     size = MAX_PATH;
4165     r = MsiRecordGetString(rec, 1, result, &size);
4166     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4167     ok(!lstrlen(result), "Expected an empty string, got %s\n", result);
4168
4169     MsiCloseHandle(rec);
4170
4171     r = MsiViewFetch(view, &rec);
4172     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
4173
4174     r = MsiViewClose(view);
4175     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4176     r = MsiCloseHandle(view);
4177     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4178
4179     /* dialog_ and control specified */
4180     query = "UPDATE `Control` SET `Text` = 'this is text' WHERE `Dialog_` = 'ErrorDialog' AND `Control` = 'ErrorText'";
4181     r = MsiDatabaseOpenView(hdb, query, &view);
4182     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4183     r = MsiViewExecute(view, 0);
4184     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4185     r = MsiViewClose(view);
4186     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4187     r = MsiCloseHandle(view);
4188     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4189
4190     /* check the modified text */
4191     query = "SELECT `Text` FROM `Control` WHERE `Control` = 'ErrorText'";
4192     r = MsiDatabaseOpenView(hdb, query, &view);
4193     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4194     r = MsiViewExecute(view, 0);
4195     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4196
4197     r = MsiViewFetch(view, &rec);
4198     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4199
4200     size = MAX_PATH;
4201     r = MsiRecordGetString(rec, 1, result, &size);
4202     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4203     ok(!lstrcmp(result, "this is text"), "Expected `this is text`, got %s\n", result);
4204
4205     MsiCloseHandle(rec);
4206
4207     r = MsiViewFetch(view, &rec);
4208     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4209
4210     size = MAX_PATH;
4211     r = MsiRecordGetString(rec, 1, result, &size);
4212     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4213     ok(!lstrlen(result), "Expected an empty string, got %s\n", result);
4214
4215     MsiCloseHandle(rec);
4216
4217     r = MsiViewFetch(view, &rec);
4218     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
4219
4220     r = MsiViewClose(view);
4221     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4222     r = MsiCloseHandle(view);
4223     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4224
4225     /* no where condition */
4226     query = "UPDATE `Control` SET `Text` = 'this is text'";
4227     r = MsiDatabaseOpenView(hdb, query, &view);
4228     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4229     r = MsiViewExecute(view, 0);
4230     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4231     r = MsiViewClose(view);
4232     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4233     r = MsiCloseHandle(view);
4234     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4235
4236     /* check the modified text */
4237     query = "SELECT `Text` FROM `Control`";
4238     r = MsiDatabaseOpenView(hdb, query, &view);
4239     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4240     r = MsiViewExecute(view, 0);
4241     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4242
4243     r = MsiViewFetch(view, &rec);
4244     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4245
4246     size = MAX_PATH;
4247     r = MsiRecordGetString(rec, 1, result, &size);
4248     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4249     ok(!lstrcmp(result, "this is text"), "Expected `this is text`, got %s\n", result);
4250
4251     MsiCloseHandle(rec);
4252
4253     r = MsiViewFetch(view, &rec);
4254     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4255
4256     size = MAX_PATH;
4257     r = MsiRecordGetString(rec, 1, result, &size);
4258     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4259     ok(!lstrcmp(result, "this is text"), "Expected `this is text`, got %s\n", result);
4260
4261     MsiCloseHandle(rec);
4262
4263     r = MsiViewFetch(view, &rec);
4264     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4265
4266     size = MAX_PATH;
4267     r = MsiRecordGetString(rec, 1, result, &size);
4268     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4269     ok(!lstrcmp(result, "this is text"), "Expected `this is text`, got %s\n", result);
4270
4271     MsiCloseHandle(rec);
4272
4273     r = MsiViewFetch(view, &rec);
4274     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
4275
4276     r = MsiViewClose(view);
4277     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4278     r = MsiCloseHandle(view);
4279     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4280
4281     query = "CREATE TABLE `Apple` ( `Banana` CHAR(72) NOT NULL, "
4282         "`Orange` CHAR(72),  `Pear` INT PRIMARY KEY `Banana`)";
4283     r = run_query(hdb, 0, query);
4284     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4285
4286     query = "INSERT INTO `Apple` ( `Banana`, `Orange`, `Pear` )"
4287         "VALUES('one', 'two', 3)";
4288     r = run_query(hdb, 0, query);
4289     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4290
4291     query = "INSERT INTO `Apple` ( `Banana`, `Orange`, `Pear` )"
4292         "VALUES('three', 'four', 5)";
4293     r = run_query(hdb, 0, query);
4294     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4295
4296     query = "INSERT INTO `Apple` ( `Banana`, `Orange`, `Pear` )"
4297         "VALUES('six', 'two', 7)";
4298     r = run_query(hdb, 0, query);
4299     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4300
4301     rec = MsiCreateRecord(2);
4302     MsiRecordSetInteger(rec, 1, 8);
4303     MsiRecordSetString(rec, 2, "two");
4304
4305     query = "UPDATE `Apple` SET `Pear` = ? WHERE `Orange` = ?";
4306     r = run_query(hdb, rec, query);
4307     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4308
4309     MsiCloseHandle(rec);
4310
4311     query = "SELECT `Pear` FROM `Apple` ORDER BY `Orange`";
4312     r = MsiDatabaseOpenView(hdb, query, &view);
4313     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4314     r = MsiViewExecute(view, 0);
4315     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4316
4317     r = MsiViewFetch(view, &rec);
4318     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4319
4320     r = MsiRecordGetInteger(rec, 1);
4321     ok(r == 8, "Expected 8, got %d\n", r);
4322
4323     MsiCloseHandle(rec);
4324
4325     r = MsiViewFetch(view, &rec);
4326     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4327
4328     r = MsiRecordGetInteger(rec, 1);
4329     ok(r == 8, "Expected 8, got %d\n", r);
4330
4331     MsiCloseHandle(rec);
4332
4333     r = MsiViewFetch(view, &rec);
4334     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4335
4336     r = MsiRecordGetInteger(rec, 1);
4337     ok(r == 5, "Expected 5, got %d\n", r);
4338
4339     MsiCloseHandle(rec);
4340
4341     r = MsiViewFetch(view, &rec);
4342     ok(r == ERROR_NO_MORE_ITEMS, "Expectd ERROR_NO_MORE_ITEMS, got %d\n", r);
4343
4344     MsiViewClose(view);
4345     MsiCloseHandle(view);
4346
4347     r = MsiDatabaseCommit(hdb);
4348     ok(r == ERROR_SUCCESS, "MsiDatabaseCommit failed\n");
4349     r = MsiCloseHandle(hdb);
4350     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4351
4352     DeleteFile(msifile);
4353 }
4354
4355 static void test_special_tables(void)
4356 {
4357     const char *query;
4358     MSIHANDLE hdb = 0;
4359     UINT r;
4360
4361     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
4362     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
4363
4364     query = "CREATE TABLE `_Properties` ( "
4365         "`foo` INT NOT NULL, `bar` INT LOCALIZABLE PRIMARY KEY `foo`)";
4366     r = run_query(hdb, 0, query);
4367     ok(r == ERROR_SUCCESS, "failed to create table\n");
4368
4369     query = "CREATE TABLE `_Storages` ( "
4370         "`foo` INT NOT NULL, `bar` INT LOCALIZABLE PRIMARY KEY `foo`)";
4371     r = run_query(hdb, 0, query);
4372     ok(r == ERROR_BAD_QUERY_SYNTAX, "created _Streams table\n");
4373
4374     query = "CREATE TABLE `_Streams` ( "
4375         "`foo` INT NOT NULL, `bar` INT LOCALIZABLE PRIMARY KEY `foo`)";
4376     r = run_query(hdb, 0, query);
4377     ok(r == ERROR_BAD_QUERY_SYNTAX, "created _Streams table\n");
4378
4379     query = "CREATE TABLE `_Tables` ( "
4380         "`foo` INT NOT NULL, `bar` INT LOCALIZABLE PRIMARY KEY `foo`)";
4381     r = run_query(hdb, 0, query);
4382     ok(r == ERROR_BAD_QUERY_SYNTAX, "created _Tables table\n");
4383
4384     query = "CREATE TABLE `_Columns` ( "
4385         "`foo` INT NOT NULL, `bar` INT LOCALIZABLE PRIMARY KEY `foo`)";
4386     r = run_query(hdb, 0, query);
4387     ok(r == ERROR_BAD_QUERY_SYNTAX, "created _Columns table\n");
4388
4389     r = MsiCloseHandle(hdb);
4390     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4391 }
4392
4393 static void test_tables_order(void)
4394 {
4395     const char *query;
4396     MSIHANDLE hdb = 0, hview = 0, hrec = 0;
4397     UINT r;
4398     char buffer[100];
4399     DWORD sz;
4400
4401     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
4402     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
4403
4404     query = "CREATE TABLE `foo` ( "
4405         "`baz` INT NOT NULL PRIMARY KEY `baz`)";
4406     r = run_query(hdb, 0, query);
4407     ok(r == ERROR_SUCCESS, "failed to create table\n");
4408
4409     query = "CREATE TABLE `bar` ( "
4410         "`foo` INT NOT NULL PRIMARY KEY `foo`)";
4411     r = run_query(hdb, 0, query);
4412     ok(r == ERROR_SUCCESS, "failed to create table\n");
4413
4414     query = "CREATE TABLE `baz` ( "
4415         "`bar` INT NOT NULL, "
4416         "`baz` INT NOT NULL, "
4417         "`foo` INT NOT NULL PRIMARY KEY `bar`)";
4418     r = run_query(hdb, 0, query);
4419     ok(r == ERROR_SUCCESS, "failed to create table\n");
4420
4421     /* The names of the tables in the _Tables table must
4422        be in the same order as these names are created in
4423        the strings table. */
4424     query = "SELECT * FROM `_Tables`";
4425     r = MsiDatabaseOpenView(hdb, query, &hview);
4426     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
4427     r = MsiViewExecute(hview, 0);
4428     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
4429
4430     r = MsiViewFetch(hview, &hrec);
4431     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4432     sz = sizeof(buffer);
4433     r = MsiRecordGetString(hrec, 1, buffer, &sz);
4434     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4435     ok(!lstrcmp(buffer, "foo"), "Expected foo, got %s\n", buffer);
4436     r = MsiCloseHandle(hrec);
4437     ok(r == ERROR_SUCCESS, "failed to close record\n");
4438
4439     r = MsiViewFetch(hview, &hrec);
4440     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4441     sz = sizeof(buffer);
4442     r = MsiRecordGetString(hrec, 1, buffer, &sz);
4443     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4444     ok(!lstrcmp(buffer, "baz"), "Expected baz, got %s\n", buffer);
4445     r = MsiCloseHandle(hrec);
4446     ok(r == ERROR_SUCCESS, "failed to close record\n");
4447
4448     r = MsiViewFetch(hview, &hrec);
4449     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4450     sz = sizeof(buffer);
4451     r = MsiRecordGetString(hrec, 1, buffer, &sz);
4452     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4453     ok(!lstrcmp(buffer, "bar"), "Expected bar, got %s\n", buffer);
4454     r = MsiCloseHandle(hrec);
4455     ok(r == ERROR_SUCCESS, "failed to close record\n");
4456
4457     r = MsiViewClose(hview);
4458     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4459     r = MsiCloseHandle(hview);
4460     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4461
4462     /* The names of the tables in the _Columns table must
4463        be in the same order as these names are created in
4464        the strings table. */
4465     query = "SELECT * FROM `_Columns`";
4466     r = MsiDatabaseOpenView(hdb, query, &hview);
4467     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
4468     r = MsiViewExecute(hview, 0);
4469     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
4470
4471     r = MsiViewFetch(hview, &hrec);
4472     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4473     sz = sizeof(buffer);
4474     r = MsiRecordGetString(hrec, 1, buffer, &sz);
4475     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4476     ok(!lstrcmp(buffer, "foo"), "Expected foo, got %s\n", buffer);
4477     sz = sizeof(buffer);
4478     r = MsiRecordGetString(hrec, 3, buffer, &sz);
4479     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4480     ok(!lstrcmp(buffer, "baz"), "Expected baz, got %s\n", buffer);
4481     r = MsiCloseHandle(hrec);
4482     ok(r == ERROR_SUCCESS, "failed to close record\n");
4483
4484     r = MsiViewFetch(hview, &hrec);
4485     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4486     sz = sizeof(buffer);
4487     r = MsiRecordGetString(hrec, 1, buffer, &sz);
4488     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4489     ok(!lstrcmp(buffer, "baz"), "Expected baz, got %s\n", buffer);
4490     sz = sizeof(buffer);
4491     r = MsiRecordGetString(hrec, 3, buffer, &sz);
4492     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4493     ok(!lstrcmp(buffer, "bar"), "Expected bar, got %s\n", buffer);
4494     r = MsiCloseHandle(hrec);
4495     ok(r == ERROR_SUCCESS, "failed to close record\n");
4496
4497     r = MsiViewFetch(hview, &hrec);
4498     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4499     sz = sizeof(buffer);
4500     r = MsiRecordGetString(hrec, 1, buffer, &sz);
4501     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4502     ok(!lstrcmp(buffer, "baz"), "Expected baz, got %s\n", buffer);
4503     sz = sizeof(buffer);
4504     r = MsiRecordGetString(hrec, 3, buffer, &sz);
4505     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4506     ok(!lstrcmp(buffer, "baz"), "Expected baz, got %s\n", buffer);
4507     r = MsiCloseHandle(hrec);
4508     ok(r == ERROR_SUCCESS, "failed to close record\n");
4509
4510     r = MsiViewFetch(hview, &hrec);
4511     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4512     sz = sizeof(buffer);
4513     r = MsiRecordGetString(hrec, 1, buffer, &sz);
4514     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4515     ok(!lstrcmp(buffer, "baz"), "Expected baz, got %s\n", buffer);
4516     sz = sizeof(buffer);
4517     r = MsiRecordGetString(hrec, 3, buffer, &sz);
4518     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4519     ok(!lstrcmp(buffer, "foo"), "Expected foo, got %s\n", buffer);
4520     r = MsiCloseHandle(hrec);
4521     ok(r == ERROR_SUCCESS, "failed to close record\n");
4522
4523     r = MsiViewFetch(hview, &hrec);
4524     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4525     sz = sizeof(buffer);
4526     r = MsiRecordGetString(hrec, 1, buffer, &sz);
4527     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4528     ok(!lstrcmp(buffer, "bar"), "Expected bar, got %s\n", buffer);
4529     sz = sizeof(buffer);
4530     r = MsiRecordGetString(hrec, 3, buffer, &sz);
4531     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4532     ok(!lstrcmp(buffer, "foo"), "Expected foo, got %s\n", buffer);
4533     r = MsiCloseHandle(hrec);
4534     ok(r == ERROR_SUCCESS, "failed to close record\n");
4535
4536     r = MsiViewClose(hview);
4537     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4538     r = MsiCloseHandle(hview);
4539     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4540
4541     r = MsiCloseHandle(hdb);
4542     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4543
4544     DeleteFile(msifile);
4545 }
4546
4547 static void test_rows_order(void)
4548 {
4549     const char *query;
4550     MSIHANDLE hdb = 0, hview = 0, hrec = 0;
4551     UINT r;
4552     char buffer[100];
4553     DWORD sz;
4554
4555     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
4556     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
4557
4558     query = "CREATE TABLE `foo` ( "
4559         "`bar` LONGCHAR NOT NULL PRIMARY KEY `bar`)";
4560     r = run_query(hdb, 0, query);
4561     ok(r == ERROR_SUCCESS, "failed to create table\n");
4562
4563     r = run_query(hdb, 0, "INSERT INTO `foo` "
4564             "( `bar` ) VALUES ( 'A' )");
4565     ok(r == ERROR_SUCCESS, "cannot add value to table\n");
4566
4567     r = run_query(hdb, 0, "INSERT INTO `foo` "
4568             "( `bar` ) VALUES ( 'B' )");
4569     ok(r == ERROR_SUCCESS, "cannot add value to table\n");
4570
4571     r = run_query(hdb, 0, "INSERT INTO `foo` "
4572             "( `bar` ) VALUES ( 'C' )");
4573     ok(r == ERROR_SUCCESS, "cannot add value to table\n");
4574
4575     r = run_query(hdb, 0, "INSERT INTO `foo` "
4576             "( `bar` ) VALUES ( 'D' )");
4577     ok(r == ERROR_SUCCESS, "cannot add value to table\n");
4578
4579     r = run_query(hdb, 0, "INSERT INTO `foo` "
4580             "( `bar` ) VALUES ( 'E' )");
4581     ok(r == ERROR_SUCCESS, "cannot add value to table\n");
4582
4583     r = run_query(hdb, 0, "INSERT INTO `foo` "
4584             "( `bar` ) VALUES ( 'F' )");
4585     ok(r == ERROR_SUCCESS, "cannot add value to table\n");
4586
4587     query = "CREATE TABLE `bar` ( "
4588         "`foo` LONGCHAR NOT NULL, "
4589         "`baz` LONGCHAR NOT NULL "
4590         "PRIMARY KEY `foo` )";
4591     r = run_query(hdb, 0, query);
4592     ok(r == ERROR_SUCCESS, "failed to create table\n");
4593
4594     r = run_query(hdb, 0, "INSERT INTO `bar` "
4595             "( `foo`, `baz` ) VALUES ( 'C', 'E' )");
4596     ok(r == ERROR_SUCCESS, "cannot add value to table\n");
4597
4598     r = run_query(hdb, 0, "INSERT INTO `bar` "
4599             "( `foo`, `baz` ) VALUES ( 'F', 'A' )");
4600     ok(r == ERROR_SUCCESS, "cannot add value to table\n");
4601
4602     r = run_query(hdb, 0, "INSERT INTO `bar` "
4603             "( `foo`, `baz` ) VALUES ( 'A', 'B' )");
4604     ok(r == ERROR_SUCCESS, "cannot add value to table\n");
4605
4606     r = run_query(hdb, 0, "INSERT INTO `bar` "
4607             "( `foo`, `baz` ) VALUES ( 'D', 'E' )");
4608     ok(r == ERROR_SUCCESS, "cannot add value to table\n");
4609
4610     /* The rows of the table must be ordered by the column values of
4611        each row. For strings, the column value is the string id
4612        in the string table.  */
4613
4614     query = "SELECT * FROM `bar`";
4615     r = MsiDatabaseOpenView(hdb, query, &hview);
4616     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
4617     r = MsiViewExecute(hview, 0);
4618     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
4619
4620     r = MsiViewFetch(hview, &hrec);
4621     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4622     sz = sizeof(buffer);
4623     r = MsiRecordGetString(hrec, 1, buffer, &sz);
4624     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4625     ok(!lstrcmp(buffer, "A"), "Expected A, got %s\n", buffer);
4626     sz = sizeof(buffer);
4627     r = MsiRecordGetString(hrec, 2, buffer, &sz);
4628     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4629     ok(!lstrcmp(buffer, "B"), "Expected B, got %s\n", buffer);
4630     r = MsiCloseHandle(hrec);
4631     ok(r == ERROR_SUCCESS, "failed to close record\n");
4632
4633     r = MsiViewFetch(hview, &hrec);
4634     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4635     sz = sizeof(buffer);
4636     r = MsiRecordGetString(hrec, 1, buffer, &sz);
4637     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4638     ok(!lstrcmp(buffer, "C"), "Expected E, got %s\n", buffer);
4639     sz = sizeof(buffer);
4640     r = MsiRecordGetString(hrec, 2, buffer, &sz);
4641     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4642     ok(!lstrcmp(buffer, "E"), "Expected E, got %s\n", buffer);
4643     r = MsiCloseHandle(hrec);
4644     ok(r == ERROR_SUCCESS, "failed to close record\n");
4645
4646     r = MsiViewFetch(hview, &hrec);
4647     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4648     sz = sizeof(buffer);
4649     r = MsiRecordGetString(hrec, 1, buffer, &sz);
4650     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4651     ok(!lstrcmp(buffer, "D"), "Expected D, got %s\n", buffer);
4652     sz = sizeof(buffer);
4653     r = MsiRecordGetString(hrec, 2, buffer, &sz);
4654     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4655     ok(!lstrcmp(buffer, "E"), "Expected E, got %s\n", buffer);
4656     r = MsiCloseHandle(hrec);
4657     ok(r == ERROR_SUCCESS, "failed to close record\n");
4658
4659     r = MsiViewFetch(hview, &hrec);
4660     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4661     sz = sizeof(buffer);
4662     r = MsiRecordGetString(hrec, 1, buffer, &sz);
4663     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4664     ok(!lstrcmp(buffer, "F"), "Expected F, got %s\n", buffer);
4665     sz = sizeof(buffer);
4666     r = MsiRecordGetString(hrec, 2, buffer, &sz);
4667     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4668     ok(!lstrcmp(buffer, "A"), "Expected A, got %s\n", buffer);
4669     r = MsiCloseHandle(hrec);
4670     ok(r == ERROR_SUCCESS, "failed to close record\n");
4671
4672     r = MsiViewClose(hview);
4673     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4674     r = MsiCloseHandle(hview);
4675     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4676
4677     r = MsiCloseHandle(hdb);
4678     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4679
4680     DeleteFile(msifile);
4681 }
4682
4683 static void test_select_markers(void)
4684 {
4685     MSIHANDLE hdb = 0, rec, view, res;
4686     LPCSTR query;
4687     UINT r;
4688     DWORD size;
4689     CHAR buf[MAX_PATH];
4690
4691     hdb = create_db();
4692     ok( hdb, "failed to create db\n");
4693
4694     r = run_query(hdb, 0,
4695             "CREATE TABLE `Table` (`One` CHAR(72), `Two` CHAR(72), `Three` SHORT PRIMARY KEY `One`, `Two`, `Three`)");
4696     ok(r == S_OK, "cannot create table: %d\n", r);
4697
4698     r = run_query(hdb, 0, "INSERT INTO `Table` "
4699             "( `One`, `Two`, `Three` ) VALUES ( 'apple', 'one', 1 )");
4700     ok(r == S_OK, "cannot add file to the Media table: %d\n", r);
4701
4702     r = run_query(hdb, 0, "INSERT INTO `Table` "
4703             "( `One`, `Two`, `Three` ) VALUES ( 'apple', 'two', 1 )");
4704     ok(r == S_OK, "cannot add file to the Media table: %d\n", r);
4705
4706     r = run_query(hdb, 0, "INSERT INTO `Table` "
4707             "( `One`, `Two`, `Three` ) VALUES ( 'apple', 'two', 2 )");
4708     ok(r == S_OK, "cannot add file to the Media table: %d\n", r);
4709
4710     r = run_query(hdb, 0, "INSERT INTO `Table` "
4711             "( `One`, `Two`, `Three` ) VALUES ( 'banana', 'three', 3 )");
4712     ok(r == S_OK, "cannot add file to the Media table: %d\n", r);
4713
4714     rec = MsiCreateRecord(2);
4715     MsiRecordSetString(rec, 1, "apple");
4716     MsiRecordSetString(rec, 2, "two");
4717
4718     query = "SELECT * FROM `Table` WHERE `One`=? AND `Two`=? ORDER BY `Three`";
4719     r = MsiDatabaseOpenView(hdb, query, &view);
4720     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4721
4722     r = MsiViewExecute(view, rec);
4723     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4724
4725     r = MsiViewFetch(view, &res);
4726     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4727
4728     size = MAX_PATH;
4729     r = MsiRecordGetString(res, 1, buf, &size);
4730     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4731     ok(!lstrcmp(buf, "apple"), "Expected apple, got %s\n", buf);
4732
4733     size = MAX_PATH;
4734     r = MsiRecordGetString(res, 2, buf, &size);
4735     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4736     ok(!lstrcmp(buf, "two"), "Expected two, got %s\n", buf);
4737
4738     r = MsiRecordGetInteger(res, 3);
4739     ok(r == 1, "Expected 1, got %d\n", r);
4740
4741     MsiCloseHandle(res);
4742
4743     r = MsiViewFetch(view, &res);
4744     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4745
4746     size = MAX_PATH;
4747     r = MsiRecordGetString(res, 1, buf, &size);
4748     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4749     ok(!lstrcmp(buf, "apple"), "Expected apple, got %s\n", buf);
4750
4751     size = MAX_PATH;
4752     r = MsiRecordGetString(res, 2, buf, &size);
4753     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4754     ok(!lstrcmp(buf, "two"), "Expected two, got %s\n", buf);
4755
4756     r = MsiRecordGetInteger(res, 3);
4757     ok(r == 2, "Expected 2, got %d\n", r);
4758
4759     MsiCloseHandle(res);
4760
4761     r = MsiViewFetch(view, &res);
4762     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
4763
4764     MsiCloseHandle(rec);
4765     MsiViewClose(view);
4766     MsiCloseHandle(view);
4767
4768     rec = MsiCreateRecord(2);
4769     MsiRecordSetString(rec, 1, "one");
4770     MsiRecordSetInteger(rec, 2, 1);
4771
4772     query = "SELECT * FROM `Table` WHERE `Two`<>? AND `Three`>? ORDER BY `Three`";
4773     r = MsiDatabaseOpenView(hdb, query, &view);
4774     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4775     r = MsiViewExecute(view, rec);
4776     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4777
4778     r = MsiViewFetch(view, &res);
4779     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4780
4781     size = MAX_PATH;
4782     r = MsiRecordGetString(res, 1, buf, &size);
4783     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4784     ok(!lstrcmp(buf, "apple"), "Expected apple, got %s\n", buf);
4785
4786     size = MAX_PATH;
4787     r = MsiRecordGetString(res, 2, buf, &size);
4788     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4789     ok(!lstrcmp(buf, "two"), "Expected two, got %s\n", buf);
4790
4791     r = MsiRecordGetInteger(res, 3);
4792     ok(r == 2, "Expected 2, got %d\n", r);
4793
4794     MsiCloseHandle(res);
4795
4796     r = MsiViewFetch(view, &res);
4797     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4798
4799     size = MAX_PATH;
4800     r = MsiRecordGetString(res, 1, buf, &size);
4801     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4802     ok(!lstrcmp(buf, "banana"), "Expected banana, got %s\n", buf);
4803
4804     size = MAX_PATH;
4805     r = MsiRecordGetString(res, 2, buf, &size);
4806     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4807     ok(!lstrcmp(buf, "three"), "Expected three, got %s\n", buf);
4808
4809     r = MsiRecordGetInteger(res, 3);
4810     ok(r == 3, "Expected 3, got %d\n", r);
4811
4812     MsiCloseHandle(res);
4813
4814     r = MsiViewFetch(view, &res);
4815     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
4816
4817     MsiCloseHandle(rec);
4818     MsiViewClose(view);
4819     MsiCloseHandle(view);
4820     MsiCloseHandle(hdb);
4821     DeleteFile(msifile);
4822 }
4823
4824 static void test_viewmodify_update(void)
4825 {
4826     MSIHANDLE hdb = 0, hview = 0, hrec = 0;
4827     const char *query;
4828     UINT r;
4829
4830     DeleteFile(msifile);
4831
4832     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
4833     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
4834
4835     query = "CREATE TABLE `table` (`A` INT, `B` INT PRIMARY KEY `A`)";
4836     r = run_query( hdb, 0, query );
4837     ok(r == ERROR_SUCCESS, "query failed\n");
4838
4839     query = "INSERT INTO `table` (`A`, `B`) VALUES (1, 2)";
4840     r = run_query( hdb, 0, query );
4841     ok(r == ERROR_SUCCESS, "query failed\n");
4842
4843     query = "INSERT INTO `table` (`A`, `B`) VALUES (3, 4)";
4844     r = run_query( hdb, 0, query );
4845     ok(r == ERROR_SUCCESS, "query failed\n");
4846
4847     query = "INSERT INTO `table` (`A`, `B`) VALUES (5, 6)";
4848     r = run_query( hdb, 0, query );
4849     ok(r == ERROR_SUCCESS, "query failed\n");
4850
4851     query = "SELECT `B` FROM `table`";
4852     r = MsiDatabaseOpenView(hdb, query, &hview);
4853     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
4854     r = MsiViewExecute(hview, 0);
4855     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
4856     r = MsiViewFetch(hview, &hrec);
4857     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4858
4859     r = MsiRecordSetInteger(hrec, 1, 0);
4860     ok(r == ERROR_SUCCESS, "failed to set integer\n");
4861
4862     r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
4863     ok(r == ERROR_SUCCESS, "MsiViewModify failed: %d\n", r);
4864
4865     r = MsiCloseHandle(hrec);
4866     ok(r == ERROR_SUCCESS, "failed to close record\n");
4867
4868     r = MsiViewClose(hview);
4869     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4870     r = MsiCloseHandle(hview);
4871     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4872
4873     query = "SELECT * FROM `table`";
4874     r = MsiDatabaseOpenView(hdb, query, &hview);
4875     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
4876     r = MsiViewExecute(hview, 0);
4877     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
4878     r = MsiViewFetch(hview, &hrec);
4879     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4880
4881     r = MsiRecordGetInteger(hrec, 1);
4882     ok(r == 1, "Expected 1, got %d\n", r);
4883     r = MsiRecordGetInteger(hrec, 2);
4884     ok(r == 0, "Expected 0, got %d\n", r);
4885
4886     r = MsiCloseHandle(hrec);
4887     ok(r == ERROR_SUCCESS, "failed to close record\n");
4888
4889     r = MsiViewFetch(hview, &hrec);
4890     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4891
4892     r = MsiRecordGetInteger(hrec, 1);
4893     ok(r == 3, "Expected 3, got %d\n", r);
4894     r = MsiRecordGetInteger(hrec, 2);
4895     ok(r == 4, "Expected 4, got %d\n", r);
4896
4897     r = MsiCloseHandle(hrec);
4898     ok(r == ERROR_SUCCESS, "failed to close record\n");
4899
4900     r = MsiViewFetch(hview, &hrec);
4901     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4902
4903     r = MsiRecordGetInteger(hrec, 1);
4904     ok(r == 5, "Expected 5, got %d\n", r);
4905     r = MsiRecordGetInteger(hrec, 2);
4906     ok(r == 6, "Expected 6, got %d\n", r);
4907
4908     r = MsiCloseHandle(hrec);
4909     ok(r == ERROR_SUCCESS, "failed to close record\n");
4910
4911     r = MsiViewFetch(hview, &hrec);
4912     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
4913
4914     r = MsiViewClose(hview);
4915     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4916     r = MsiCloseHandle(hview);
4917     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4918
4919     /* loop through all elements */
4920     query = "SELECT `B` FROM `table`";
4921     r = MsiDatabaseOpenView(hdb, query, &hview);
4922     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
4923     r = MsiViewExecute(hview, 0);
4924     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
4925
4926     while (TRUE)
4927     {
4928         r = MsiViewFetch(hview, &hrec);
4929         if (r != ERROR_SUCCESS)
4930             break;
4931
4932         r = MsiRecordSetInteger(hrec, 1, 0);
4933         ok(r == ERROR_SUCCESS, "failed to set integer\n");
4934
4935         r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
4936         ok(r == ERROR_SUCCESS, "MsiViewModify failed: %d\n", r);
4937
4938         r = MsiCloseHandle(hrec);
4939         ok(r == ERROR_SUCCESS, "failed to close record\n");
4940     }
4941
4942     r = MsiViewClose(hview);
4943     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4944     r = MsiCloseHandle(hview);
4945     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4946
4947     query = "SELECT * FROM `table`";
4948     r = MsiDatabaseOpenView(hdb, query, &hview);
4949     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
4950     r = MsiViewExecute(hview, 0);
4951     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
4952     r = MsiViewFetch(hview, &hrec);
4953     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4954
4955     r = MsiRecordGetInteger(hrec, 1);
4956     ok(r == 1, "Expected 1, got %d\n", r);
4957     r = MsiRecordGetInteger(hrec, 2);
4958     ok(r == 0, "Expected 0, got %d\n", r);
4959
4960     r = MsiCloseHandle(hrec);
4961     ok(r == ERROR_SUCCESS, "failed to close record\n");
4962
4963     r = MsiViewFetch(hview, &hrec);
4964     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4965
4966     r = MsiRecordGetInteger(hrec, 1);
4967     ok(r == 3, "Expected 3, got %d\n", r);
4968     r = MsiRecordGetInteger(hrec, 2);
4969     ok(r == 0, "Expected 0, got %d\n", r);
4970
4971     r = MsiCloseHandle(hrec);
4972     ok(r == ERROR_SUCCESS, "failed to close record\n");
4973
4974     r = MsiViewFetch(hview, &hrec);
4975     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4976
4977     r = MsiRecordGetInteger(hrec, 1);
4978     ok(r == 5, "Expected 5, got %d\n", r);
4979     r = MsiRecordGetInteger(hrec, 2);
4980     ok(r == 0, "Expected 0, got %d\n", r);
4981
4982     r = MsiCloseHandle(hrec);
4983     ok(r == ERROR_SUCCESS, "failed to close record\n");
4984
4985     r = MsiViewFetch(hview, &hrec);
4986     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
4987
4988     r = MsiViewClose(hview);
4989     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4990     r = MsiCloseHandle(hview);
4991     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4992
4993     r = MsiCloseHandle( hdb );
4994     ok(r == ERROR_SUCCESS, "MsiOpenDatabase close failed\n");
4995 }
4996
4997 static void test_viewmodify_assign(void)
4998 {
4999     MSIHANDLE hdb = 0, hview = 0, hrec = 0;
5000     const char *query;
5001     UINT r;
5002
5003     /* setup database */
5004     DeleteFile(msifile);
5005
5006     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
5007     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
5008
5009     query = "CREATE TABLE `table` (`A` INT, `B` INT PRIMARY KEY `A`)";
5010     r = run_query( hdb, 0, query );
5011     ok(r == ERROR_SUCCESS, "query failed\n");
5012
5013     /* assign to view, new primary key */
5014     query = "SELECT * FROM `table`";
5015     r = MsiDatabaseOpenView(hdb, query, &hview);
5016     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
5017     r = MsiViewExecute(hview, 0);
5018     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
5019
5020     hrec = MsiCreateRecord(2);
5021     ok(hrec != 0, "MsiCreateRecord failed\n");
5022
5023     r = MsiRecordSetInteger(hrec, 1, 1);
5024     ok(r == ERROR_SUCCESS, "failed to set integer\n");
5025     r = MsiRecordSetInteger(hrec, 2, 2);
5026     ok(r == ERROR_SUCCESS, "failed to set integer\n");
5027
5028     r = MsiViewModify(hview, MSIMODIFY_ASSIGN, hrec);
5029     ok(r == ERROR_SUCCESS, "MsiViewModify failed: %d\n", r);
5030
5031     r = MsiCloseHandle(hrec);
5032     ok(r == ERROR_SUCCESS, "failed to close record\n");
5033
5034     r = MsiViewClose(hview);
5035     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
5036     r = MsiCloseHandle(hview);
5037     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
5038
5039     query = "SELECT * FROM `table`";
5040     r = MsiDatabaseOpenView(hdb, query, &hview);
5041     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
5042     r = MsiViewExecute(hview, 0);
5043     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
5044     r = MsiViewFetch(hview, &hrec);
5045     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
5046
5047     r = MsiRecordGetInteger(hrec, 1);
5048     ok(r == 1, "Expected 1, got %d\n", r);
5049     r = MsiRecordGetInteger(hrec, 2);
5050     ok(r == 2, "Expected 2, got %d\n", r);
5051
5052     r = MsiCloseHandle(hrec);
5053     ok(r == ERROR_SUCCESS, "failed to close record\n");
5054
5055     r = MsiViewFetch(hview, &hrec);
5056     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5057
5058     r = MsiViewClose(hview);
5059     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
5060     r = MsiCloseHandle(hview);
5061     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
5062
5063     /* assign to view, primary key matches */
5064     query = "SELECT * FROM `table`";
5065     r = MsiDatabaseOpenView(hdb, query, &hview);
5066     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
5067     r = MsiViewExecute(hview, 0);
5068     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
5069
5070     hrec = MsiCreateRecord(2);
5071     ok(hrec != 0, "MsiCreateRecord failed\n");
5072
5073     r = MsiRecordSetInteger(hrec, 1, 1);
5074     ok(r == ERROR_SUCCESS, "failed to set integer\n");
5075     r = MsiRecordSetInteger(hrec, 2, 4);
5076     ok(r == ERROR_SUCCESS, "failed to set integer\n");
5077
5078     r = MsiViewModify(hview, MSIMODIFY_ASSIGN, hrec);
5079     ok(r == ERROR_SUCCESS, "MsiViewModify failed: %d\n", r);
5080
5081     r = MsiCloseHandle(hrec);
5082     ok(r == ERROR_SUCCESS, "failed to close record\n");
5083
5084     r = MsiViewClose(hview);
5085     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
5086     r = MsiCloseHandle(hview);
5087     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
5088
5089     query = "SELECT * FROM `table`";
5090     r = MsiDatabaseOpenView(hdb, query, &hview);
5091     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
5092     r = MsiViewExecute(hview, 0);
5093     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
5094     r = MsiViewFetch(hview, &hrec);
5095     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
5096
5097     r = MsiRecordGetInteger(hrec, 1);
5098     ok(r == 1, "Expected 1, got %d\n", r);
5099     r = MsiRecordGetInteger(hrec, 2);
5100     ok(r == 4, "Expected 4, got %d\n", r);
5101
5102     r = MsiCloseHandle(hrec);
5103     ok(r == ERROR_SUCCESS, "failed to close record\n");
5104
5105     r = MsiViewFetch(hview, &hrec);
5106     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5107
5108     r = MsiViewClose(hview);
5109     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
5110     r = MsiCloseHandle(hview);
5111     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
5112
5113     /* close database */
5114     r = MsiCloseHandle( hdb );
5115     ok(r == ERROR_SUCCESS, "MsiOpenDatabase close failed\n");
5116 }
5117
5118 static const WCHAR data10[] = { /* MOO */
5119     0x8001, 0x000b,
5120 };
5121 static const WCHAR data11[] = { /* AAR */
5122     0x8002, 0x8005,
5123     0x000c, 0x000f,
5124 };
5125 static const char data12[] = /* _StringData */
5126     "MOOABAARCDonetwofourfive";
5127 static const WCHAR data13[] = { /* _StringPool */
5128 /*  len, refs */
5129     0,   0,    /* string 0 ''     */
5130     0,   0,    /* string 1 ''     */
5131     0,   0,    /* string 2 ''     */
5132     0,   0,    /* string 3 ''     */
5133     0,   0,    /* string 4 ''     */
5134     3,   3,    /* string 5 'MOO'  */
5135     1,   1,    /* string 6 'A'    */
5136     1,   1,    /* string 7 'B'    */
5137     3,   3,    /* string 8 'AAR'  */
5138     1,   1,    /* string 9 'C'    */
5139     1,   1,    /* string a 'D'    */
5140     3,   1,    /* string b 'one'  */
5141     3,   1,    /* string c 'two'  */
5142     0,   0,    /* string d ''     */
5143     4,   1,    /* string e 'four' */
5144     4,   1,    /* string f 'five' */
5145 };
5146
5147 static void test_stringtable(void)
5148 {
5149     MSIHANDLE hdb = 0, hview = 0, hrec = 0;
5150     IStorage *stg = NULL;
5151     IStream *stm;
5152     WCHAR name[0x20];
5153     HRESULT hr;
5154     const char *query;
5155     char buffer[MAX_PATH];
5156     WCHAR data[MAX_PATH];
5157     DWORD sz, read;
5158     UINT r;
5159
5160     static const DWORD mode = STGM_DIRECT | STGM_READ | STGM_SHARE_DENY_WRITE;
5161     static const WCHAR stringdata[] = {0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0}; /* _StringData */
5162     static const WCHAR stringpool[] = {0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0}; /* _StringPool */
5163     static const WCHAR moo[] = {0x4840, 0x3e16, 0x4818, 0}; /* MOO */
5164     static const WCHAR aar[] = {0x4840, 0x3a8a, 0x481b, 0}; /* AAR */
5165
5166     DeleteFile(msifile);
5167
5168     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
5169     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5170
5171     query = "CREATE TABLE `MOO` (`A` INT, `B` CHAR(72) PRIMARY KEY `A`)";
5172     r = run_query(hdb, 0, query);
5173     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5174
5175     query = "CREATE TABLE `AAR` (`C` INT, `D` CHAR(72) PRIMARY KEY `C`)";
5176     r = run_query(hdb, 0, query);
5177     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5178
5179     /* insert persistent row */
5180     query = "INSERT INTO `MOO` (`A`, `B`) VALUES (1, 'one')";
5181     r = run_query(hdb, 0, query);
5182     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5183
5184     /* insert persistent row */
5185     query = "INSERT INTO `AAR` (`C`, `D`) VALUES (2, 'two')";
5186     r = run_query(hdb, 0, query);
5187     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5188
5189     /* open a view */
5190     query = "SELECT * FROM `MOO`";
5191     r = MsiDatabaseOpenView(hdb, query, &hview);
5192     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5193     r = MsiViewExecute(hview, 0);
5194     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5195
5196     hrec = MsiCreateRecord(2);
5197
5198     r = MsiRecordSetInteger(hrec, 1, 3);
5199     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5200     r = MsiRecordSetString(hrec, 2, "three");
5201     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5202
5203     /* insert a nonpersistent row */
5204     r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec);
5205     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5206
5207     r = MsiCloseHandle(hrec);
5208     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5209     r = MsiViewClose(hview);
5210     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5211     r = MsiCloseHandle(hview);
5212     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5213
5214     /* insert persistent row */
5215     query = "INSERT INTO `MOO` (`A`, `B`) VALUES (4, 'four')";
5216     r = run_query(hdb, 0, query);
5217     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5218
5219     /* insert persistent row */
5220     query = "INSERT INTO `AAR` (`C`, `D`) VALUES (5, 'five')";
5221     r = run_query(hdb, 0, query);
5222     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5223
5224     r = MsiDatabaseCommit(hdb);
5225     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5226
5227     r = MsiCloseHandle(hdb);
5228     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5229
5230     r = MsiOpenDatabase(msifile, MSIDBOPEN_READONLY, &hdb);
5231     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5232
5233     query = "SELECT * FROM `MOO`";
5234     r = MsiDatabaseOpenView(hdb, query, &hview);
5235     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5236
5237     r = MsiViewExecute(hview, 0);
5238     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5239
5240     r = MsiViewFetch(hview, &hrec);
5241     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5242
5243     r = MsiRecordGetFieldCount(hrec);
5244     ok(r == 2, "Expected 2, got %d\n", r);
5245
5246     r = MsiRecordGetInteger(hrec, 1);
5247     ok(r == 1, "Expected 1, got %d\n", r);
5248
5249     sz = sizeof(buffer);
5250     r = MsiRecordGetString(hrec, 2, buffer, &sz);
5251     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5252     ok(!lstrcmp(buffer, "one"), "Expected one, got %s\n", buffer);
5253
5254     r = MsiCloseHandle(hrec);
5255     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5256
5257     r = MsiViewFetch(hview, &hrec);
5258     todo_wine
5259     {
5260         ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5261     }
5262
5263     r = MsiViewClose(hview);
5264     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5265     r = MsiCloseHandle(hview);
5266     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5267     r = MsiCloseHandle(hrec);
5268     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5269
5270     query = "SELECT * FROM `AAR`";
5271     r = MsiDatabaseOpenView(hdb, query, &hview);
5272     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5273
5274     r = MsiViewExecute(hview, 0);
5275     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5276
5277     r = MsiViewFetch(hview, &hrec);
5278     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5279
5280     r = MsiRecordGetFieldCount(hrec);
5281     ok(r == 2, "Expected 2, got %d\n", r);
5282
5283     r = MsiRecordGetInteger(hrec, 1);
5284     ok(r == 2, "Expected 2, got %d\n", r);
5285
5286     sz = sizeof(buffer);
5287     r = MsiRecordGetString(hrec, 2, buffer, &sz);
5288     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5289     ok(!lstrcmp(buffer, "two"), "Expected two, got %s\n", buffer);
5290
5291     r = MsiCloseHandle(hrec);
5292     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5293
5294     r = MsiViewFetch(hview, &hrec);
5295     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5296
5297     r = MsiRecordGetFieldCount(hrec);
5298     ok(r == 2, "Expected 2, got %d\n", r);
5299
5300     r = MsiRecordGetInteger(hrec, 1);
5301     ok(r == 5, "Expected 5, got %d\n", r);
5302
5303     sz = sizeof(buffer);
5304     r = MsiRecordGetString(hrec, 2, buffer, &sz);
5305     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5306     ok(!lstrcmp(buffer, "five"), "Expected five, got %s\n", buffer);
5307
5308     r = MsiCloseHandle(hrec);
5309     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5310
5311     r = MsiViewFetch(hview, &hrec);
5312     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5313
5314     r = MsiViewClose(hview);
5315     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5316     r = MsiCloseHandle(hview);
5317     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5318     r = MsiCloseHandle(hrec);
5319     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5320     r = MsiCloseHandle(hdb);
5321     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5322
5323     MultiByteToWideChar(CP_ACP, 0, msifile, -1, name, 0x20);
5324     hr = StgOpenStorage(name, NULL, mode, NULL, 0, &stg);
5325     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5326     ok(stg != NULL, "Expected non-NULL storage\n");
5327
5328     hr = IStorage_OpenStream(stg, moo, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm);
5329     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5330     ok(stm != NULL, "Expected non-NULL stream\n");
5331
5332     hr = IStream_Read(stm, data, MAX_PATH, &read);
5333     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5334     todo_wine
5335     {
5336         ok(read == 4, "Expected 4, got %d\n", read);
5337         ok(!memcmp(data, data10, read), "Unexpected data\n");
5338     }
5339
5340     hr = IStream_Release(stm);
5341     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5342
5343     hr = IStorage_OpenStream(stg, aar, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm);
5344     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5345     ok(stm != NULL, "Expected non-NULL stream\n");
5346
5347     hr = IStream_Read(stm, data, MAX_PATH, &read);
5348     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5349     ok(read == 8, "Expected 8, got %d\n", read);
5350     todo_wine
5351     {
5352         ok(!memcmp(data, data11, read), "Unexpected data\n");
5353     }
5354
5355     hr = IStream_Release(stm);
5356     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5357
5358     hr = IStorage_OpenStream(stg, stringdata, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm);
5359     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5360     ok(stm != NULL, "Expected non-NULL stream\n");
5361
5362     hr = IStream_Read(stm, buffer, MAX_PATH, &read);
5363     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5364     ok(read == 24, "Expected 24, got %d\n", read);
5365     ok(!memcmp(buffer, data12, read), "Unexpected data\n");
5366
5367     hr = IStream_Release(stm);
5368     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5369
5370     hr = IStorage_OpenStream(stg, stringpool, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm);
5371     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5372     ok(stm != NULL, "Expected non-NULL stream\n");
5373
5374     hr = IStream_Read(stm, data, MAX_PATH, &read);
5375     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5376     todo_wine
5377     {
5378         ok(read == 64, "Expected 64, got %d\n", read);
5379         ok(!memcmp(data, data13, read), "Unexpected data\n");
5380     }
5381
5382     hr = IStream_Release(stm);
5383     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5384
5385     hr = IStorage_Release(stg);
5386     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5387
5388     DeleteFileA(msifile);
5389 }
5390
5391 static void test_viewmodify_delete(void)
5392 {
5393     MSIHANDLE hdb = 0, hview = 0, hrec = 0;
5394     UINT r;
5395     const char *query;
5396     char buffer[0x100];
5397     DWORD sz;
5398
5399     DeleteFile(msifile);
5400
5401     /* just MsiOpenDatabase should not create a file */
5402     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
5403     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5404
5405     query = "CREATE TABLE `phone` ( "
5406             "`id` INT, `name` CHAR(32), `number` CHAR(32) "
5407             "PRIMARY KEY `id`)";
5408     r = run_query(hdb, 0, query);
5409     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5410
5411     query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
5412         "VALUES('1', 'Alan', '5030581')";
5413     r = run_query(hdb, 0, query);
5414     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5415
5416     query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
5417         "VALUES('2', 'Barry', '928440')";
5418     r = run_query(hdb, 0, query);
5419     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5420
5421     query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
5422         "VALUES('3', 'Cindy', '2937550')";
5423     r = run_query(hdb, 0, query);
5424     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5425
5426     query = "SELECT * FROM `phone` WHERE `id` <= 2";
5427     r = MsiDatabaseOpenView(hdb, query, &hview);
5428     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5429     r = MsiViewExecute(hview, 0);
5430     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5431     r = MsiViewFetch(hview, &hrec);
5432     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5433
5434     /* delete 1 */
5435     r = MsiViewModify(hview, MSIMODIFY_DELETE, hrec);
5436     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5437
5438     r = MsiCloseHandle(hrec);
5439     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5440     r = MsiViewFetch(hview, &hrec);
5441     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5442
5443     /* delete 2 */
5444     r = MsiViewModify(hview, MSIMODIFY_DELETE, hrec);
5445     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5446
5447     r = MsiCloseHandle(hrec);
5448     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5449     r = MsiViewClose(hview);
5450     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5451     r = MsiCloseHandle(hview);
5452     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5453
5454     query = "SELECT * FROM `phone`";
5455     r = MsiDatabaseOpenView(hdb, query, &hview);
5456     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5457     r = MsiViewExecute(hview, 0);
5458     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5459     r = MsiViewFetch(hview, &hrec);
5460     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5461
5462     r = MsiRecordGetInteger(hrec, 1);
5463     ok(r == 3, "Expected 3, got %d\n", r);
5464
5465     sz = sizeof(buffer);
5466     r = MsiRecordGetString(hrec, 2, buffer, &sz);
5467     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5468     ok(!lstrcmp(buffer, "Cindy"), "Expected Cindy, got %s\n", buffer);
5469
5470     sz = sizeof(buffer);
5471     r = MsiRecordGetString(hrec, 3, buffer, &sz);
5472     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5473     ok(!lstrcmp(buffer, "2937550"), "Expected 2937550, got %s\n", buffer);
5474
5475     r = MsiCloseHandle(hrec);
5476     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5477
5478     r = MsiViewFetch(hview, &hrec);
5479     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5480
5481     r = MsiViewClose(hview);
5482     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5483     r = MsiCloseHandle(hview);
5484     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5485     r = MsiCloseHandle(hdb);
5486     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5487 }
5488
5489 static const WCHAR _Tables[] = {0x4840, 0x3f7f, 0x4164, 0x422f, 0x4836, 0};
5490 static const WCHAR _StringData[] = {0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0};
5491 static const WCHAR _StringPool[] = {0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0};
5492
5493 static const WCHAR data14[] = { /* _StringPool */
5494 /*  len, refs */
5495     0,   0,    /* string 0 ''    */
5496 };
5497
5498 static const struct {
5499     LPCWSTR name;
5500     const void *data;
5501     DWORD size;
5502 } database_table_data[] =
5503 {
5504     {_Tables, NULL, 0},
5505     {_StringData, NULL, 0},
5506     {_StringPool, data14, sizeof data14},
5507 };
5508
5509 static void enum_stream_names(IStorage *stg)
5510 {
5511     IEnumSTATSTG *stgenum = NULL;
5512     IStream *stm;
5513     HRESULT hr;
5514     STATSTG stat;
5515     ULONG n, count;
5516     BYTE data[MAX_PATH];
5517     BYTE check[MAX_PATH];
5518     DWORD sz;
5519
5520     memset(check, 'a', MAX_PATH);
5521
5522     hr = IStorage_EnumElements(stg, 0, NULL, 0, &stgenum);
5523     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
5524
5525     n = 0;
5526     while(TRUE)
5527     {
5528         count = 0;
5529         hr = IEnumSTATSTG_Next(stgenum, 1, &stat, &count);
5530         if(FAILED(hr) || !count)
5531             break;
5532
5533         ok(!lstrcmpW(stat.pwcsName, database_table_data[n].name),
5534            "Expected table %d name to match\n", n);
5535
5536         stm = NULL;
5537         hr = IStorage_OpenStream(stg, stat.pwcsName, NULL,
5538                                  STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm);
5539         ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
5540         ok(stm != NULL, "Expected non-NULL stream\n");
5541
5542         sz = MAX_PATH;
5543         memset(data, 'a', MAX_PATH);
5544         hr = IStream_Read(stm, data, sz, &count);
5545         ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
5546
5547         ok(count == database_table_data[n].size,
5548            "Expected %d, got %d\n", database_table_data[n].size, count);
5549
5550         if (!database_table_data[n].size)
5551             ok(!memcmp(data, check, MAX_PATH), "data should not be changed\n");
5552         else
5553             ok(!memcmp(data, database_table_data[n].data, database_table_data[n].size),
5554                "Expected table %d data to match\n", n);
5555
5556         IStream_Release(stm);
5557         n++;
5558     }
5559
5560     ok(n == 3, "Expected 3, got %d\n", n);
5561
5562     IEnumSTATSTG_Release(stgenum);
5563 }
5564
5565 static void test_defaultdatabase(void)
5566 {
5567     UINT r;
5568     HRESULT hr;
5569     MSIHANDLE hdb;
5570     IStorage *stg = NULL;
5571
5572     static const WCHAR msifileW[] = {'w','i','n','e','t','e','s','t','.','m','s','i',0};
5573
5574     DeleteFile(msifile);
5575
5576     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
5577     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5578
5579     r = MsiDatabaseCommit(hdb);
5580     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5581
5582     MsiCloseHandle(hdb);
5583
5584     hr = StgOpenStorage(msifileW, NULL, STGM_READ | STGM_SHARE_DENY_WRITE, NULL, 0, &stg);
5585     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
5586     ok(stg != NULL, "Expected non-NULL stg\n");
5587
5588     enum_stream_names(stg);
5589
5590     IStorage_Release(stg);
5591     DeleteFileA(msifile);
5592 }
5593
5594 static void test_order(void)
5595 {
5596     MSIHANDLE hdb, hview, hrec;
5597     CHAR buffer[MAX_PATH];
5598     LPCSTR query;
5599     UINT r, sz;
5600     int val;
5601
5602     hdb = create_db();
5603     ok(hdb, "failed to create db\n");
5604
5605     query = "CREATE TABLE `Empty` ( `A` SHORT NOT NULL PRIMARY KEY `A`)";
5606     r = run_query(hdb, 0, query);
5607     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5608
5609     query = "CREATE TABLE `Mesa` ( `A` SHORT NOT NULL, `B` SHORT, `C` SHORT PRIMARY KEY `A`)";
5610     r = run_query(hdb, 0, query);
5611     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5612
5613     query = "INSERT INTO `Mesa` ( `A`, `B`, `C` ) VALUES ( 1, 2, 9 )";
5614     r = run_query(hdb, 0, query);
5615     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5616
5617     query = "INSERT INTO `Mesa` ( `A`, `B`, `C` ) VALUES ( 3, 4, 7 )";
5618     r = run_query(hdb, 0, query);
5619     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5620
5621     query = "INSERT INTO `Mesa` ( `A`, `B`, `C` ) VALUES ( 5, 6, 8 )";
5622     r = run_query(hdb, 0, query);
5623     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5624
5625     query = "CREATE TABLE `Sideboard` ( `D` SHORT NOT NULL, `E` SHORT, `F` SHORT PRIMARY KEY `D`)";
5626     r = run_query(hdb, 0, query);
5627     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5628
5629     query = "INSERT INTO `Sideboard` ( `D`, `E`, `F` ) VALUES ( 10, 11, 18 )";
5630     r = run_query(hdb, 0, query);
5631     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5632
5633     query = "INSERT INTO `Sideboard` ( `D`, `E`, `F` ) VALUES ( 12, 13, 16 )";
5634     r = run_query(hdb, 0, query);
5635     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5636
5637     query = "INSERT INTO `Sideboard` ( `D`, `E`, `F` ) VALUES ( 14, 15, 17 )";
5638     r = run_query(hdb, 0, query);
5639     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5640
5641     query = "SELECT `A`, `B` FROM `Mesa` ORDER BY `C`";
5642     r = MsiDatabaseOpenView(hdb, query, &hview);
5643     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5644     r = MsiViewExecute(hview, 0);
5645     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5646
5647     r = MsiViewFetch(hview, &hrec);
5648     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5649
5650     val = MsiRecordGetInteger(hrec, 1);
5651     ok(val == 3, "Expected 3, got %d\n", val);
5652
5653     val = MsiRecordGetInteger(hrec, 2);
5654     ok(val == 4, "Expected 3, got %d\n", val);
5655
5656     MsiCloseHandle(hrec);
5657
5658     r = MsiViewFetch(hview, &hrec);
5659     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5660
5661     val = MsiRecordGetInteger(hrec, 1);
5662     ok(val == 5, "Expected 5, got %d\n", val);
5663
5664     val = MsiRecordGetInteger(hrec, 2);
5665     ok(val == 6, "Expected 6, got %d\n", val);
5666
5667     MsiCloseHandle(hrec);
5668
5669     r = MsiViewFetch(hview, &hrec);
5670     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5671
5672     val = MsiRecordGetInteger(hrec, 1);
5673     ok(val == 1, "Expected 1, got %d\n", val);
5674
5675     val = MsiRecordGetInteger(hrec, 2);
5676     ok(val == 2, "Expected 2, got %d\n", val);
5677
5678     MsiCloseHandle(hrec);
5679
5680     r = MsiViewFetch(hview, &hrec);
5681     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5682
5683     MsiViewClose(hview);
5684     MsiCloseHandle(hview);
5685
5686     query = "SELECT `A`, `D` FROM `Mesa`, `Sideboard` ORDER BY `F`";
5687     r = MsiDatabaseOpenView(hdb, query, &hview);
5688     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5689     r = MsiViewExecute(hview, 0);
5690     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5691
5692     r = MsiViewFetch(hview, &hrec);
5693     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5694
5695     val = MsiRecordGetInteger(hrec, 1);
5696     ok(val == 1, "Expected 1, got %d\n", val);
5697
5698     val = MsiRecordGetInteger(hrec, 2);
5699     ok(val == 12, "Expected 12, got %d\n", val);
5700
5701     MsiCloseHandle(hrec);
5702
5703     r = MsiViewFetch(hview, &hrec);
5704     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5705
5706     val = MsiRecordGetInteger(hrec, 1);
5707     ok(val == 3, "Expected 3, got %d\n", val);
5708
5709     val = MsiRecordGetInteger(hrec, 2);
5710     ok(val == 12, "Expected 12, got %d\n", val);
5711
5712     MsiCloseHandle(hrec);
5713
5714     r = MsiViewFetch(hview, &hrec);
5715     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5716
5717     val = MsiRecordGetInteger(hrec, 1);
5718     ok(val == 5, "Expected 5, got %d\n", val);
5719
5720     val = MsiRecordGetInteger(hrec, 2);
5721     ok(val == 12, "Expected 12, got %d\n", val);
5722
5723     MsiCloseHandle(hrec);
5724
5725     r = MsiViewFetch(hview, &hrec);
5726     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5727
5728     val = MsiRecordGetInteger(hrec, 1);
5729     ok(val == 1, "Expected 1, got %d\n", val);
5730
5731     val = MsiRecordGetInteger(hrec, 2);
5732     ok(val == 14, "Expected 14, got %d\n", val);
5733
5734     MsiCloseHandle(hrec);
5735
5736     r = MsiViewFetch(hview, &hrec);
5737     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5738
5739     val = MsiRecordGetInteger(hrec, 1);
5740     ok(val == 3, "Expected 3, got %d\n", val);
5741
5742     val = MsiRecordGetInteger(hrec, 2);
5743     ok(val == 14, "Expected 14, got %d\n", val);
5744
5745     MsiCloseHandle(hrec);
5746
5747     r = MsiViewFetch(hview, &hrec);
5748     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5749
5750     val = MsiRecordGetInteger(hrec, 1);
5751     ok(val == 5, "Expected 5, got %d\n", val);
5752
5753     val = MsiRecordGetInteger(hrec, 2);
5754     ok(val == 14, "Expected 14, got %d\n", val);
5755
5756     MsiCloseHandle(hrec);
5757
5758     r = MsiViewFetch(hview, &hrec);
5759     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5760
5761     val = MsiRecordGetInteger(hrec, 1);
5762     ok(val == 1, "Expected 1, got %d\n", val);
5763
5764     val = MsiRecordGetInteger(hrec, 2);
5765     ok(val == 10, "Expected 10, got %d\n", val);
5766
5767     MsiCloseHandle(hrec);
5768
5769     r = MsiViewFetch(hview, &hrec);
5770     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5771
5772     val = MsiRecordGetInteger(hrec, 1);
5773     ok(val == 3, "Expected 3, got %d\n", val);
5774
5775     val = MsiRecordGetInteger(hrec, 2);
5776     ok(val == 10, "Expected 10, got %d\n", val);
5777
5778     MsiCloseHandle(hrec);
5779
5780     r = MsiViewFetch(hview, &hrec);
5781     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5782
5783     val = MsiRecordGetInteger(hrec, 1);
5784     ok(val == 5, "Expected 5, got %d\n", val);
5785
5786     val = MsiRecordGetInteger(hrec, 2);
5787     ok(val == 10, "Expected 10, got %d\n", val);
5788
5789     MsiCloseHandle(hrec);
5790
5791     r = MsiViewFetch(hview, &hrec);
5792     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5793
5794     MsiViewClose(hview);
5795     MsiCloseHandle(hview);
5796
5797     query = "SELECT * FROM `Empty` ORDER BY `A`";
5798     r = MsiDatabaseOpenView(hdb, query, &hview);
5799     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5800     r = MsiViewExecute(hview, 0);
5801     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5802
5803     r = MsiViewFetch(hview, &hrec);
5804     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5805
5806     MsiViewClose(hview);
5807     MsiCloseHandle(hview);
5808
5809     query = "CREATE TABLE `Buffet` ( `One` CHAR(72), `Two` SHORT PRIMARY KEY `One`)";
5810     r = run_query(hdb, 0, query);
5811     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5812
5813     query = "INSERT INTO `Buffet` ( `One`, `Two` ) VALUES ( 'uno',  2)";
5814     r = run_query(hdb, 0, query);
5815     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5816
5817     query = "INSERT INTO `Buffet` ( `One`, `Two` ) VALUES ( 'dos',  3)";
5818     r = run_query(hdb, 0, query);
5819     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5820
5821     query = "INSERT INTO `Buffet` ( `One`, `Two` ) VALUES ( 'tres',  1)";
5822     r = run_query(hdb, 0, query);
5823     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5824
5825     query = "SELECT * FROM `Buffet` WHERE `One` = 'dos' ORDER BY `Two`";
5826     r = MsiDatabaseOpenView(hdb, query, &hview);
5827     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5828     r = MsiViewExecute(hview, 0);
5829     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5830
5831     r = MsiViewFetch(hview, &hrec);
5832     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5833
5834     sz = sizeof(buffer);
5835     r = MsiRecordGetString(hrec, 1, buffer, &sz);
5836     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5837     ok(!lstrcmp(buffer, "dos"), "Expected \"dos\", got \"%s\"\n", buffer);
5838
5839     r = MsiRecordGetInteger(hrec, 2);
5840     ok(r == 3, "Expected 3, got %d\n", r);
5841
5842     MsiCloseHandle(hrec);
5843
5844     r = MsiViewFetch(hview, &hrec);
5845     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5846
5847     MsiViewClose(hview);
5848     MsiCloseHandle(hview);
5849     MsiCloseHandle(hdb);
5850 }
5851
5852 static void test_viewmodify_delete_temporary(void)
5853 {
5854     MSIHANDLE hdb, hview, hrec;
5855     const char *query;
5856     UINT r;
5857
5858     DeleteFile(msifile);
5859
5860     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
5861     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5862
5863     query = "CREATE TABLE `Table` ( `A` SHORT PRIMARY KEY `A` )";
5864     r = run_query(hdb, 0, query);
5865     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5866
5867     query = "SELECT * FROM `Table`";
5868     r = MsiDatabaseOpenView(hdb, query, &hview);
5869     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5870     r = MsiViewExecute(hview, 0);
5871     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5872
5873     hrec = MsiCreateRecord(1);
5874     MsiRecordSetInteger(hrec, 1, 1);
5875
5876     r = MsiViewModify(hview, MSIMODIFY_INSERT, hrec);
5877     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5878
5879     MsiCloseHandle(hrec);
5880
5881     hrec = MsiCreateRecord(1);
5882     MsiRecordSetInteger(hrec, 1, 2);
5883
5884     r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec);
5885     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5886
5887     MsiCloseHandle(hrec);
5888
5889     hrec = MsiCreateRecord(1);
5890     MsiRecordSetInteger(hrec, 1, 3);
5891
5892     r = MsiViewModify(hview, MSIMODIFY_INSERT, hrec);
5893     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5894
5895     MsiCloseHandle(hrec);
5896
5897     hrec = MsiCreateRecord(1);
5898     MsiRecordSetInteger(hrec, 1, 4);
5899
5900     r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec);
5901     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5902
5903     MsiCloseHandle(hrec);
5904     MsiViewClose(hview);
5905     MsiCloseHandle(hview);
5906
5907     query = "SELECT * FROM `Table` WHERE  `A` = 2";
5908     r = MsiDatabaseOpenView(hdb, query, &hview);
5909     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5910     r = MsiViewExecute(hview, 0);
5911     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5912     r = MsiViewFetch(hview, &hrec);
5913     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5914
5915     r = MsiViewModify(hview, MSIMODIFY_DELETE, hrec);
5916     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5917
5918     MsiCloseHandle(hrec);
5919     MsiViewClose(hview);
5920     MsiCloseHandle(hview);
5921
5922     query = "SELECT * FROM `Table` WHERE  `A` = 3";
5923     r = MsiDatabaseOpenView(hdb, query, &hview);
5924     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5925     r = MsiViewExecute(hview, 0);
5926     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5927     r = MsiViewFetch(hview, &hrec);
5928     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5929
5930     r = MsiViewModify(hview, MSIMODIFY_DELETE, hrec);
5931     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5932
5933     MsiCloseHandle(hrec);
5934     MsiViewClose(hview);
5935     MsiCloseHandle(hview);
5936
5937     query = "SELECT * FROM `Table` ORDER BY `A`";
5938     r = MsiDatabaseOpenView(hdb, query, &hview);
5939     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5940     r = MsiViewExecute(hview, 0);
5941     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5942
5943     r = MsiViewFetch(hview, &hrec);
5944     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5945
5946     r = MsiRecordGetInteger(hrec, 1);
5947     ok(r == 1, "Expected 1, got %d\n", r);
5948
5949     MsiCloseHandle(hrec);
5950
5951     r = MsiViewFetch(hview, &hrec);
5952     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5953
5954     r = MsiRecordGetInteger(hrec, 1);
5955     ok(r == 4, "Expected 4, got %d\n", r);
5956
5957     MsiCloseHandle(hrec);
5958
5959     r = MsiViewFetch(hview, &hrec);
5960     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5961
5962     MsiViewClose(hview);
5963     MsiCloseHandle(hview);
5964     MsiCloseHandle(hdb);
5965     DeleteFileA(msifile);
5966 }
5967
5968 static void test_deleterow(void)
5969 {
5970     MSIHANDLE hdb, hview, hrec;
5971     const char *query;
5972     char buf[MAX_PATH];
5973     UINT r;
5974     DWORD size;
5975
5976     DeleteFile(msifile);
5977
5978     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
5979     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5980
5981     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
5982     r = run_query(hdb, 0, query);
5983     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5984
5985     query = "INSERT INTO `Table` (`A`) VALUES ('one')";
5986     r = run_query(hdb, 0, query);
5987     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5988
5989     query = "INSERT INTO `Table` (`A`) VALUES ('two')";
5990     r = run_query(hdb, 0, query);
5991     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5992
5993     query = "DELETE FROM `Table` WHERE `A` = 'one'";
5994     r = run_query(hdb, 0, query);
5995     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5996
5997     r = MsiDatabaseCommit(hdb);
5998     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5999
6000     MsiCloseHandle(hdb);
6001
6002     r = MsiOpenDatabase(msifile, MSIDBOPEN_READONLY, &hdb);
6003     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6004
6005     query = "SELECT * FROM `Table`";
6006     r = MsiDatabaseOpenView(hdb, query, &hview);
6007     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6008     r = MsiViewExecute(hview, 0);
6009     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6010
6011     r = MsiViewFetch(hview, &hrec);
6012     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6013
6014     size = MAX_PATH;
6015     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6016     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6017     ok(!lstrcmpA(buf, "two"), "Expected two, got %s\n", buf);
6018
6019     MsiCloseHandle(hrec);
6020
6021     r = MsiViewFetch(hview, &hrec);
6022     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6023
6024     MsiViewClose(hview);
6025     MsiCloseHandle(hview);
6026     MsiCloseHandle(hdb);
6027     DeleteFileA(msifile);
6028 }
6029
6030 static const CHAR import_dat[] = "A\n"
6031                                  "s72\n"
6032                                  "Table\tA\n"
6033                                  "This is a new 'string' ok\n";
6034
6035 static void test_quotes(void)
6036 {
6037     MSIHANDLE hdb, hview, hrec;
6038     const char *query;
6039     char buf[MAX_PATH];
6040     UINT r;
6041     DWORD size;
6042
6043     DeleteFile(msifile);
6044
6045     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
6046     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6047
6048     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6049     r = run_query(hdb, 0, query);
6050     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6051
6052     query = "INSERT INTO `Table` ( `A` ) VALUES ( 'This is a 'string' ok' )";
6053     r = run_query(hdb, 0, query);
6054     ok(r == ERROR_BAD_QUERY_SYNTAX,
6055        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6056
6057     query = "INSERT INTO `Table` ( `A` ) VALUES ( \"This is a 'string' ok\" )";
6058     r = run_query(hdb, 0, query);
6059     ok(r == ERROR_BAD_QUERY_SYNTAX,
6060        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6061
6062     query = "INSERT INTO `Table` ( `A` ) VALUES ( \"test\" )";
6063     r = run_query(hdb, 0, query);
6064     ok(r == ERROR_BAD_QUERY_SYNTAX,
6065        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6066
6067     query = "INSERT INTO `Table` ( `A` ) VALUES ( 'This is a ''string'' ok' )";
6068     r = run_query(hdb, 0, query);
6069     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6070
6071     query = "INSERT INTO `Table` ( `A` ) VALUES ( 'This is a '''string''' ok' )";
6072     r = run_query(hdb, 0, query);
6073     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6074
6075     query = "INSERT INTO `Table` ( `A` ) VALUES ( 'This is a \'string\' ok' )";
6076     r = run_query(hdb, 0, query);
6077     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6078
6079     query = "INSERT INTO `Table` ( `A` ) VALUES ( 'This is a \"string\" ok' )";
6080     r = run_query(hdb, 0, query);
6081     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6082
6083     query = "SELECT * FROM `Table`";
6084     r = MsiDatabaseOpenView(hdb, query, &hview);
6085     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6086
6087     r = MsiViewExecute(hview, 0);
6088     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6089
6090     r = MsiViewFetch(hview, &hrec);
6091     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6092
6093     size = MAX_PATH;
6094     r = MsiRecordGetString(hrec, 1, buf, &size);
6095     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6096     ok(!lstrcmp(buf, "This is a \"string\" ok"),
6097        "Expected \"This is a \"string\" ok\", got %s\n", buf);
6098
6099     MsiCloseHandle(hrec);
6100
6101     r = MsiViewFetch(hview, &hrec);
6102     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6103
6104     MsiViewClose(hview);
6105     MsiCloseHandle(hview);
6106
6107     write_file("import.idt", import_dat, (sizeof(import_dat) - 1) * sizeof(char));
6108
6109     r = MsiDatabaseImportA(hdb, CURR_DIR, "import.idt");
6110     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6111
6112     DeleteFileA("import.idt");
6113
6114     query = "SELECT * FROM `Table`";
6115     r = MsiDatabaseOpenView(hdb, query, &hview);
6116     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6117
6118     r = MsiViewExecute(hview, 0);
6119     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6120
6121     r = MsiViewFetch(hview, &hrec);
6122     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6123
6124     size = MAX_PATH;
6125     r = MsiRecordGetString(hrec, 1, buf, &size);
6126     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6127     ok(!lstrcmp(buf, "This is a new 'string' ok"),
6128        "Expected \"This is a new 'string' ok\", got %s\n", buf);
6129
6130     MsiCloseHandle(hrec);
6131
6132     r = MsiViewFetch(hview, &hrec);
6133     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6134
6135     MsiViewClose(hview);
6136     MsiCloseHandle(hview);
6137     MsiCloseHandle(hdb);
6138     DeleteFileA(msifile);
6139 }
6140
6141 static void test_carriagereturn(void)
6142 {
6143     MSIHANDLE hdb, hview, hrec;
6144     const char *query;
6145     char buf[MAX_PATH];
6146     UINT r;
6147     DWORD size;
6148
6149     DeleteFile(msifile);
6150
6151     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
6152     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6153
6154     query = "CREATE TABLE `Table`\r ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6155     r = run_query(hdb, 0, query);
6156     ok(r == ERROR_BAD_QUERY_SYNTAX,
6157        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6158
6159     query = "CREATE TABLE `Table` \r( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6160     r = run_query(hdb, 0, query);
6161     ok(r == ERROR_BAD_QUERY_SYNTAX,
6162        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6163
6164     query = "CREATE\r TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6165     r = run_query(hdb, 0, query);
6166     ok(r == ERROR_BAD_QUERY_SYNTAX,
6167        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6168
6169     query = "CREATE TABLE\r `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6170     r = run_query(hdb, 0, query);
6171     ok(r == ERROR_BAD_QUERY_SYNTAX,
6172        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6173
6174     query = "CREATE TABLE `Table` (\r `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6175     r = run_query(hdb, 0, query);
6176     ok(r == ERROR_BAD_QUERY_SYNTAX,
6177        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6178
6179     query = "CREATE TABLE `Table` ( `A`\r CHAR(72) NOT NULL PRIMARY KEY `A` )";
6180     r = run_query(hdb, 0, query);
6181     ok(r == ERROR_BAD_QUERY_SYNTAX,
6182        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6183
6184     query = "CREATE TABLE `Table` ( `A` CHAR(72)\r NOT NULL PRIMARY KEY `A` )";
6185     r = run_query(hdb, 0, query);
6186     ok(r == ERROR_BAD_QUERY_SYNTAX,
6187        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6188
6189     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT\r NULL PRIMARY KEY `A` )";
6190     r = run_query(hdb, 0, query);
6191     ok(r == ERROR_BAD_QUERY_SYNTAX,
6192        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6193
6194     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT \rNULL PRIMARY KEY `A` )";
6195     r = run_query(hdb, 0, query);
6196     ok(r == ERROR_BAD_QUERY_SYNTAX,
6197        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6198
6199     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL\r PRIMARY KEY `A` )";
6200     r = run_query(hdb, 0, query);
6201     ok(r == ERROR_BAD_QUERY_SYNTAX,
6202        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6203
6204     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL \rPRIMARY KEY `A` )";
6205     r = run_query(hdb, 0, query);
6206     ok(r == ERROR_BAD_QUERY_SYNTAX,
6207        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6208
6209     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY\r KEY `A` )";
6210     r = run_query(hdb, 0, query);
6211     ok(r == ERROR_BAD_QUERY_SYNTAX,
6212        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6213
6214     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY \rKEY `A` )";
6215     r = run_query(hdb, 0, query);
6216     ok(r == ERROR_BAD_QUERY_SYNTAX,
6217        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6218
6219     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY\r `A` )";
6220     r = run_query(hdb, 0, query);
6221     ok(r == ERROR_BAD_QUERY_SYNTAX,
6222        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6223
6224     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A`\r )";
6225     r = run_query(hdb, 0, query);
6226     ok(r == ERROR_BAD_QUERY_SYNTAX,
6227        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6228
6229     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )\r";
6230     r = run_query(hdb, 0, query);
6231     ok(r == ERROR_BAD_QUERY_SYNTAX,
6232        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6233
6234     query = "CREATE TABLE `\rOne` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6235     r = run_query(hdb, 0, query);
6236     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6237
6238     query = "CREATE TABLE `Tw\ro` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6239     r = run_query(hdb, 0, query);
6240     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6241
6242     query = "CREATE TABLE `Three\r` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6243     r = run_query(hdb, 0, query);
6244     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6245
6246     query = "CREATE TABLE `Four` ( `A\r` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6247     r = run_query(hdb, 0, query);
6248     ok(r == ERROR_BAD_QUERY_SYNTAX,
6249        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6250
6251     query = "CREATE TABLE `Four` ( `\rA` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6252     r = run_query(hdb, 0, query);
6253     ok(r == ERROR_BAD_QUERY_SYNTAX,
6254        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6255
6256     query = "CREATE TABLE `Four` ( `A` CHAR(72\r) NOT NULL PRIMARY KEY `A` )";
6257     r = run_query(hdb, 0, query);
6258     ok(r == ERROR_BAD_QUERY_SYNTAX,
6259        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6260
6261     query = "CREATE TABLE `Four` ( `A` CHAR(\r72) NOT NULL PRIMARY KEY `A` )";
6262     r = run_query(hdb, 0, query);
6263     ok(r == ERROR_BAD_QUERY_SYNTAX,
6264        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6265
6266     query = "CREATE TABLE `Four` ( `A` CHAR(72) NOT NULL PRIMARY KEY `\rA` )";
6267     r = run_query(hdb, 0, query);
6268     ok(r == ERROR_BAD_QUERY_SYNTAX,
6269        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6270
6271     query = "CREATE TABLE `Four` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A\r` )";
6272     r = run_query(hdb, 0, query);
6273     ok(r == ERROR_BAD_QUERY_SYNTAX,
6274        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6275
6276     query = "CREATE TABLE `Four` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A\r` )";
6277     r = run_query(hdb, 0, query);
6278     ok(r == ERROR_BAD_QUERY_SYNTAX,
6279        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6280
6281     query = "SELECT * FROM `_Tables`";
6282     r = MsiDatabaseOpenView(hdb, query, &hview);
6283     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6284     r = MsiViewExecute(hview, 0);
6285     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6286
6287     r = MsiViewFetch(hview, &hrec);
6288     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6289
6290     size = MAX_PATH;
6291     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6292     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6293     ok(!lstrcmpA(buf, "\rOne"), "Expected \"\\rOne\", got \"%s\"\n", buf);
6294
6295     MsiCloseHandle(hrec);
6296
6297     r = MsiViewFetch(hview, &hrec);
6298     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6299
6300     size = MAX_PATH;
6301     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6302     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6303     ok(!lstrcmpA(buf, "Tw\ro"), "Expected \"Tw\\ro\", got \"%s\"\n", buf);
6304
6305     MsiCloseHandle(hrec);
6306
6307     r = MsiViewFetch(hview, &hrec);
6308     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6309
6310     size = MAX_PATH;
6311     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6312     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6313     ok(!lstrcmpA(buf, "Three\r"), "Expected \"Three\r\", got \"%s\"\n", buf);
6314
6315     MsiCloseHandle(hrec);
6316
6317     r = MsiViewFetch(hview, &hrec);
6318     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6319
6320     MsiViewClose(hview);
6321     MsiCloseHandle(hview);
6322
6323     MsiCloseHandle(hdb);
6324     DeleteFileA(msifile);
6325 }
6326
6327 static void test_noquotes(void)
6328 {
6329     MSIHANDLE hdb, hview, hrec;
6330     const char *query;
6331     char buf[MAX_PATH];
6332     UINT r;
6333     DWORD size;
6334
6335     DeleteFile(msifile);
6336
6337     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
6338     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6339
6340     query = "CREATE TABLE Table ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6341     r = run_query(hdb, 0, query);
6342     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6343
6344     query = "CREATE TABLE `Table` ( A CHAR(72) NOT NULL PRIMARY KEY `A` )";
6345     r = run_query(hdb, 0, query);
6346     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6347
6348     query = "CREATE TABLE `Table2` ( `A` CHAR(72) NOT NULL PRIMARY KEY A )";
6349     r = run_query(hdb, 0, query);
6350     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6351
6352     query = "CREATE TABLE `Table3` ( A CHAR(72) NOT NULL PRIMARY KEY A )";
6353     r = run_query(hdb, 0, query);
6354     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6355
6356     query = "SELECT * FROM `_Tables`";
6357     r = MsiDatabaseOpenView(hdb, query, &hview);
6358     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6359     r = MsiViewExecute(hview, 0);
6360     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6361
6362     r = MsiViewFetch(hview, &hrec);
6363     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6364
6365     size = MAX_PATH;
6366     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6367     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6368     ok(!lstrcmpA(buf, "Table"), "Expected \"Table\", got \"%s\"\n", buf);
6369
6370     MsiCloseHandle(hrec);
6371
6372     r = MsiViewFetch(hview, &hrec);
6373     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6374
6375     size = MAX_PATH;
6376     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6377     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6378     ok(!lstrcmpA(buf, "Table2"), "Expected \"Table2\", got \"%s\"\n", buf);
6379
6380     MsiCloseHandle(hrec);
6381
6382     r = MsiViewFetch(hview, &hrec);
6383     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6384
6385     size = MAX_PATH;
6386     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6387     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6388     ok(!lstrcmpA(buf, "Table3"), "Expected \"Table3\", got \"%s\"\n", buf);
6389
6390     MsiCloseHandle(hrec);
6391
6392     r = MsiViewFetch(hview, &hrec);
6393     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6394
6395     MsiViewClose(hview);
6396     MsiCloseHandle(hview);
6397
6398     query = "SELECT * FROM `_Columns`";
6399     r = MsiDatabaseOpenView(hdb, query, &hview);
6400     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6401     r = MsiViewExecute(hview, 0);
6402     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6403
6404     r = MsiViewFetch(hview, &hrec);
6405     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6406
6407     size = MAX_PATH;
6408     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6409     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6410     ok(!lstrcmpA(buf, "Table"), "Expected \"Table\", got \"%s\"\n", buf);
6411
6412     r = MsiRecordGetInteger(hrec, 2);
6413     ok(r == 1, "Expected 1, got %d\n", r);
6414
6415     size = MAX_PATH;
6416     r = MsiRecordGetStringA(hrec, 3, buf, &size);
6417     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6418     ok(!lstrcmpA(buf, "A"), "Expected \"A\", got \"%s\"\n", buf);
6419
6420     MsiCloseHandle(hrec);
6421
6422     r = MsiViewFetch(hview, &hrec);
6423     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6424
6425     size = MAX_PATH;
6426     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6427     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6428     ok(!lstrcmpA(buf, "Table2"), "Expected \"Table2\", got \"%s\"\n", buf);
6429
6430     r = MsiRecordGetInteger(hrec, 2);
6431     ok(r == 1, "Expected 1, got %d\n", r);
6432
6433     size = MAX_PATH;
6434     r = MsiRecordGetStringA(hrec, 3, buf, &size);
6435     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6436     ok(!lstrcmpA(buf, "A"), "Expected \"A\", got \"%s\"\n", buf);
6437
6438     MsiCloseHandle(hrec);
6439
6440     r = MsiViewFetch(hview, &hrec);
6441     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6442
6443     size = MAX_PATH;
6444     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6445     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6446     ok(!lstrcmpA(buf, "Table3"), "Expected \"Table3\", got \"%s\"\n", buf);
6447
6448     r = MsiRecordGetInteger(hrec, 2);
6449     ok(r == 1, "Expected 1, got %d\n", r);
6450
6451     size = MAX_PATH;
6452     r = MsiRecordGetStringA(hrec, 3, buf, &size);
6453     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6454     ok(!lstrcmpA(buf, "A"), "Expected \"A\", got \"%s\"\n", buf);
6455
6456     MsiCloseHandle(hrec);
6457
6458     r = MsiViewFetch(hview, &hrec);
6459     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6460
6461     MsiViewClose(hview);
6462     MsiCloseHandle(hview);
6463
6464     query = "INSERT INTO Table ( `A` ) VALUES ( 'hi' )";
6465     r = run_query(hdb, 0, query);
6466     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6467
6468     query = "INSERT INTO `Table` ( A ) VALUES ( 'hi' )";
6469     r = run_query(hdb, 0, query);
6470     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6471
6472     query = "INSERT INTO `Table` ( `A` ) VALUES ( hi )";
6473     r = run_query(hdb, 0, query);
6474     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6475
6476     query = "SELECT * FROM Table WHERE `A` = 'hi'";
6477     r = run_query(hdb, 0, query);
6478     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6479
6480     query = "SELECT * FROM `Table` WHERE `A` = hi";
6481     r = run_query(hdb, 0, query);
6482     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6483
6484     query = "SELECT * FROM Table";
6485     r = run_query(hdb, 0, query);
6486     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6487
6488     query = "SELECT * FROM Table2";
6489     r = MsiDatabaseOpenView(hdb, query, &hview);
6490     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6491     r = MsiViewExecute(hview, 0);
6492     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6493
6494     r = MsiViewFetch(hview, &hrec);
6495     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6496
6497     MsiViewClose(hview);
6498     MsiCloseHandle(hview);
6499
6500     query = "SELECT * FROM `Table` WHERE A = 'hi'";
6501     r = MsiDatabaseOpenView(hdb, query, &hview);
6502     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6503     r = MsiViewExecute(hview, 0);
6504     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6505
6506     r = MsiViewFetch(hview, &hrec);
6507     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6508
6509     size = MAX_PATH;
6510     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6511     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6512     ok(!lstrcmpA(buf, "hi"), "Expected \"hi\", got \"%s\"\n", buf);
6513
6514     MsiCloseHandle(hrec);
6515
6516     r = MsiViewFetch(hview, &hrec);
6517     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6518
6519     MsiViewClose(hview);
6520     MsiCloseHandle(hview);
6521     MsiCloseHandle(hdb);
6522     DeleteFileA(msifile);
6523 }
6524
6525 static void read_file_data(LPCSTR filename, LPSTR buffer)
6526 {
6527     HANDLE file;
6528     DWORD read;
6529
6530     file = CreateFileA( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
6531     ZeroMemory(buffer, MAX_PATH);
6532     ReadFile(file, buffer, MAX_PATH, &read, NULL);
6533     CloseHandle(file);
6534 }
6535
6536 static void test_forcecodepage(void)
6537 {
6538     MSIHANDLE hdb;
6539     const char *query;
6540     char buffer[MAX_PATH];
6541     UINT r;
6542
6543     DeleteFile(msifile);
6544
6545     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
6546     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6547
6548     query = "SELECT * FROM `_ForceCodepage`";
6549     r = run_query(hdb, 0, query);
6550     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6551
6552     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6553     r = run_query(hdb, 0, query);
6554     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6555
6556     query = "SELECT * FROM `_ForceCodepage`";
6557     r = run_query(hdb, 0, query);
6558     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6559
6560     r = MsiDatabaseCommit(hdb);
6561     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6562
6563     query = "SELECT * FROM `_ForceCodepage`";
6564     r = run_query(hdb, 0, query);
6565     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6566
6567     MsiCloseHandle(hdb);
6568
6569     r = MsiOpenDatabase(msifile, MSIDBOPEN_DIRECT, &hdb);
6570     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6571
6572     query = "SELECT * FROM `_ForceCodepage`";
6573     r = run_query(hdb, 0, query);
6574     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6575
6576     r = MsiDatabaseExport(hdb, "_ForceCodepage", CURR_DIR, "forcecodepage.idt");
6577     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6578
6579     read_file_data("forcecodepage.idt", buffer);
6580     ok(!lstrcmpA(buffer, "\r\n\r\n0\t_ForceCodepage\r\n"),
6581        "Expected \"\r\n\r\n0\t_ForceCodepage\r\n\", got \"%s\"", buffer);
6582
6583     MsiCloseHandle(hdb);
6584     DeleteFileA(msifile);
6585     DeleteFileA("forcecodepage.idt");
6586 }
6587
6588 static void test_viewmodify_refresh(void)
6589 {
6590     MSIHANDLE hdb, hview, hrec;
6591     const char *query;
6592     char buffer[MAX_PATH];
6593     UINT r;
6594     DWORD size;
6595
6596     DeleteFile(msifile);
6597
6598     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
6599     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6600
6601     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL, `B` INT PRIMARY KEY `A` )";
6602     r = run_query(hdb, 0, query);
6603     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6604
6605     query = "INSERT INTO `Table` ( `A`, `B` ) VALUES ( 'hi', 1 )";
6606     r = run_query(hdb, 0, query);
6607     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6608
6609     query = "SELECT * FROM `Table`";
6610     r = MsiDatabaseOpenView(hdb, query, &hview);
6611     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6612     r = MsiViewExecute(hview, 0);
6613     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6614
6615     r = MsiViewFetch(hview, &hrec);
6616     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6617
6618     query = "UPDATE `Table` SET `B` = 2 WHERE `A` = 'hi'";
6619     r = run_query(hdb, 0, query);
6620     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6621
6622     r = MsiViewModify(hview, MSIMODIFY_REFRESH, hrec);
6623     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6624
6625     size = MAX_PATH;
6626     r = MsiRecordGetStringA(hrec, 1, buffer, &size);
6627     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6628     ok(!lstrcmpA(buffer, "hi"), "Expected \"hi\", got \"%s\"\n", buffer);
6629     ok(size == 2, "Expected 2, got %d\n", size);
6630
6631     r = MsiRecordGetInteger(hrec, 2);
6632     ok(r == 2, "Expected 2, got %d\n", r);
6633
6634     MsiCloseHandle(hrec);
6635     MsiViewClose(hview);
6636     MsiCloseHandle(hview);
6637
6638     query = "INSERT INTO `Table` ( `A`, `B` ) VALUES ( 'hello', 3 )";
6639     r = run_query(hdb, 0, query);
6640     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6641
6642     query = "SELECT * FROM `Table` WHERE `B` = 3";
6643     r = MsiDatabaseOpenView(hdb, query, &hview);
6644     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6645     r = MsiViewExecute(hview, 0);
6646     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6647
6648     r = MsiViewFetch(hview, &hrec);
6649     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6650
6651     query = "UPDATE `Table` SET `B` = 2 WHERE `A` = 'hello'";
6652     r = run_query(hdb, 0, query);
6653     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6654
6655     query = "INSERT INTO `Table` ( `A`, `B` ) VALUES ( 'hithere', 3 )";
6656     r = run_query(hdb, 0, query);
6657     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6658
6659     r = MsiViewModify(hview, MSIMODIFY_REFRESH, hrec);
6660     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6661
6662     size = MAX_PATH;
6663     r = MsiRecordGetStringA(hrec, 1, buffer, &size);
6664     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6665     ok(!lstrcmpA(buffer, "hello"), "Expected \"hello\", got \"%s\"\n", buffer);
6666     ok(size == 5, "Expected 5, got %d\n", size);
6667
6668     r = MsiRecordGetInteger(hrec, 2);
6669     ok(r == 2, "Expected 2, got %d\n", r);
6670
6671     MsiCloseHandle(hrec);
6672     MsiViewClose(hview);
6673     MsiCloseHandle(hview);
6674     MsiCloseHandle(hdb);
6675     DeleteFileA(msifile);
6676 }
6677
6678 static void test_where_viewmodify(void)
6679 {
6680     MSIHANDLE hdb, hview, hrec;
6681     const char *query;
6682     UINT r;
6683
6684     DeleteFile(msifile);
6685
6686     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
6687     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6688
6689     query = "CREATE TABLE `Table` ( `A` INT, `B` INT PRIMARY KEY `A` )";
6690     r = run_query(hdb, 0, query);
6691     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6692
6693     query = "INSERT INTO `Table` ( `A`, `B` ) VALUES ( 1, 2 )";
6694     r = run_query(hdb, 0, query);
6695     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6696
6697     query = "INSERT INTO `Table` ( `A`, `B` ) VALUES ( 3, 4 )";
6698     r = run_query(hdb, 0, query);
6699     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6700
6701     query = "INSERT INTO `Table` ( `A`, `B` ) VALUES ( 5, 6 )";
6702     r = run_query(hdb, 0, query);
6703     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6704
6705     /* `B` = 3 doesn't match, but the view shouldn't be executed */
6706     query = "SELECT * FROM `Table` WHERE `B` = 3";
6707     r = MsiDatabaseOpenView(hdb, query, &hview);
6708     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6709
6710     hrec = MsiCreateRecord(2);
6711     MsiRecordSetInteger(hrec, 1, 7);
6712     MsiRecordSetInteger(hrec, 2, 8);
6713
6714     r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec);
6715     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6716
6717     MsiCloseHandle(hrec);
6718     MsiViewClose(hview);
6719     MsiCloseHandle(hview);
6720
6721     query = "SELECT * FROM `Table` WHERE `A` = 7";
6722     r = MsiDatabaseOpenView(hdb, query, &hview);
6723     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6724     r = MsiViewExecute(hview, 0);
6725     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6726
6727     r = MsiViewFetch(hview, &hrec);
6728     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6729
6730     r = MsiRecordGetInteger(hrec, 1);
6731     ok(r == 7, "Expected 7, got %d\n", r);
6732
6733     r = MsiRecordGetInteger(hrec, 2);
6734     ok(r == 8, "Expected 8, got %d\n", r);
6735
6736     MsiRecordSetInteger(hrec, 2, 9);
6737
6738     r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
6739     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6740
6741     MsiCloseHandle(hrec);
6742     MsiViewClose(hview);
6743     MsiCloseHandle(hview);
6744
6745     query = "SELECT * FROM `Table` WHERE `A` = 7";
6746     r = MsiDatabaseOpenView(hdb, query, &hview);
6747     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6748     r = MsiViewExecute(hview, 0);
6749     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6750
6751     r = MsiViewFetch(hview, &hrec);
6752     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6753
6754     r = MsiRecordGetInteger(hrec, 1);
6755     ok(r == 7, "Expected 7, got %d\n", r);
6756
6757     r = MsiRecordGetInteger(hrec, 2);
6758     ok(r == 9, "Expected 9, got %d\n", r);
6759
6760     query = "UPDATE `Table` SET `B` = 10 WHERE `A` = 7";
6761     r = run_query(hdb, 0, query);
6762     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6763
6764     r = MsiViewModify(hview, MSIMODIFY_REFRESH, hrec);
6765     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6766
6767     r = MsiRecordGetInteger(hrec, 1);
6768     ok(r == 7, "Expected 7, got %d\n", r);
6769
6770     r = MsiRecordGetInteger(hrec, 2);
6771     ok(r == 10, "Expected 10, got %d\n", r);
6772
6773     MsiCloseHandle(hrec);
6774     MsiViewClose(hview);
6775     MsiCloseHandle(hview);
6776     MsiCloseHandle(hdb);
6777 }
6778
6779 static BOOL create_storage(LPCSTR name)
6780 {
6781     WCHAR nameW[MAX_PATH];
6782     IStorage *stg;
6783     IStream *stm;
6784     HRESULT hr;
6785     DWORD count;
6786     BOOL res = FALSE;
6787
6788     MultiByteToWideChar(CP_ACP, 0, name, -1, nameW, MAX_PATH);
6789     hr = StgCreateDocfile(nameW, STGM_CREATE | STGM_READWRITE |
6790                           STGM_DIRECT | STGM_SHARE_EXCLUSIVE, 0, &stg);
6791     if (FAILED(hr))
6792         return FALSE;
6793
6794     hr = IStorage_CreateStream(stg, nameW, STGM_WRITE | STGM_SHARE_EXCLUSIVE,
6795                                0, 0, &stm);
6796     if (FAILED(hr))
6797         goto done;
6798
6799     hr = IStream_Write(stm, "stgdata", 8, &count);
6800     if (SUCCEEDED(hr))
6801         res = TRUE;
6802
6803 done:
6804     IStream_Release(stm);
6805     IStorage_Release(stg);
6806
6807     return res;
6808 }
6809
6810 static void test_storages_table(void)
6811 {
6812     MSIHANDLE hdb, hview, hrec;
6813     IStorage *stg, *inner;
6814     IStream *stm;
6815     char file[MAX_PATH];
6816     char buf[MAX_PATH];
6817     WCHAR name[MAX_PATH];
6818     LPCSTR query;
6819     HRESULT hr;
6820     DWORD size;
6821     UINT r;
6822
6823     hdb = create_db();
6824     ok(hdb, "failed to create db\n");
6825
6826     r = MsiDatabaseCommit(hdb);
6827     ok(r == ERROR_SUCCESS , "Failed to commit database\n");
6828
6829     MsiCloseHandle(hdb);
6830
6831     r = MsiOpenDatabase(msifile, MSIDBOPEN_TRANSACT, &hdb);
6832     ok(r == ERROR_SUCCESS , "Failed to open database\n");
6833
6834     /* check the column types */
6835     hrec = get_column_info(hdb, "SELECT * FROM `_Storages`", MSICOLINFO_TYPES);
6836     ok(hrec, "failed to get column info hrecord\n");
6837     ok(check_record(hrec, 1, "s62"), "wrong hrecord type\n");
6838     ok(check_record(hrec, 2, "V0"), "wrong hrecord type\n");
6839
6840     MsiCloseHandle(hrec);
6841
6842     /* now try the names */
6843     hrec = get_column_info(hdb, "SELECT * FROM `_Storages`", MSICOLINFO_NAMES);
6844     ok(hrec, "failed to get column info hrecord\n");
6845     ok(check_record(hrec, 1, "Name"), "wrong hrecord type\n");
6846     ok(check_record(hrec, 2, "Data"), "wrong hrecord type\n");
6847
6848     MsiCloseHandle(hrec);
6849
6850     create_storage("storage.bin");
6851
6852     hrec = MsiCreateRecord(2);
6853     MsiRecordSetString(hrec, 1, "stgname");
6854
6855     r = MsiRecordSetStream(hrec, 2, "storage.bin");
6856     ok(r == ERROR_SUCCESS, "Failed to add stream data to the hrecord: %d\n", r);
6857
6858     DeleteFileA("storage.bin");
6859
6860     query = "INSERT INTO `_Storages` (`Name`, `Data`) VALUES (?, ?)";
6861     r = MsiDatabaseOpenView(hdb, query, &hview);
6862     ok(r == ERROR_SUCCESS, "Failed to open database hview: %d\n", r);
6863
6864     r = MsiViewExecute(hview, hrec);
6865     ok(r == ERROR_SUCCESS, "Failed to execute hview: %d\n", r);
6866
6867     MsiCloseHandle(hrec);
6868     MsiViewClose(hview);
6869     MsiCloseHandle(hview);
6870
6871     query = "SELECT `Name`, `Data` FROM `_Storages`";
6872     r = MsiDatabaseOpenView(hdb, query, &hview);
6873     ok(r == ERROR_SUCCESS, "Failed to open database hview: %d\n", r);
6874
6875     r = MsiViewExecute(hview, 0);
6876     ok(r == ERROR_SUCCESS, "Failed to execute hview: %d\n", r);
6877
6878     r = MsiViewFetch(hview, &hrec);
6879     ok(r == ERROR_SUCCESS, "Failed to fetch hrecord: %d\n", r);
6880
6881     size = MAX_PATH;
6882     r = MsiRecordGetString(hrec, 1, file, &size);
6883     ok(r == ERROR_SUCCESS, "Failed to get string: %d\n", r);
6884     ok(!lstrcmp(file, "stgname"), "Expected \"stgname\", got \"%s\"\n", file);
6885
6886     size = MAX_PATH;
6887     lstrcpyA(buf, "apple");
6888     r = MsiRecordReadStream(hrec, 2, buf, &size);
6889     ok(r == ERROR_INVALID_DATA, "Expected ERROR_INVALID_DATA, got %d\n", r);
6890     ok(!lstrcmp(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf);
6891     ok(size == 0, "Expected 0, got %d\n", size);
6892
6893     MsiCloseHandle(hrec);
6894
6895     r = MsiViewFetch(hview, &hrec);
6896     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6897
6898     MsiViewClose(hview);
6899     MsiCloseHandle(hview);
6900
6901     MsiDatabaseCommit(hdb);
6902     MsiCloseHandle(hdb);
6903
6904     MultiByteToWideChar(CP_ACP, 0, msifile, -1, name, MAX_PATH);
6905     hr = StgOpenStorage(name, NULL, STGM_DIRECT | STGM_READ |
6906                         STGM_SHARE_DENY_WRITE, NULL, 0, &stg);
6907     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
6908     ok(stg != NULL, "Expected non-NULL storage\n");
6909
6910     MultiByteToWideChar(CP_ACP, 0, "stgname", -1, name, MAX_PATH);
6911     hr = IStorage_OpenStorage(stg, name, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE,
6912                               NULL, 0, &inner);
6913     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
6914     ok(inner != NULL, "Expected non-NULL storage\n");
6915
6916     MultiByteToWideChar(CP_ACP, 0, "storage.bin", -1, name, MAX_PATH);
6917     hr = IStorage_OpenStream(inner, name, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm);
6918     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
6919     ok(stm != NULL, "Expected non-NULL stream\n");
6920
6921     hr = IStream_Read(stm, buf, MAX_PATH, &size);
6922     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
6923     ok(size == 8, "Expected 8, got %d\n", size);
6924     ok(!lstrcmpA(buf, "stgdata"), "Expected \"stgdata\", got \"%s\"\n", buf);
6925
6926     IStream_Release(stm);
6927     IStorage_Release(inner);
6928
6929     IStorage_Release(stg);
6930     DeleteFileA(msifile);
6931 }
6932
6933 static void test_dbtopackage(void)
6934 {
6935     MSIHANDLE hdb, hpkg;
6936     CHAR package[10];
6937     CHAR buf[MAX_PATH];
6938     DWORD size;
6939     UINT r;
6940
6941     /* create an empty database, transact mode */
6942     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
6943     ok(r == ERROR_SUCCESS, "Failed to create database\n");
6944
6945     set_summary_info(hdb);
6946
6947     r = create_directory_table(hdb);
6948     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6949
6950     r = create_custom_action_table(hdb);
6951     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6952
6953     r = add_custom_action_entry(hdb, "'SetProp', 51, 'MYPROP', 'grape'");
6954     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6955
6956     sprintf(package, "#%i", hdb);
6957     r = MsiOpenPackage(package, &hpkg);
6958     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6959
6960     /* property is not set yet */
6961     size = MAX_PATH;
6962     lstrcpyA(buf, "kiwi");
6963     r = MsiGetProperty(hpkg, "MYPROP", buf, &size);
6964     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6965     ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf);
6966     ok(size == 0, "Expected 0, got %d\n", size);
6967
6968     /* run the custom action to set the property */
6969     r = MsiDoAction(hpkg, "SetProp");
6970     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6971
6972     /* property is now set */
6973     size = MAX_PATH;
6974     lstrcpyA(buf, "kiwi");
6975     r = MsiGetProperty(hpkg, "MYPROP", buf, &size);
6976     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6977     ok(!lstrcmpA(buf, "grape"), "Expected \"grape\", got \"%s\"\n", buf);
6978     ok(size == 5, "Expected 5, got %d\n", size);
6979
6980     MsiCloseHandle(hpkg);
6981
6982     /* reset the package */
6983     r = MsiOpenPackage(package, &hpkg);
6984     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6985
6986     /* property is not set anymore */
6987     size = MAX_PATH;
6988     lstrcpyA(buf, "kiwi");
6989     r = MsiGetProperty(hpkg, "MYPROP", buf, &size);
6990     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6991     todo_wine
6992     {
6993         ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf);
6994         ok(size == 0, "Expected 0, got %d\n", size);
6995     }
6996
6997     MsiCloseHandle(hdb);
6998     MsiCloseHandle(hpkg);
6999
7000     /* create an empty database, direct mode */
7001     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATEDIRECT, &hdb);
7002     ok(r == ERROR_SUCCESS, "Failed to create database\n");
7003
7004     set_summary_info(hdb);
7005
7006     r = create_directory_table(hdb);
7007     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7008
7009     r = create_custom_action_table(hdb);
7010     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7011
7012     r = add_custom_action_entry(hdb, "'SetProp', 51, 'MYPROP', 'grape'");
7013     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7014
7015     sprintf(package, "#%i", hdb);
7016     r = MsiOpenPackage(package, &hpkg);
7017     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7018
7019     /* property is not set yet */
7020     size = MAX_PATH;
7021     lstrcpyA(buf, "kiwi");
7022     r = MsiGetProperty(hpkg, "MYPROP", buf, &size);
7023     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7024     ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf);
7025     ok(size == 0, "Expected 0, got %d\n", size);
7026
7027     /* run the custom action to set the property */
7028     r = MsiDoAction(hpkg, "SetProp");
7029     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7030
7031     /* property is now set */
7032     size = MAX_PATH;
7033     lstrcpyA(buf, "kiwi");
7034     r = MsiGetProperty(hpkg, "MYPROP", buf, &size);
7035     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7036     ok(!lstrcmpA(buf, "grape"), "Expected \"grape\", got \"%s\"\n", buf);
7037     ok(size == 5, "Expected 5, got %d\n", size);
7038
7039     MsiCloseHandle(hpkg);
7040
7041     /* reset the package */
7042     r = MsiOpenPackage(package, &hpkg);
7043     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7044
7045     /* property is not set anymore */
7046     size = MAX_PATH;
7047     lstrcpyA(buf, "kiwi");
7048     r = MsiGetProperty(hpkg, "MYPROP", buf, &size);
7049     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7050     todo_wine
7051     {
7052         ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf);
7053         ok(size == 0, "Expected 0, got %d\n", size);
7054     }
7055
7056     MsiCloseHandle(hdb);
7057     MsiCloseHandle(hpkg);
7058     DeleteFileA(msifile);
7059 }
7060
7061 static void test_droptable(void)
7062 {
7063     MSIHANDLE hdb, hview, hrec;
7064     CHAR buf[MAX_PATH];
7065     LPCSTR query;
7066     DWORD size;
7067     UINT r;
7068
7069     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
7070     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7071
7072     query = "CREATE TABLE `One` ( `A` 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 = "SELECT * FROM `One`";
7077     r = do_query(hdb, query, &hrec);
7078     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7079
7080     query = "SELECT * FROM `_Tables` WHERE `Name` = 'One'";
7081     r = MsiDatabaseOpenViewA(hdb, query, &hview);
7082     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7083     r = MsiViewExecute(hview, 0);
7084     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7085
7086     r = MsiViewFetch(hview, &hrec);
7087     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7088
7089     size = MAX_PATH;
7090     r = MsiRecordGetStringA(hrec, 1, buf, &size);
7091     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7092     ok(!lstrcmpA(buf, "One"), "Expected \"One\", got \"%s\"\n", buf);
7093
7094     MsiCloseHandle(hrec);
7095     MsiViewClose(hview);
7096     MsiCloseHandle(hview);
7097
7098     query = "SELECT * FROM `_Columns` WHERE `Table` = 'One'";
7099     r = MsiDatabaseOpenViewA(hdb, query, &hview);
7100     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7101     r = MsiViewExecute(hview, 0);
7102     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7103
7104     r = MsiViewFetch(hview, &hrec);
7105     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7106
7107     size = MAX_PATH;
7108     r = MsiRecordGetStringA(hrec, 1, buf, &size);
7109     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7110     ok(!lstrcmpA(buf, "One"), "Expected \"One\", got \"%s\"\n", buf);
7111
7112     r = MsiRecordGetInteger(hrec, 2);
7113     ok(r == 1, "Expected 1, got %d\n", r);
7114
7115     size = MAX_PATH;
7116     r = MsiRecordGetStringA(hrec, 3, buf, &size);
7117     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7118     ok(!lstrcmpA(buf, "A"), "Expected \"A\", got \"%s\"\n", buf);
7119
7120     MsiCloseHandle(hrec);
7121
7122     r = MsiViewFetch(hview, &hrec);
7123     ok(r == ERROR_NO_MORE_ITEMS,
7124        "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7125
7126     MsiViewClose(hview);
7127     MsiCloseHandle(hview);
7128
7129     query = "DROP `One`";
7130     r = run_query(hdb, 0, query);
7131     ok(r == ERROR_BAD_QUERY_SYNTAX,
7132        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7133
7134     query = "DROP TABLE";
7135     r = run_query(hdb, 0, query);
7136     ok(r == ERROR_BAD_QUERY_SYNTAX,
7137        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7138
7139     query = "DROP TABLE `One`";
7140     hview = 0;
7141     r = MsiDatabaseOpenViewA(hdb, query, &hview);
7142     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7143     r = MsiViewExecute(hview, 0);
7144     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7145
7146     r = MsiViewFetch(hview, &hrec);
7147     ok(r == ERROR_FUNCTION_FAILED,
7148        "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
7149
7150     MsiViewClose(hview);
7151     MsiCloseHandle(hview);
7152
7153     query = "SELECT * FROM `IDontExist`";
7154     r = do_query(hdb, query, &hrec);
7155     ok(r == ERROR_BAD_QUERY_SYNTAX,
7156        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7157
7158     query = "SELECT * FROM `One`";
7159     r = do_query(hdb, query, &hrec);
7160     ok(r == ERROR_BAD_QUERY_SYNTAX,
7161        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7162
7163     query = "CREATE TABLE `One` ( `A` INT PRIMARY KEY `A` )";
7164     r = run_query(hdb, 0, query);
7165     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7166
7167     query = "DROP TABLE One";
7168     r = run_query(hdb, 0, query);
7169     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7170
7171     query = "SELECT * FROM `One`";
7172     r = do_query(hdb, query, &hrec);
7173     ok(r == ERROR_BAD_QUERY_SYNTAX,
7174        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7175
7176     query = "SELECT * FROM `_Tables` WHERE `Name` = 'One'";
7177     r = do_query(hdb, query, &hrec);
7178     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7179
7180     query = "SELECT * FROM `_Columns` WHERE `Table` = 'One'";
7181     r = do_query(hdb, query, &hrec);
7182     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7183
7184     query = "CREATE TABLE `One` ( `B` INT, `C` INT PRIMARY KEY `B` )";
7185     r = run_query(hdb, 0, query);
7186     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7187
7188     query = "SELECT * FROM `One`";
7189     r = do_query(hdb, query, &hrec);
7190     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7191
7192     query = "SELECT * FROM `_Tables` WHERE `Name` = 'One'";
7193     r = MsiDatabaseOpenViewA(hdb, query, &hview);
7194     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7195     r = MsiViewExecute(hview, 0);
7196     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7197
7198     r = MsiViewFetch(hview, &hrec);
7199     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7200
7201     size = MAX_PATH;
7202     r = MsiRecordGetStringA(hrec, 1, buf, &size);
7203     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7204     ok(!lstrcmpA(buf, "One"), "Expected \"One\", got \"%s\"\n", buf);
7205
7206     MsiCloseHandle(hrec);
7207     MsiViewClose(hview);
7208     MsiCloseHandle(hview);
7209
7210     query = "SELECT * FROM `_Columns` WHERE `Table` = 'One'";
7211     r = MsiDatabaseOpenViewA(hdb, query, &hview);
7212     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7213     r = MsiViewExecute(hview, 0);
7214     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7215
7216     r = MsiViewFetch(hview, &hrec);
7217     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7218
7219     size = MAX_PATH;
7220     r = MsiRecordGetStringA(hrec, 1, buf, &size);
7221     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7222     ok(!lstrcmpA(buf, "One"), "Expected \"One\", got \"%s\"\n", buf);
7223
7224     r = MsiRecordGetInteger(hrec, 2);
7225     ok(r == 1, "Expected 1, got %d\n", r);
7226
7227     size = MAX_PATH;
7228     r = MsiRecordGetStringA(hrec, 3, buf, &size);
7229     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7230     ok(!lstrcmpA(buf, "B"), "Expected \"B\", got \"%s\"\n", buf);
7231
7232     MsiCloseHandle(hrec);
7233
7234     r = MsiViewFetch(hview, &hrec);
7235     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7236
7237     size = MAX_PATH;
7238     r = MsiRecordGetStringA(hrec, 1, buf, &size);
7239     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7240     ok(!lstrcmpA(buf, "One"), "Expected \"One\", got \"%s\"\n", buf);
7241
7242     r = MsiRecordGetInteger(hrec, 2);
7243     ok(r == 2, "Expected 2, got %d\n", r);
7244
7245     size = MAX_PATH;
7246     r = MsiRecordGetStringA(hrec, 3, buf, &size);
7247     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7248     ok(!lstrcmpA(buf, "C"), "Expected \"C\", got \"%s\"\n", buf);
7249
7250     MsiCloseHandle(hrec);
7251
7252     r = MsiViewFetch(hview, &hrec);
7253     ok(r == ERROR_NO_MORE_ITEMS,
7254        "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7255
7256     MsiViewClose(hview);
7257     MsiCloseHandle(hview);
7258
7259     query = "DROP TABLE One";
7260     r = run_query(hdb, 0, query);
7261     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7262
7263     query = "SELECT * FROM `One`";
7264     r = do_query(hdb, query, &hrec);
7265     ok(r == ERROR_BAD_QUERY_SYNTAX,
7266        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7267
7268     query = "SELECT * FROM `_Tables` WHERE `Name` = 'One'";
7269     r = do_query(hdb, query, &hrec);
7270     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7271
7272     query = "SELECT * FROM `_Columns` WHERE `Table` = 'One'";
7273     r = do_query(hdb, query, &hrec);
7274     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7275
7276     MsiCloseHandle(hdb);
7277     DeleteFileA(msifile);
7278 }
7279
7280 static void test_dbmerge(void)
7281 {
7282     MSIHANDLE hdb, href, hview, hrec;
7283     CHAR buf[MAX_PATH];
7284     LPCSTR query;
7285     DWORD size;
7286     UINT r;
7287
7288     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
7289     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7290
7291     r = MsiOpenDatabase("refdb.msi", MSIDBOPEN_CREATE, &href);
7292     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7293
7294     /* hDatabase is invalid */
7295     r = MsiDatabaseMergeA(0, href, "MergeErrors");
7296     ok(r == ERROR_INVALID_HANDLE,
7297        "Expected ERROR_INVALID_HANDLE, got %d\n", r);
7298
7299     /* hDatabaseMerge is invalid */
7300     r = MsiDatabaseMergeA(hdb, 0, "MergeErrors");
7301     ok(r == ERROR_INVALID_HANDLE,
7302        "Expected ERROR_INVALID_HANDLE, got %d\n", r);
7303
7304     /* szTableName is NULL */
7305     r = MsiDatabaseMergeA(hdb, href, NULL);
7306     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7307
7308     /* szTableName is empty */
7309     r = MsiDatabaseMergeA(hdb, href, "");
7310     ok(r == ERROR_INVALID_TABLE, "Expected ERROR_INVALID_TABLE, got %d\n", r);
7311
7312     /* both DBs empty, szTableName is valid */
7313     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7314     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7315
7316     query = "CREATE TABLE `One` ( `A` INT PRIMARY KEY `A` )";
7317     r = run_query(hdb, 0, query);
7318     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7319
7320     query = "CREATE TABLE `One` ( `A` CHAR(72) PRIMARY KEY `A` )";
7321     r = run_query(href, 0, query);
7322     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7323
7324     /* column types don't match */
7325     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7326     ok(r == ERROR_DATATYPE_MISMATCH,
7327        "Expected ERROR_DATATYPE_MISMATCH, got %d\n", r);
7328
7329     /* nothing in MergeErrors */
7330     query = "SELECT * FROM `MergeErrors`";
7331     r = do_query(hdb, query, &hrec);
7332     ok(r == ERROR_BAD_QUERY_SYNTAX,
7333        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7334
7335     query = "DROP TABLE `One`";
7336     r = run_query(hdb, 0, query);
7337     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7338
7339     query = "DROP TABLE `One`";
7340     r = run_query(href, 0, query);
7341     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7342
7343     query = "CREATE TABLE `One` ( "
7344         "`A` CHAR(72), "
7345         "`B` CHAR(56), "
7346         "`C` CHAR(64) LOCALIZABLE, "
7347         "`D` LONGCHAR, "
7348         "`E` CHAR(72) NOT NULL, "
7349         "`F` CHAR(56) NOT NULL, "
7350         "`G` CHAR(64) NOT NULL LOCALIZABLE, "
7351         "`H` LONGCHAR NOT NULL "
7352         "PRIMARY KEY `A` )";
7353     r = run_query(hdb, 0, query);
7354     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7355
7356     query = "CREATE TABLE `One` ( "
7357         "`A` CHAR(64), "
7358         "`B` CHAR(64), "
7359         "`C` CHAR(64), "
7360         "`D` CHAR(64), "
7361         "`E` CHAR(64) NOT NULL, "
7362         "`F` CHAR(64) NOT NULL, "
7363         "`G` CHAR(64) NOT NULL, "
7364         "`H` CHAR(64) NOT NULL "
7365         "PRIMARY KEY `A` )";
7366     r = run_query(href, 0, query);
7367     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7368
7369     /* column sting types don't match exactly */
7370     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7371     ok(r == ERROR_SUCCESS,
7372        "Expected ERROR_SUCCESS, got %d\n", r);
7373
7374     /* nothing in MergeErrors */
7375     query = "SELECT * FROM `MergeErrors`";
7376     r = do_query(hdb, query, &hrec);
7377     ok(r == ERROR_BAD_QUERY_SYNTAX,
7378        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7379
7380     query = "DROP TABLE `One`";
7381     r = run_query(hdb, 0, query);
7382     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7383
7384     query = "DROP TABLE `One`";
7385     r = run_query(href, 0, query);
7386     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7387
7388     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A` )";
7389     r = run_query(hdb, 0, query);
7390     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7391
7392     query = "CREATE TABLE `One` ( `A` INT, `C` INT PRIMARY KEY `A` )";
7393     r = run_query(href, 0, query);
7394     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7395
7396     /* column names don't match */
7397     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7398     ok(r == ERROR_DATATYPE_MISMATCH,
7399        "Expected ERROR_DATATYPE_MISMATCH, got %d\n", r);
7400
7401     /* nothing in MergeErrors */
7402     query = "SELECT * FROM `MergeErrors`";
7403     r = do_query(hdb, query, &hrec);
7404     ok(r == ERROR_BAD_QUERY_SYNTAX,
7405        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7406
7407     query = "DROP TABLE `One`";
7408     r = run_query(hdb, 0, query);
7409     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7410
7411     query = "DROP TABLE `One`";
7412     r = run_query(href, 0, query);
7413     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7414
7415     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A` )";
7416     r = run_query(hdb, 0, query);
7417     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7418
7419     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `B` )";
7420     r = run_query(href, 0, query);
7421     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7422
7423     /* primary keys don't match */
7424     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7425     ok(r == ERROR_DATATYPE_MISMATCH,
7426        "Expected ERROR_DATATYPE_MISMATCH, got %d\n", r);
7427
7428     /* nothing in MergeErrors */
7429     query = "SELECT * FROM `MergeErrors`";
7430     r = do_query(hdb, query, &hrec);
7431     ok(r == ERROR_BAD_QUERY_SYNTAX,
7432        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7433
7434     query = "DROP TABLE `One`";
7435     r = run_query(hdb, 0, query);
7436     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7437
7438     query = "DROP TABLE `One`";
7439     r = run_query(href, 0, query);
7440     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7441
7442     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A` )";
7443     r = run_query(hdb, 0, query);
7444     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7445
7446     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A`, `B` )";
7447     r = run_query(href, 0, query);
7448     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7449
7450     /* number of primary keys doesn't match */
7451     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7452     ok(r == ERROR_DATATYPE_MISMATCH,
7453        "Expected ERROR_DATATYPE_MISMATCH, got %d\n", r);
7454
7455     /* nothing in MergeErrors */
7456     query = "SELECT * FROM `MergeErrors`";
7457     r = do_query(hdb, query, &hrec);
7458     ok(r == ERROR_BAD_QUERY_SYNTAX,
7459        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7460
7461     query = "DROP TABLE `One`";
7462     r = run_query(hdb, 0, query);
7463     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7464
7465     query = "DROP TABLE `One`";
7466     r = run_query(href, 0, query);
7467     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7468
7469     query = "CREATE TABLE `One` ( `A` INT, `B` INT, `C` INT PRIMARY KEY `A` )";
7470     r = run_query(hdb, 0, query);
7471     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7472
7473     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A` )";
7474     r = run_query(href, 0, query);
7475     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7476
7477     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 1, 2 )";
7478     r = run_query(href, 0, query);
7479     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7480
7481     /* number of columns doesn't match */
7482     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7483     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7484
7485     query = "SELECT * FROM `One`";
7486     r = do_query(hdb, query, &hrec);
7487     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7488
7489     r = MsiRecordGetInteger(hrec, 1);
7490     ok(r == 1, "Expected 1, got %d\n", r);
7491
7492     r = MsiRecordGetInteger(hrec, 2);
7493     ok(r == 2, "Expected 2, got %d\n", r);
7494
7495     r = MsiRecordGetInteger(hrec, 3);
7496     ok(r == MSI_NULL_INTEGER, "Expected MSI_NULL_INTEGER, got %d\n", r);
7497
7498     MsiCloseHandle(hrec);
7499
7500     /* nothing in MergeErrors */
7501     query = "SELECT * FROM `MergeErrors`";
7502     r = do_query(hdb, query, &hrec);
7503     ok(r == ERROR_BAD_QUERY_SYNTAX,
7504        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7505
7506     query = "DROP TABLE `One`";
7507     r = run_query(hdb, 0, query);
7508     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7509
7510     query = "DROP TABLE `One`";
7511     r = run_query(href, 0, query);
7512     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7513
7514     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A` )";
7515     r = run_query(hdb, 0, query);
7516     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7517
7518     query = "CREATE TABLE `One` ( `A` INT, `B` INT, `C` INT PRIMARY KEY `A` )";
7519     r = run_query(href, 0, query);
7520     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7521
7522     query = "INSERT INTO `One` ( `A`, `B`, `C` ) VALUES ( 1, 2, 3 )";
7523     r = run_query(href, 0, query);
7524     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7525
7526     /* number of columns doesn't match */
7527     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7528     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7529
7530     query = "SELECT * FROM `One`";
7531     r = do_query(hdb, query, &hrec);
7532     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7533
7534     r = MsiRecordGetInteger(hrec, 1);
7535     ok(r == 1, "Expected 1, got %d\n", r);
7536
7537     r = MsiRecordGetInteger(hrec, 2);
7538     ok(r == 2, "Expected 2, got %d\n", r);
7539
7540     r = MsiRecordGetInteger(hrec, 3);
7541     ok(r == MSI_NULL_INTEGER, "Expected MSI_NULL_INTEGER, got %d\n", r);
7542
7543     MsiCloseHandle(hrec);
7544
7545     /* nothing in MergeErrors */
7546     query = "SELECT * FROM `MergeErrors`";
7547     r = do_query(hdb, query, &hrec);
7548     ok(r == ERROR_BAD_QUERY_SYNTAX,
7549        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7550
7551     query = "DROP TABLE `One`";
7552     r = run_query(hdb, 0, query);
7553     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7554
7555     query = "DROP TABLE `One`";
7556     r = run_query(href, 0, query);
7557     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7558
7559     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A` )";
7560     r = run_query(hdb, 0, query);
7561     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7562
7563     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 1, 1 )";
7564     r = run_query(hdb, 0, query);
7565     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7566
7567     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 2, 2 )";
7568     r = run_query(hdb, 0, query);
7569     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7570
7571     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A` )";
7572     r = run_query(href, 0, query);
7573     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7574
7575     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 1, 2 )";
7576     r = run_query(href, 0, query);
7577     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7578
7579     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 2, 3 )";
7580     r = run_query(href, 0, query);
7581     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7582
7583     /* primary keys match, rows do not */
7584     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7585     ok(r == ERROR_FUNCTION_FAILED,
7586        "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
7587
7588     /* nothing in MergeErrors */
7589     query = "SELECT * FROM `MergeErrors`";
7590     r = do_query(hdb, query, &hrec);
7591     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7592
7593     size = MAX_PATH;
7594     r = MsiRecordGetStringA(hrec, 1, buf, &size);
7595     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7596     ok(!lstrcmpA(buf, "One"), "Expected \"One\", got \"%s\"\n", buf);
7597
7598     r = MsiRecordGetInteger(hrec, 2);
7599     ok(r == 2, "Expected 2, got %d\n", r);
7600
7601     MsiCloseHandle(hrec);
7602
7603     r = MsiDatabaseOpenViewA(hdb, "SELECT * FROM `MergeErrors`", &hview);
7604     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7605
7606     r = MsiViewGetColumnInfo(hview, MSICOLINFO_NAMES, &hrec);
7607     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7608
7609     size = MAX_PATH;
7610     r = MsiRecordGetString(hrec, 1, buf, &size);
7611     ok(!lstrcmpA(buf, "Table"), "Expected \"Table\", got \"%s\"\n", buf);
7612
7613     size = MAX_PATH;
7614     r = MsiRecordGetString(hrec, 2, buf, &size);
7615     ok(!lstrcmpA(buf, "NumRowMergeConflicts"),
7616        "Expected \"NumRowMergeConflicts\", got \"%s\"\n", buf);
7617
7618     MsiCloseHandle(hrec);
7619
7620     r = MsiViewGetColumnInfo(hview, MSICOLINFO_TYPES, &hrec);
7621     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7622
7623     size = MAX_PATH;
7624     r = MsiRecordGetString(hrec, 1, buf, &size);
7625     ok(!lstrcmpA(buf, "s255"), "Expected \"s255\", got \"%s\"\n", buf);
7626
7627     size = MAX_PATH;
7628     r = MsiRecordGetString(hrec, 2, buf, &size);
7629     ok(!lstrcmpA(buf, "i2"), "Expected \"i2\", got \"%s\"\n", buf);
7630
7631     MsiCloseHandle(hrec);
7632     MsiViewClose(hview);
7633     MsiCloseHandle(hview);
7634
7635     query = "DROP TABLE `MergeErrors`";
7636     r = run_query(hdb, 0, query);
7637     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7638
7639     query = "DROP TABLE `One`";
7640     r = run_query(hdb, 0, query);
7641     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7642
7643     query = "DROP TABLE `One`";
7644     r = run_query(href, 0, query);
7645     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7646
7647     query = "CREATE TABLE `One` ( `A` INT, `B` CHAR(72) PRIMARY KEY `A` )";
7648     r = run_query(href, 0, query);
7649     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7650
7651     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 1, 'hi' )";
7652     r = run_query(href, 0, query);
7653     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7654
7655     /* table from merged database is not in target database */
7656     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7657     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7658
7659     query = "SELECT * FROM `One`";
7660     r = do_query(hdb, query, &hrec);
7661     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7662
7663     r = MsiRecordGetInteger(hrec, 1);
7664     ok(r == 1, "Expected 1, got %d\n", r);
7665
7666     size = MAX_PATH;
7667     r = MsiRecordGetStringA(hrec, 2, buf, &size);
7668     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7669     ok(!lstrcmpA(buf, "hi"), "Expected \"hi\", got \"%s\"\n", buf);
7670
7671     MsiCloseHandle(hrec);
7672
7673     /* nothing in MergeErrors */
7674     query = "SELECT * FROM `MergeErrors`";
7675     r = do_query(hdb, query, &hrec);
7676     ok(r == ERROR_BAD_QUERY_SYNTAX,
7677        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7678
7679     query = "DROP TABLE `One`";
7680     r = run_query(hdb, 0, query);
7681     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7682
7683     query = "DROP TABLE `One`";
7684     r = run_query(href, 0, query);
7685     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7686
7687     query = "CREATE TABLE `One` ( "
7688             "`A` CHAR(72), `B` INT PRIMARY KEY `A` )";
7689     r = run_query(hdb, 0, query);
7690     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7691
7692     query = "CREATE TABLE `One` ( "
7693             "`A` CHAR(72), `B` INT PRIMARY KEY `A` )";
7694     r = run_query(href, 0, query);
7695     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7696
7697     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 'hi', 1 )";
7698     r = run_query(href, 0, query);
7699     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7700
7701     /* primary key is string */
7702     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7703     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7704
7705     query = "SELECT * FROM `One`";
7706     r = do_query(hdb, query, &hrec);
7707     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7708
7709     size = MAX_PATH;
7710     r = MsiRecordGetStringA(hrec, 1, buf, &size);
7711     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7712     ok(!lstrcmpA(buf, "hi"), "Expected \"hi\", got \"%s\"\n", buf);
7713
7714     r = MsiRecordGetInteger(hrec, 2);
7715     ok(r == 1, "Expected 1, got %d\n", r);
7716
7717     MsiCloseHandle(hrec);
7718
7719     /* nothing in MergeErrors */
7720     query = "SELECT * FROM `MergeErrors`";
7721     r = do_query(hdb, query, &hrec);
7722     ok(r == ERROR_BAD_QUERY_SYNTAX,
7723        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7724
7725     create_file_data("codepage.idt", "\r\n\r\n850\t_ForceCodepage\r\n", 0);
7726
7727     GetCurrentDirectoryA(MAX_PATH, buf);
7728     r = MsiDatabaseImportA(hdb, buf, "codepage.idt");
7729     todo_wine
7730     {
7731         ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7732     }
7733
7734     query = "DROP TABLE `One`";
7735     r = run_query(hdb, 0, query);
7736     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7737
7738     query = "DROP TABLE `One`";
7739     r = run_query(href, 0, query);
7740     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7741
7742     query = "CREATE TABLE `One` ( "
7743             "`A` INT, `B` CHAR(72) LOCALIZABLE PRIMARY KEY `A` )";
7744     r = run_query(hdb, 0, query);
7745     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7746
7747     query = "CREATE TABLE `One` ( "
7748             "`A` INT, `B` CHAR(72) LOCALIZABLE PRIMARY KEY `A` )";
7749     r = run_query(href, 0, query);
7750     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7751
7752     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 1, 'hi' )";
7753     r = run_query(href, 0, query);
7754     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7755
7756     /* code page does not match */
7757     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7758     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7759
7760     query = "SELECT * FROM `One`";
7761     r = do_query(hdb, query, &hrec);
7762     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7763
7764     r = MsiRecordGetInteger(hrec, 1);
7765     ok(r == 1, "Expected 1, got %d\n", r);
7766
7767     size = MAX_PATH;
7768     r = MsiRecordGetStringA(hrec, 2, buf, &size);
7769     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7770     ok(!lstrcmpA(buf, "hi"), "Expected \"hi\", got \"%s\"\n", buf);
7771
7772     MsiCloseHandle(hrec);
7773
7774     /* nothing in MergeErrors */
7775     query = "SELECT * FROM `MergeErrors`";
7776     r = do_query(hdb, query, &hrec);
7777     ok(r == ERROR_BAD_QUERY_SYNTAX,
7778        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7779
7780     query = "DROP TABLE `One`";
7781     r = run_query(hdb, 0, query);
7782     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7783
7784     query = "DROP TABLE `One`";
7785     r = run_query(href, 0, query);
7786     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7787
7788     query = "CREATE TABLE `One` ( `A` INT, `B` OBJECT PRIMARY KEY `A` )";
7789     r = run_query(hdb, 0, query);
7790     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7791
7792     query = "CREATE TABLE `One` ( `A` INT, `B` OBJECT PRIMARY KEY `A` )";
7793     r = run_query(href, 0, query);
7794     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7795
7796     create_file("binary.dat");
7797     hrec = MsiCreateRecord(1);
7798     MsiRecordSetStreamA(hrec, 1, "binary.dat");
7799
7800     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 1, ? )";
7801     r = run_query(href, hrec, query);
7802     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7803
7804     MsiCloseHandle(hrec);
7805
7806     /* binary data to merge */
7807     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7808     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7809
7810     query = "SELECT * FROM `One`";
7811     r = do_query(hdb, query, &hrec);
7812     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7813
7814     r = MsiRecordGetInteger(hrec, 1);
7815     ok(r == 1, "Expected 1, got %d\n", r);
7816
7817     size = MAX_PATH;
7818     ZeroMemory(buf, MAX_PATH);
7819     r = MsiRecordReadStream(hrec, 2, buf, &size);
7820     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7821     ok(!lstrcmpA(buf, "binary.dat\n"),
7822        "Expected \"binary.dat\\n\", got \"%s\"\n", buf);
7823
7824     MsiCloseHandle(hrec);
7825
7826     /* nothing in MergeErrors */
7827     query = "SELECT * FROM `MergeErrors`";
7828     r = do_query(hdb, query, &hrec);
7829     ok(r == ERROR_BAD_QUERY_SYNTAX,
7830        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7831
7832     query = "DROP TABLE `One`";
7833     r = run_query(hdb, 0, query);
7834     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7835
7836     query = "DROP TABLE `One`";
7837     r = run_query(href, 0, query);
7838     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7839
7840     query = "CREATE TABLE `One` ( `A` INT, `B` CHAR(72) PRIMARY KEY `A` )";
7841     r = run_query(hdb, 0, query);
7842     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7843     r = run_query(href, 0, query);
7844     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7845
7846     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 1, 'foo' )";
7847     r = run_query(href, 0, query);
7848     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7849
7850     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 2, 'bar' )";
7851     r = run_query(href, 0, query);
7852     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7853
7854     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7855     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7856
7857     query = "SELECT * FROM `One`";
7858     r = MsiDatabaseOpenViewA(hdb, query, &hview);
7859     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7860     r = MsiViewExecute(hview, 0);
7861     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7862
7863     r = MsiViewFetch(hview, &hrec);
7864     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7865
7866     r = MsiRecordGetInteger(hrec, 1);
7867     ok(r == 1, "Expected 1, got %d\n", r);
7868
7869     size = MAX_PATH;
7870     r = MsiRecordGetStringA(hrec, 2, buf, &size);
7871     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7872     ok(!lstrcmpA(buf, "foo"), "Expected \"foo\", got \"%s\"\n", buf);
7873
7874     MsiCloseHandle(hrec);
7875
7876     r = MsiViewFetch(hview, &hrec);
7877     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7878
7879     r = MsiRecordGetInteger(hrec, 1);
7880     ok(r == 2, "Expected 2, got %d\n", r);
7881
7882     size = MAX_PATH;
7883     r = MsiRecordGetStringA(hrec, 2, buf, &size);
7884     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7885     ok(!lstrcmpA(buf, "bar"), "Expected \"bar\", got \"%s\"\n", buf);
7886
7887     MsiCloseHandle(hrec);
7888
7889     r = MsiViewFetch(hview, &hrec);
7890     ok(r == ERROR_NO_MORE_ITEMS,
7891        "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7892
7893     MsiViewClose(hview);
7894     MsiCloseHandle(hview);
7895
7896     MsiCloseHandle(hdb);
7897     MsiCloseHandle(href);
7898     DeleteFileA(msifile);
7899     DeleteFileA("refdb.msi");
7900     DeleteFileA("codepage.idt");
7901     DeleteFileA("binary.dat");
7902 }
7903
7904 UINT ordervals[6][3] =
7905 {
7906     { MSI_NULL_INTEGER, 12, 13 },
7907     { 1, 2, 3 },
7908     { 6, 4, 5 },
7909     { 8, 9, 7 },
7910     { 10, 11, MSI_NULL_INTEGER },
7911     { 14, MSI_NULL_INTEGER, 15 }
7912 };
7913
7914 static void test_insertorder(void)
7915 {
7916     MSIHANDLE hdb, view, rec;
7917     LPCSTR query;
7918     UINT r;
7919     int i;
7920
7921     hdb = create_db();
7922     ok(hdb, "failed to create db\n");
7923
7924     query = "CREATE TABLE `T` ( `A` SHORT, `B` SHORT, `C` SHORT PRIMARY KEY `A`)";
7925     r = run_query(hdb, 0, query);
7926     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7927
7928     query = "INSERT INTO `T` ( `A`, `B`, `C` ) VALUES ( 1, 2, 3 )";
7929     r = run_query(hdb, 0, query);
7930     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7931
7932     query = "INSERT INTO `T` ( `B`, `C`, `A` ) VALUES ( 4, 5, 6 )";
7933     r = run_query(hdb, 0, query);
7934     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7935
7936     query = "INSERT INTO `T` ( `C`, `A`, `B` ) VALUES ( 7, 8, 9 )";
7937     r = run_query(hdb, 0, query);
7938     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7939
7940     query = "INSERT INTO `T` ( `A`, `B` ) VALUES ( 10, 11 )";
7941     r = run_query(hdb, 0, query);
7942     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7943
7944     query = "INSERT INTO `T` ( `B`, `C` ) VALUES ( 12, 13 )";
7945     r = run_query(hdb, 0, query);
7946     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7947
7948     /* fails because the primary key already
7949      * has an MSI_NULL_INTEGER value set above
7950      */
7951     query = "INSERT INTO `T` ( `C` ) VALUES ( 14 )";
7952     r = run_query(hdb, 0, query);
7953     ok(r == ERROR_FUNCTION_FAILED,
7954        "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
7955
7956     /* replicate the error where primary key is set twice */
7957     query = "INSERT INTO `T` ( `A`, `C` ) VALUES ( 1, 14 )";
7958     r = run_query(hdb, 0, query);
7959     ok(r == ERROR_FUNCTION_FAILED,
7960        "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
7961
7962     query = "INSERT INTO `T` ( `A`, `C` ) VALUES ( 14, 15 )";
7963     r = run_query(hdb, 0, query);
7964     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7965
7966     query = "INSERT INTO `T` VALUES ( 16 )";
7967     r = run_query(hdb, 0, query);
7968     ok(r == ERROR_BAD_QUERY_SYNTAX,
7969        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7970
7971     query = "INSERT INTO `T` VALUES ( 17, 18 )";
7972     r = run_query(hdb, 0, query);
7973     ok(r == ERROR_BAD_QUERY_SYNTAX,
7974        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7975
7976     query = "INSERT INTO `T` VALUES ( 19, 20, 21 )";
7977     r = run_query(hdb, 0, query);
7978     ok(r == ERROR_BAD_QUERY_SYNTAX,
7979        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7980
7981     query = "SELECT * FROM `T`";
7982     r = MsiDatabaseOpenView(hdb, query, &view);
7983     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7984     r = MsiViewExecute(view, 0);
7985     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7986
7987     for (i = 0; i < 6; i++)
7988     {
7989         r = MsiViewFetch(view, &rec);
7990         ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7991
7992         r = MsiRecordGetInteger(rec, 1);
7993         ok(r == ordervals[i][0], "Expected %d, got %d\n", ordervals[i][0], r);
7994
7995         r = MsiRecordGetInteger(rec, 2);
7996         ok(r == ordervals[i][1], "Expected %d, got %d\n", ordervals[i][1], r);
7997
7998         r = MsiRecordGetInteger(rec, 3);
7999         ok(r == ordervals[i][2], "Expected %d, got %d\n", ordervals[i][2], r);
8000
8001         MsiCloseHandle(rec);
8002     }
8003
8004     r = MsiViewFetch(view, &rec);
8005     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
8006
8007     MsiViewClose(view);
8008     MsiCloseHandle(view);
8009
8010     query = "DELETE FROM `T` WHERE `A` IS NULL";
8011     r = run_query(hdb, 0, query);
8012     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8013
8014     query = "INSERT INTO `T` ( `B`, `C` ) VALUES ( 12, 13 ) TEMPORARY";
8015     r = run_query(hdb, 0, query);
8016     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8017
8018     query = "SELECT * FROM `T`";
8019     r = MsiDatabaseOpenView(hdb, query, &view);
8020     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8021     r = MsiViewExecute(view, 0);
8022     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8023
8024     for (i = 0; i < 6; i++)
8025     {
8026         r = MsiViewFetch(view, &rec);
8027         ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8028
8029         r = MsiRecordGetInteger(rec, 1);
8030         ok(r == ordervals[i][0], "Expected %d, got %d\n", ordervals[i][0], r);
8031
8032         r = MsiRecordGetInteger(rec, 2);
8033         ok(r == ordervals[i][1], "Expected %d, got %d\n", ordervals[i][1], r);
8034
8035         r = MsiRecordGetInteger(rec, 3);
8036         ok(r == ordervals[i][2], "Expected %d, got %d\n", ordervals[i][2], r);
8037
8038         MsiCloseHandle(rec);
8039     }
8040
8041     r = MsiViewFetch(view, &rec);
8042     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
8043
8044     MsiViewClose(view);
8045     MsiCloseHandle(view);
8046     MsiCloseHandle(hdb);
8047     DeleteFileA(msifile);
8048 }
8049
8050 static void test_columnorder(void)
8051 {
8052     MSIHANDLE hdb, view, rec;
8053     char buf[MAX_PATH];
8054     LPCSTR query;
8055     DWORD sz;
8056     UINT r;
8057
8058     hdb = create_db();
8059     ok(hdb, "failed to create db\n");
8060
8061     /* Each column is a slot:
8062      * ---------------------
8063      * | B | C | A | E | D |
8064      * ---------------------
8065      *
8066      * When a column is selected as a primary key,
8067      * the column occupying the nth primary key slot is swapped
8068      * with the current position of the primary key in question:
8069      *
8070      * set primary key `D`
8071      * ---------------------    ---------------------
8072      * | B | C | A | E | D | -> | D | C | A | E | B |
8073      * ---------------------    ---------------------
8074      *
8075      * set primary key `E`
8076      * ---------------------    ---------------------
8077      * | D | C | A | E | B | -> | D | E | A | C | B |
8078      * ---------------------    ---------------------
8079      */
8080
8081     query = "CREATE TABLE `T` ( `B` SHORT NOT NULL, `C` SHORT NOT NULL, "
8082             "`A` CHAR(255), `E` INT, `D` CHAR(255) NOT NULL "
8083             "PRIMARY KEY `D`, `E`)";
8084     r = run_query(hdb, 0, query);
8085     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8086
8087     query = "SELECT * FROM `T`";
8088     r = MsiDatabaseOpenView(hdb, query, &view);
8089     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8090
8091     r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
8092     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8093
8094     sz = MAX_PATH;
8095     lstrcpyA(buf, "kiwi");
8096     r = MsiRecordGetString(rec, 1, buf, &sz);
8097     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8098     ok(!lstrcmpA("s255", buf), "Expected \"s255\", got \"%s\"\n", buf);
8099
8100     sz = MAX_PATH;
8101     lstrcpyA(buf, "kiwi");
8102     r = MsiRecordGetString(rec, 2, buf, &sz);
8103     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8104     ok(!lstrcmpA("I2", buf), "Expected \"I2\", got \"%s\"\n", buf);
8105
8106     sz = MAX_PATH;
8107     lstrcpyA(buf, "kiwi");
8108     r = MsiRecordGetString(rec, 3, buf, &sz);
8109     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8110     ok(!lstrcmpA("S255", buf), "Expected \"S255\", got \"%s\"\n", buf);
8111
8112     sz = MAX_PATH;
8113     lstrcpyA(buf, "kiwi");
8114     r = MsiRecordGetString(rec, 4, buf, &sz);
8115     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8116     ok(!lstrcmpA("i2", buf), "Expected \"i2\", got \"%s\"\n", buf);
8117
8118     sz = MAX_PATH;
8119     lstrcpyA(buf, "kiwi");
8120     r = MsiRecordGetString(rec, 5, buf, &sz);
8121     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8122     ok(!lstrcmpA("i2", buf), "Expected \"i2\", got \"%s\"\n", buf);
8123
8124     MsiCloseHandle(rec);
8125
8126     r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec);
8127     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8128
8129     sz = MAX_PATH;
8130     lstrcpyA(buf, "kiwi");
8131     r = MsiRecordGetString(rec, 1, buf, &sz);
8132     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8133     ok(!lstrcmpA("D", buf), "Expected \"D\", got \"%s\"\n", buf);
8134
8135     sz = MAX_PATH;
8136     lstrcpyA(buf, "kiwi");
8137     r = MsiRecordGetString(rec, 2, buf, &sz);
8138     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8139     ok(!lstrcmpA("E", buf), "Expected \"E\", got \"%s\"\n", buf);
8140
8141     sz = MAX_PATH;
8142     lstrcpyA(buf, "kiwi");
8143     r = MsiRecordGetString(rec, 3, buf, &sz);
8144     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8145     ok(!lstrcmpA("A", buf), "Expected \"A\", got \"%s\"\n", buf);
8146
8147     sz = MAX_PATH;
8148     lstrcpyA(buf, "kiwi");
8149     r = MsiRecordGetString(rec, 4, buf, &sz);
8150     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8151     ok(!lstrcmpA("C", buf), "Expected \"C\", got \"%s\"\n", buf);
8152
8153     sz = MAX_PATH;
8154     lstrcpyA(buf, "kiwi");
8155     r = MsiRecordGetString(rec, 5, buf, &sz);
8156     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8157     ok(!lstrcmpA("B", buf), "Expected \"B\", got \"%s\"\n", buf);
8158
8159     MsiCloseHandle(rec);
8160     MsiViewClose(view);
8161     MsiCloseHandle(view);
8162
8163     query = "INSERT INTO `T` ( `B`, `C`, `A`, `E`, `D` ) "
8164             "VALUES ( 1, 2, 'a', 3, 'bc' )";
8165     r = run_query(hdb, 0, query);
8166     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8167
8168     query = "SELECT * FROM `T`";
8169     r = do_query(hdb, query, &rec);
8170
8171     sz = MAX_PATH;
8172     lstrcpyA(buf, "kiwi");
8173     r = MsiRecordGetString(rec, 1, buf, &sz);
8174     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8175     ok(!lstrcmpA("bc", buf), "Expected \"bc\", got \"%s\"\n", buf);
8176
8177     r = MsiRecordGetInteger(rec, 2);
8178     ok(r == 3, "Expected 3, got %d\n", r);
8179
8180     sz = MAX_PATH;
8181     lstrcpyA(buf, "kiwi");
8182     r = MsiRecordGetString(rec, 3, buf, &sz);
8183     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8184     ok(!lstrcmpA("a", buf), "Expected \"a\", got \"%s\"\n", buf);
8185
8186     r = MsiRecordGetInteger(rec, 4);
8187     ok(r == 2, "Expected 2, got %d\n", r);
8188
8189     r = MsiRecordGetInteger(rec, 5);
8190     ok(r == 1, "Expected 1, got %d\n", r);
8191
8192     MsiCloseHandle(rec);
8193
8194     query = "SELECT * FROM `_Columns` WHERE `Table` = 'T'";
8195     r = MsiDatabaseOpenView(hdb, query, &view);
8196     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8197     r = MsiViewExecute(view, 0);
8198     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8199
8200     r = MsiViewFetch(view, &rec);
8201     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8202
8203     sz = MAX_PATH;
8204     lstrcpyA(buf, "kiwi");
8205     r = MsiRecordGetString(rec, 1, buf, &sz);
8206     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8207     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
8208
8209     r = MsiRecordGetInteger(rec, 2);
8210     ok(r == 1, "Expected 1, got %d\n", r);
8211
8212     sz = MAX_PATH;
8213     lstrcpyA(buf, "kiwi");
8214     r = MsiRecordGetString(rec, 3, buf, &sz);
8215     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8216     ok(!lstrcmpA("D", buf), "Expected \"D\", got \"%s\"\n", buf);
8217
8218     MsiCloseHandle(rec);
8219
8220     r = MsiViewFetch(view, &rec);
8221     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8222
8223     sz = MAX_PATH;
8224     lstrcpyA(buf, "kiwi");
8225     r = MsiRecordGetString(rec, 1, buf, &sz);
8226     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8227     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
8228
8229     r = MsiRecordGetInteger(rec, 2);
8230     ok(r == 2, "Expected 2, got %d\n", r);
8231
8232     sz = MAX_PATH;
8233     lstrcpyA(buf, "kiwi");
8234     r = MsiRecordGetString(rec, 3, buf, &sz);
8235     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8236     ok(!lstrcmpA("E", buf), "Expected \"E\", got \"%s\"\n", buf);
8237
8238     MsiCloseHandle(rec);
8239
8240     r = MsiViewFetch(view, &rec);
8241     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8242
8243     sz = MAX_PATH;
8244     lstrcpyA(buf, "kiwi");
8245     r = MsiRecordGetString(rec, 1, buf, &sz);
8246     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8247     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
8248
8249     r = MsiRecordGetInteger(rec, 2);
8250     ok(r == 3, "Expected 3, got %d\n", r);
8251
8252     sz = MAX_PATH;
8253     lstrcpyA(buf, "kiwi");
8254     r = MsiRecordGetString(rec, 3, buf, &sz);
8255     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8256     ok(!lstrcmpA("A", buf), "Expected \"A\", got \"%s\"\n", buf);
8257
8258     MsiCloseHandle(rec);
8259
8260     r = MsiViewFetch(view, &rec);
8261     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8262
8263     sz = MAX_PATH;
8264     lstrcpyA(buf, "kiwi");
8265     r = MsiRecordGetString(rec, 1, buf, &sz);
8266     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8267     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
8268
8269     r = MsiRecordGetInteger(rec, 2);
8270     ok(r == 4, "Expected 4, got %d\n", r);
8271
8272     sz = MAX_PATH;
8273     lstrcpyA(buf, "kiwi");
8274     r = MsiRecordGetString(rec, 3, buf, &sz);
8275     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8276     ok(!lstrcmpA("C", buf), "Expected \"C\", got \"%s\"\n", buf);
8277
8278     MsiCloseHandle(rec);
8279
8280     r = MsiViewFetch(view, &rec);
8281     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8282
8283     sz = MAX_PATH;
8284     lstrcpyA(buf, "kiwi");
8285     r = MsiRecordGetString(rec, 1, buf, &sz);
8286     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8287     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
8288
8289     r = MsiRecordGetInteger(rec, 2);
8290     ok(r == 5, "Expected 5, got %d\n", r);
8291
8292     sz = MAX_PATH;
8293     lstrcpyA(buf, "kiwi");
8294     r = MsiRecordGetString(rec, 3, buf, &sz);
8295     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8296     ok(!lstrcmpA("B", buf), "Expected \"B\", got \"%s\"\n", buf);
8297
8298     MsiCloseHandle(rec);
8299
8300     r = MsiViewFetch(view, &rec);
8301     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
8302
8303     MsiViewClose(view);
8304     MsiCloseHandle(view);
8305
8306     query = "CREATE TABLE `Z` ( `B` SHORT NOT NULL, `C` SHORT NOT NULL, "
8307             "`A` CHAR(255), `E` INT, `D` CHAR(255) NOT NULL "
8308             "PRIMARY KEY `C`, `A`, `D`)";
8309     r = run_query(hdb, 0, query);
8310     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8311
8312     query = "SELECT * FROM `Z`";
8313     r = MsiDatabaseOpenView(hdb, query, &view);
8314     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8315
8316     r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
8317     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8318
8319     sz = MAX_PATH;
8320     lstrcpyA(buf, "kiwi");
8321     r = MsiRecordGetString(rec, 1, buf, &sz);
8322     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8323     ok(!lstrcmpA("i2", buf), "Expected \"i2\", got \"%s\"\n", buf);
8324
8325     sz = MAX_PATH;
8326     lstrcpyA(buf, "kiwi");
8327     r = MsiRecordGetString(rec, 2, buf, &sz);
8328     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8329     ok(!lstrcmpA("S255", buf), "Expected \"S255\", got \"%s\"\n", buf);
8330
8331     sz = MAX_PATH;
8332     lstrcpyA(buf, "kiwi");
8333     r = MsiRecordGetString(rec, 3, buf, &sz);
8334     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8335     ok(!lstrcmpA("s255", buf), "Expected \"s255\", got \"%s\"\n", buf);
8336
8337     sz = MAX_PATH;
8338     lstrcpyA(buf, "kiwi");
8339     r = MsiRecordGetString(rec, 4, buf, &sz);
8340     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8341     ok(!lstrcmpA("I2", buf), "Expected \"I2\", got \"%s\"\n", buf);
8342
8343     sz = MAX_PATH;
8344     lstrcpyA(buf, "kiwi");
8345     r = MsiRecordGetString(rec, 5, buf, &sz);
8346     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8347     ok(!lstrcmpA("i2", buf), "Expected \"i2\", got \"%s\"\n", buf);
8348
8349     MsiCloseHandle(rec);
8350
8351     r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec);
8352     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8353
8354     sz = MAX_PATH;
8355     lstrcpyA(buf, "kiwi");
8356     r = MsiRecordGetString(rec, 1, buf, &sz);
8357     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8358     ok(!lstrcmpA("C", buf), "Expected \"C\", got \"%s\"\n", buf);
8359
8360     sz = MAX_PATH;
8361     lstrcpyA(buf, "kiwi");
8362     r = MsiRecordGetString(rec, 2, buf, &sz);
8363     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8364     ok(!lstrcmpA("A", buf), "Expected \"A\", got \"%s\"\n", buf);
8365
8366     sz = MAX_PATH;
8367     lstrcpyA(buf, "kiwi");
8368     r = MsiRecordGetString(rec, 3, buf, &sz);
8369     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8370     ok(!lstrcmpA("D", buf), "Expected \"D\", got \"%s\"\n", buf);
8371
8372     sz = MAX_PATH;
8373     lstrcpyA(buf, "kiwi");
8374     r = MsiRecordGetString(rec, 4, buf, &sz);
8375     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8376     ok(!lstrcmpA("E", buf), "Expected \"E\", got \"%s\"\n", buf);
8377
8378     sz = MAX_PATH;
8379     lstrcpyA(buf, "kiwi");
8380     r = MsiRecordGetString(rec, 5, buf, &sz);
8381     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8382     ok(!lstrcmpA("B", buf), "Expected \"B\", got \"%s\"\n", buf);
8383
8384     MsiCloseHandle(rec);
8385     MsiViewClose(view);
8386     MsiCloseHandle(view);
8387
8388     query = "INSERT INTO `Z` ( `B`, `C`, `A`, `E`, `D` ) "
8389             "VALUES ( 1, 2, 'a', 3, 'bc' )";
8390     r = run_query(hdb, 0, query);
8391     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8392
8393     query = "SELECT * FROM `Z`";
8394     r = do_query(hdb, query, &rec);
8395
8396     r = MsiRecordGetInteger(rec, 1);
8397     ok(r == 2, "Expected 2, got %d\n", r);
8398
8399     sz = MAX_PATH;
8400     lstrcpyA(buf, "kiwi");
8401     r = MsiRecordGetString(rec, 2, buf, &sz);
8402     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8403     ok(!lstrcmpA("a", buf), "Expected \"a\", got \"%s\"\n", buf);
8404
8405     sz = MAX_PATH;
8406     lstrcpyA(buf, "kiwi");
8407     r = MsiRecordGetString(rec, 3, buf, &sz);
8408     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8409     ok(!lstrcmpA("bc", buf), "Expected \"bc\", got \"%s\"\n", buf);
8410
8411     r = MsiRecordGetInteger(rec, 4);
8412     ok(r == 3, "Expected 3, got %d\n", r);
8413
8414     r = MsiRecordGetInteger(rec, 5);
8415     ok(r == 1, "Expected 1, got %d\n", r);
8416
8417     MsiCloseHandle(rec);
8418
8419     query = "SELECT * FROM `_Columns` WHERE `Table` = 'T'";
8420     r = MsiDatabaseOpenView(hdb, query, &view);
8421     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8422     r = MsiViewExecute(view, 0);
8423     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8424
8425     r = MsiViewFetch(view, &rec);
8426     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8427
8428     sz = MAX_PATH;
8429     lstrcpyA(buf, "kiwi");
8430     r = MsiRecordGetString(rec, 1, buf, &sz);
8431     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8432     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
8433
8434     r = MsiRecordGetInteger(rec, 2);
8435     ok(r == 1, "Expected 1, got %d\n", r);
8436
8437     sz = MAX_PATH;
8438     lstrcpyA(buf, "kiwi");
8439     r = MsiRecordGetString(rec, 3, buf, &sz);
8440     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8441     ok(!lstrcmpA("D", buf), "Expected \"D\", got \"%s\"\n", buf);
8442
8443     MsiCloseHandle(rec);
8444
8445     r = MsiViewFetch(view, &rec);
8446     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8447
8448     sz = MAX_PATH;
8449     lstrcpyA(buf, "kiwi");
8450     r = MsiRecordGetString(rec, 1, buf, &sz);
8451     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8452     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
8453
8454     r = MsiRecordGetInteger(rec, 2);
8455     ok(r == 2, "Expected 2, got %d\n", r);
8456
8457     sz = MAX_PATH;
8458     lstrcpyA(buf, "kiwi");
8459     r = MsiRecordGetString(rec, 3, buf, &sz);
8460     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8461     ok(!lstrcmpA("E", buf), "Expected \"E\", got \"%s\"\n", buf);
8462
8463     MsiCloseHandle(rec);
8464
8465     r = MsiViewFetch(view, &rec);
8466     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8467
8468     sz = MAX_PATH;
8469     lstrcpyA(buf, "kiwi");
8470     r = MsiRecordGetString(rec, 1, buf, &sz);
8471     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8472     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
8473
8474     r = MsiRecordGetInteger(rec, 2);
8475     ok(r == 3, "Expected 3, got %d\n", r);
8476
8477     sz = MAX_PATH;
8478     lstrcpyA(buf, "kiwi");
8479     r = MsiRecordGetString(rec, 3, buf, &sz);
8480     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8481     ok(!lstrcmpA("A", buf), "Expected \"A\", got \"%s\"\n", buf);
8482
8483     MsiCloseHandle(rec);
8484
8485     r = MsiViewFetch(view, &rec);
8486     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8487
8488     sz = MAX_PATH;
8489     lstrcpyA(buf, "kiwi");
8490     r = MsiRecordGetString(rec, 1, buf, &sz);
8491     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8492     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
8493
8494     r = MsiRecordGetInteger(rec, 2);
8495     ok(r == 4, "Expected 4, got %d\n", r);
8496
8497     sz = MAX_PATH;
8498     lstrcpyA(buf, "kiwi");
8499     r = MsiRecordGetString(rec, 3, buf, &sz);
8500     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8501     ok(!lstrcmpA("C", buf), "Expected \"C\", got \"%s\"\n", buf);
8502
8503     MsiCloseHandle(rec);
8504
8505     r = MsiViewFetch(view, &rec);
8506     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8507
8508     sz = MAX_PATH;
8509     lstrcpyA(buf, "kiwi");
8510     r = MsiRecordGetString(rec, 1, buf, &sz);
8511     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8512     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
8513
8514     r = MsiRecordGetInteger(rec, 2);
8515     ok(r == 5, "Expected 5, got %d\n", r);
8516
8517     sz = MAX_PATH;
8518     lstrcpyA(buf, "kiwi");
8519     r = MsiRecordGetString(rec, 3, buf, &sz);
8520     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8521     ok(!lstrcmpA("B", buf), "Expected \"B\", got \"%s\"\n", buf);
8522
8523     MsiCloseHandle(rec);
8524
8525     r = MsiViewFetch(view, &rec);
8526     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
8527
8528     MsiViewClose(view);
8529     MsiCloseHandle(view);
8530
8531     MsiCloseHandle(hdb);
8532     DeleteFileA(msifile);
8533 }
8534
8535 START_TEST(db)
8536 {
8537     test_msidatabase();
8538     test_msiinsert();
8539     test_msidecomposedesc();
8540     test_msibadqueries();
8541     test_viewmodify();
8542     test_viewgetcolumninfo();
8543     test_getcolinfo();
8544     test_msiexport();
8545     test_longstrings();
8546     test_streamtable();
8547     test_binary();
8548     test_where_not_in_selected();
8549     test_where();
8550     test_msiimport();
8551     test_binary_import();
8552     test_markers();
8553     test_handle_limit();
8554     test_try_transform();
8555     test_join();
8556     test_temporary_table();
8557     test_alter();
8558     test_integers();
8559     test_update();
8560     test_special_tables();
8561     test_tables_order();
8562     test_rows_order();
8563     test_select_markers();
8564     test_viewmodify_update();
8565     test_viewmodify_assign();
8566     test_stringtable();
8567     test_viewmodify_delete();
8568     test_defaultdatabase();
8569     test_order();
8570     test_viewmodify_delete_temporary();
8571     test_deleterow();
8572     test_quotes();
8573     test_carriagereturn();
8574     test_noquotes();
8575     test_forcecodepage();
8576     test_viewmodify_refresh();
8577     test_where_viewmodify();
8578     test_storages_table();
8579     test_dbtopackage();
8580     test_droptable();
8581     test_dbmerge();
8582     test_insertorder();
8583     test_columnorder();
8584     test_suminfo_import();
8585 }