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