msacm32: acmFormatEnum: Implement ACM_FORMATENUMF_SUGGEST.
[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     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5261
5262     query = "INSERT INTO `Table` ( `A` ) VALUES ( 'This is a '''string''' ok' )";
5263     r = run_query(hdb, 0, query);
5264     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5265
5266     query = "INSERT INTO `Table` ( `A` ) VALUES ( 'This is a \'string\' ok' )";
5267     r = run_query(hdb, 0, query);
5268     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5269
5270     query = "INSERT INTO `Table` ( `A` ) VALUES ( 'This is a \"string\" ok' )";
5271     r = run_query(hdb, 0, query);
5272     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5273
5274     query = "SELECT * FROM `Table`";
5275     r = MsiDatabaseOpenView(hdb, query, &hview);
5276     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5277
5278     r = MsiViewExecute(hview, 0);
5279     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5280
5281     r = MsiViewFetch(hview, &hrec);
5282     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5283
5284     size = MAX_PATH;
5285     r = MsiRecordGetString(hrec, 1, buf, &size);
5286     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5287     ok(!lstrcmp(buf, "This is a \"string\" ok"),
5288        "Expected \"This is a \"string\" ok\", got %s\n", buf);
5289
5290     MsiCloseHandle(hrec);
5291
5292     r = MsiViewFetch(hview, &hrec);
5293     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5294
5295     MsiViewClose(hview);
5296     MsiCloseHandle(hview);
5297
5298     write_file("import.idt", import_dat, (sizeof(import_dat) - 1) * sizeof(char));
5299
5300     r = MsiDatabaseImportA(hdb, CURR_DIR, "import.idt");
5301     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5302
5303     DeleteFileA("import.idt");
5304
5305     query = "SELECT * FROM `Table`";
5306     r = MsiDatabaseOpenView(hdb, query, &hview);
5307     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5308
5309     r = MsiViewExecute(hview, 0);
5310     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5311
5312     r = MsiViewFetch(hview, &hrec);
5313     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5314
5315     size = MAX_PATH;
5316     r = MsiRecordGetString(hrec, 1, buf, &size);
5317     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5318     ok(!lstrcmp(buf, "This is a new 'string' ok"),
5319        "Expected \"This is a new 'string' ok\", got %s\n", buf);
5320
5321     MsiCloseHandle(hrec);
5322
5323     r = MsiViewFetch(hview, &hrec);
5324     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5325
5326     MsiViewClose(hview);
5327     MsiCloseHandle(hview);
5328     MsiCloseHandle(hdb);
5329     DeleteFileA(msifile);
5330 }
5331
5332 static void test_carriagereturn(void)
5333 {
5334     MSIHANDLE hdb, hview, hrec;
5335     const char *query;
5336     char buf[MAX_PATH];
5337     UINT r;
5338     DWORD size;
5339
5340     DeleteFile(msifile);
5341
5342     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
5343     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5344
5345     query = "CREATE TABLE `Table`\r ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
5346     r = run_query(hdb, 0, query);
5347     ok(r == ERROR_BAD_QUERY_SYNTAX,
5348        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5349
5350     query = "CREATE TABLE `Table` \r( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
5351     r = run_query(hdb, 0, query);
5352     ok(r == ERROR_BAD_QUERY_SYNTAX,
5353        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5354
5355     query = "CREATE\r TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
5356     r = run_query(hdb, 0, query);
5357     ok(r == ERROR_BAD_QUERY_SYNTAX,
5358        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5359
5360     query = "CREATE TABLE\r `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
5361     r = run_query(hdb, 0, query);
5362     ok(r == ERROR_BAD_QUERY_SYNTAX,
5363        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5364
5365     query = "CREATE TABLE `Table` (\r `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
5366     r = run_query(hdb, 0, query);
5367     ok(r == ERROR_BAD_QUERY_SYNTAX,
5368        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5369
5370     query = "CREATE TABLE `Table` ( `A`\r CHAR(72) NOT NULL PRIMARY KEY `A` )";
5371     r = run_query(hdb, 0, query);
5372     ok(r == ERROR_BAD_QUERY_SYNTAX,
5373        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5374
5375     query = "CREATE TABLE `Table` ( `A` CHAR(72)\r NOT NULL PRIMARY KEY `A` )";
5376     r = run_query(hdb, 0, query);
5377     ok(r == ERROR_BAD_QUERY_SYNTAX,
5378        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5379
5380     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT\r NULL PRIMARY KEY `A` )";
5381     r = run_query(hdb, 0, query);
5382     ok(r == ERROR_BAD_QUERY_SYNTAX,
5383        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5384
5385     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT \rNULL PRIMARY KEY `A` )";
5386     r = run_query(hdb, 0, query);
5387     ok(r == ERROR_BAD_QUERY_SYNTAX,
5388        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5389
5390     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL\r PRIMARY KEY `A` )";
5391     r = run_query(hdb, 0, query);
5392     ok(r == ERROR_BAD_QUERY_SYNTAX,
5393        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5394
5395     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL \rPRIMARY KEY `A` )";
5396     r = run_query(hdb, 0, query);
5397     ok(r == ERROR_BAD_QUERY_SYNTAX,
5398        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5399
5400     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY\r KEY `A` )";
5401     r = run_query(hdb, 0, query);
5402     ok(r == ERROR_BAD_QUERY_SYNTAX,
5403        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5404
5405     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY \rKEY `A` )";
5406     r = run_query(hdb, 0, query);
5407     ok(r == ERROR_BAD_QUERY_SYNTAX,
5408        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5409
5410     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY\r `A` )";
5411     r = run_query(hdb, 0, query);
5412     ok(r == ERROR_BAD_QUERY_SYNTAX,
5413        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5414
5415     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A`\r )";
5416     r = run_query(hdb, 0, query);
5417     ok(r == ERROR_BAD_QUERY_SYNTAX,
5418        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5419
5420     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )\r";
5421     r = run_query(hdb, 0, query);
5422     ok(r == ERROR_BAD_QUERY_SYNTAX,
5423        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5424
5425     query = "CREATE TABLE `\rOne` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
5426     r = run_query(hdb, 0, query);
5427     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5428
5429     query = "CREATE TABLE `Tw\ro` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
5430     r = run_query(hdb, 0, query);
5431     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5432
5433     query = "CREATE TABLE `Three\r` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
5434     r = run_query(hdb, 0, query);
5435     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5436
5437     query = "CREATE TABLE `Four` ( `A\r` CHAR(72) NOT NULL PRIMARY KEY `A` )";
5438     r = run_query(hdb, 0, query);
5439     ok(r == ERROR_BAD_QUERY_SYNTAX,
5440        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5441
5442     query = "CREATE TABLE `Four` ( `\rA` CHAR(72) NOT NULL PRIMARY KEY `A` )";
5443     r = run_query(hdb, 0, query);
5444     ok(r == ERROR_BAD_QUERY_SYNTAX,
5445        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5446
5447     query = "CREATE TABLE `Four` ( `A` CHAR(72\r) NOT NULL PRIMARY KEY `A` )";
5448     r = run_query(hdb, 0, query);
5449     ok(r == ERROR_BAD_QUERY_SYNTAX,
5450        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5451
5452     query = "CREATE TABLE `Four` ( `A` CHAR(\r72) NOT NULL PRIMARY KEY `A` )";
5453     r = run_query(hdb, 0, query);
5454     ok(r == ERROR_BAD_QUERY_SYNTAX,
5455        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5456
5457     query = "CREATE TABLE `Four` ( `A` CHAR(72) NOT NULL PRIMARY KEY `\rA` )";
5458     r = run_query(hdb, 0, query);
5459     ok(r == ERROR_BAD_QUERY_SYNTAX,
5460        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5461
5462     query = "CREATE TABLE `Four` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A\r` )";
5463     r = run_query(hdb, 0, query);
5464     ok(r == ERROR_BAD_QUERY_SYNTAX,
5465        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5466
5467     query = "CREATE TABLE `Four` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A\r` )";
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 = "SELECT * FROM `_Tables`";
5473     r = MsiDatabaseOpenView(hdb, query, &hview);
5474     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5475     r = MsiViewExecute(hview, 0);
5476     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5477
5478     r = MsiViewFetch(hview, &hrec);
5479     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5480
5481     size = MAX_PATH;
5482     r = MsiRecordGetStringA(hrec, 1, buf, &size);
5483     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5484     ok(!lstrcmpA(buf, "\rOne"), "Expected \"\\rOne\", got \"%s\"\n", buf);
5485
5486     MsiCloseHandle(hrec);
5487
5488     r = MsiViewFetch(hview, &hrec);
5489     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5490
5491     size = MAX_PATH;
5492     r = MsiRecordGetStringA(hrec, 1, buf, &size);
5493     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5494     ok(!lstrcmpA(buf, "Tw\ro"), "Expected \"Tw\\ro\", got \"%s\"\n", buf);
5495
5496     MsiCloseHandle(hrec);
5497
5498     r = MsiViewFetch(hview, &hrec);
5499     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5500
5501     size = MAX_PATH;
5502     r = MsiRecordGetStringA(hrec, 1, buf, &size);
5503     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5504     ok(!lstrcmpA(buf, "Three\r"), "Expected \"Three\r\", got \"%s\"\n", buf);
5505
5506     MsiCloseHandle(hrec);
5507
5508     r = MsiViewFetch(hview, &hrec);
5509     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5510
5511     MsiViewClose(hview);
5512     MsiCloseHandle(hview);
5513
5514     MsiCloseHandle(hdb);
5515     DeleteFileA(msifile);
5516 }
5517
5518 static void test_noquotes(void)
5519 {
5520     MSIHANDLE hdb, hview, hrec;
5521     const char *query;
5522     char buf[MAX_PATH];
5523     UINT r;
5524     DWORD size;
5525
5526     DeleteFile(msifile);
5527
5528     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
5529     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5530
5531     query = "CREATE TABLE Table ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
5532     r = run_query(hdb, 0, query);
5533     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5534
5535     query = "CREATE TABLE `Table` ( A CHAR(72) NOT NULL PRIMARY KEY `A` )";
5536     r = run_query(hdb, 0, query);
5537     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5538
5539     query = "CREATE TABLE `Table2` ( `A` CHAR(72) NOT NULL PRIMARY KEY A )";
5540     r = run_query(hdb, 0, query);
5541     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5542
5543     query = "CREATE TABLE `Table3` ( A CHAR(72) NOT NULL PRIMARY KEY A )";
5544     r = run_query(hdb, 0, query);
5545     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5546
5547     query = "SELECT * FROM `_Tables`";
5548     r = MsiDatabaseOpenView(hdb, query, &hview);
5549     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5550     r = MsiViewExecute(hview, 0);
5551     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5552
5553     r = MsiViewFetch(hview, &hrec);
5554     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5555
5556     size = MAX_PATH;
5557     r = MsiRecordGetStringA(hrec, 1, buf, &size);
5558     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5559     ok(!lstrcmpA(buf, "Table"), "Expected \"Table\", got \"%s\"\n", buf);
5560
5561     MsiCloseHandle(hrec);
5562
5563     r = MsiViewFetch(hview, &hrec);
5564     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5565
5566     size = MAX_PATH;
5567     r = MsiRecordGetStringA(hrec, 1, buf, &size);
5568     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5569     ok(!lstrcmpA(buf, "Table2"), "Expected \"Table2\", got \"%s\"\n", buf);
5570
5571     MsiCloseHandle(hrec);
5572
5573     r = MsiViewFetch(hview, &hrec);
5574     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5575
5576     size = MAX_PATH;
5577     r = MsiRecordGetStringA(hrec, 1, buf, &size);
5578     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5579     ok(!lstrcmpA(buf, "Table3"), "Expected \"Table3\", got \"%s\"\n", buf);
5580
5581     MsiCloseHandle(hrec);
5582
5583     r = MsiViewFetch(hview, &hrec);
5584     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5585
5586     MsiViewClose(hview);
5587     MsiCloseHandle(hview);
5588
5589     query = "SELECT * FROM `_Columns`";
5590     r = MsiDatabaseOpenView(hdb, query, &hview);
5591     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5592     r = MsiViewExecute(hview, 0);
5593     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5594
5595     r = MsiViewFetch(hview, &hrec);
5596     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5597
5598     size = MAX_PATH;
5599     r = MsiRecordGetStringA(hrec, 1, buf, &size);
5600     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5601     ok(!lstrcmpA(buf, "Table"), "Expected \"Table\", got \"%s\"\n", buf);
5602
5603     r = MsiRecordGetInteger(hrec, 2);
5604     ok(r == 1, "Expected 1, got %d\n", r);
5605
5606     size = MAX_PATH;
5607     r = MsiRecordGetStringA(hrec, 3, buf, &size);
5608     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5609     ok(!lstrcmpA(buf, "A"), "Expected \"A\", got \"%s\"\n", buf);
5610
5611     MsiCloseHandle(hrec);
5612
5613     r = MsiViewFetch(hview, &hrec);
5614     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5615
5616     size = MAX_PATH;
5617     r = MsiRecordGetStringA(hrec, 1, buf, &size);
5618     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5619     ok(!lstrcmpA(buf, "Table2"), "Expected \"Table2\", got \"%s\"\n", buf);
5620
5621     r = MsiRecordGetInteger(hrec, 2);
5622     ok(r == 1, "Expected 1, got %d\n", r);
5623
5624     size = MAX_PATH;
5625     r = MsiRecordGetStringA(hrec, 3, buf, &size);
5626     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5627     ok(!lstrcmpA(buf, "A"), "Expected \"A\", got \"%s\"\n", buf);
5628
5629     MsiCloseHandle(hrec);
5630
5631     r = MsiViewFetch(hview, &hrec);
5632     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5633
5634     size = MAX_PATH;
5635     r = MsiRecordGetStringA(hrec, 1, buf, &size);
5636     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5637     ok(!lstrcmpA(buf, "Table3"), "Expected \"Table3\", got \"%s\"\n", buf);
5638
5639     r = MsiRecordGetInteger(hrec, 2);
5640     ok(r == 1, "Expected 1, got %d\n", r);
5641
5642     size = MAX_PATH;
5643     r = MsiRecordGetStringA(hrec, 3, buf, &size);
5644     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5645     ok(!lstrcmpA(buf, "A"), "Expected \"A\", got \"%s\"\n", buf);
5646
5647     MsiCloseHandle(hrec);
5648
5649     r = MsiViewFetch(hview, &hrec);
5650     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5651
5652     MsiViewClose(hview);
5653     MsiCloseHandle(hview);
5654
5655     query = "INSERT INTO Table ( `A` ) VALUES ( 'hi' )";
5656     r = run_query(hdb, 0, query);
5657     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5658
5659     query = "INSERT INTO `Table` ( A ) VALUES ( 'hi' )";
5660     r = run_query(hdb, 0, query);
5661     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5662
5663     query = "INSERT INTO `Table` ( `A` ) VALUES ( hi )";
5664     r = run_query(hdb, 0, query);
5665     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5666
5667     query = "SELECT * FROM Table WHERE `A` = 'hi'";
5668     r = run_query(hdb, 0, query);
5669     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5670
5671     query = "SELECT * FROM `Table` WHERE `A` = hi";
5672     r = run_query(hdb, 0, query);
5673     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5674
5675     query = "SELECT * FROM Table";
5676     r = run_query(hdb, 0, query);
5677     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5678
5679     query = "SELECT * FROM Table2";
5680     r = MsiDatabaseOpenView(hdb, query, &hview);
5681     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5682     r = MsiViewExecute(hview, 0);
5683     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5684
5685     r = MsiViewFetch(hview, &hrec);
5686     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5687
5688     MsiViewClose(hview);
5689     MsiCloseHandle(hview);
5690
5691     query = "SELECT * FROM `Table` WHERE A = 'hi'";
5692     r = MsiDatabaseOpenView(hdb, query, &hview);
5693     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5694     r = MsiViewExecute(hview, 0);
5695     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5696
5697     r = MsiViewFetch(hview, &hrec);
5698     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5699
5700     size = MAX_PATH;
5701     r = MsiRecordGetStringA(hrec, 1, buf, &size);
5702     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5703     ok(!lstrcmpA(buf, "hi"), "Expected \"hi\", got \"%s\"\n", buf);
5704
5705     MsiCloseHandle(hrec);
5706
5707     r = MsiViewFetch(hview, &hrec);
5708     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5709
5710     MsiViewClose(hview);
5711     MsiCloseHandle(hview);
5712     MsiCloseHandle(hdb);
5713     DeleteFileA(msifile);
5714 }
5715
5716 static void read_file_data(LPCSTR filename, LPSTR buffer)
5717 {
5718     HANDLE file;
5719     DWORD read;
5720
5721     file = CreateFileA( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
5722     ZeroMemory(buffer, MAX_PATH);
5723     ReadFile(file, buffer, MAX_PATH, &read, NULL);
5724     CloseHandle(file);
5725 }
5726
5727 static void test_forcecodepage(void)
5728 {
5729     MSIHANDLE hdb;
5730     const char *query;
5731     char buffer[MAX_PATH];
5732     UINT r;
5733
5734     DeleteFile(msifile);
5735
5736     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
5737     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5738
5739     query = "SELECT * FROM `_ForceCodepage`";
5740     r = run_query(hdb, 0, query);
5741     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5742
5743     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
5744     r = run_query(hdb, 0, query);
5745     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5746
5747     query = "SELECT * FROM `_ForceCodepage`";
5748     r = run_query(hdb, 0, query);
5749     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5750
5751     r = MsiDatabaseCommit(hdb);
5752     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5753
5754     query = "SELECT * FROM `_ForceCodepage`";
5755     r = run_query(hdb, 0, query);
5756     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5757
5758     MsiCloseHandle(hdb);
5759
5760     r = MsiOpenDatabase(msifile, MSIDBOPEN_DIRECT, &hdb);
5761     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5762
5763     query = "SELECT * FROM `_ForceCodepage`";
5764     r = run_query(hdb, 0, query);
5765     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5766
5767     r = MsiDatabaseExport(hdb, "_ForceCodepage", CURR_DIR, "forcecodepage.idt");
5768     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5769
5770     read_file_data("forcecodepage.idt", buffer);
5771     ok(!lstrcmpA(buffer, "\r\n\r\n0\t_ForceCodepage\r\n"),
5772        "Expected \"\r\n\r\n0\t_ForceCodepage\r\n\", got \"%s\"", buffer);
5773
5774     MsiCloseHandle(hdb);
5775     DeleteFileA(msifile);
5776     DeleteFileA("forcecodepage.idt");
5777 }
5778
5779 static void test_viewmodify_refresh(void)
5780 {
5781     MSIHANDLE hdb, hview, hrec;
5782     const char *query;
5783     char buffer[MAX_PATH];
5784     UINT r;
5785     DWORD size;
5786
5787     DeleteFile(msifile);
5788
5789     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
5790     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5791
5792     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL, `B` INT PRIMARY KEY `A` )";
5793     r = run_query(hdb, 0, query);
5794     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5795
5796     query = "INSERT INTO `Table` ( `A`, `B` ) VALUES ( 'hi', 1 )";
5797     r = run_query(hdb, 0, query);
5798     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5799
5800     query = "SELECT * FROM `Table`";
5801     r = MsiDatabaseOpenView(hdb, query, &hview);
5802     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5803     r = MsiViewExecute(hview, 0);
5804     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5805
5806     r = MsiViewFetch(hview, &hrec);
5807     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5808
5809     query = "UPDATE `Table` SET `B` = 2 WHERE `A` = 'hi'";
5810     r = run_query(hdb, 0, query);
5811     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5812
5813     r = MsiViewModify(hview, MSIMODIFY_REFRESH, hrec);
5814     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5815
5816     size = MAX_PATH;
5817     r = MsiRecordGetStringA(hrec, 1, buffer, &size);
5818     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5819     ok(!lstrcmpA(buffer, "hi"), "Expected \"hi\", got \"%s\"\n", buffer);
5820     ok(size == 2, "Expected 2, got %d\n", size);
5821
5822     r = MsiRecordGetInteger(hrec, 2);
5823     ok(r == 2, "Expected 2, got %d\n", r);
5824
5825     MsiCloseHandle(hrec);
5826     MsiViewClose(hview);
5827     MsiCloseHandle(hview);
5828
5829     query = "INSERT INTO `Table` ( `A`, `B` ) VALUES ( 'hello', 3 )";
5830     r = run_query(hdb, 0, query);
5831     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5832
5833     query = "SELECT * FROM `Table` WHERE `B` = 3";
5834     r = MsiDatabaseOpenView(hdb, query, &hview);
5835     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5836     r = MsiViewExecute(hview, 0);
5837     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5838
5839     r = MsiViewFetch(hview, &hrec);
5840     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5841
5842     query = "UPDATE `Table` SET `B` = 2 WHERE `A` = 'hello'";
5843     r = run_query(hdb, 0, query);
5844     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5845
5846     query = "INSERT INTO `Table` ( `A`, `B` ) VALUES ( 'hithere', 3 )";
5847     r = run_query(hdb, 0, query);
5848     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5849
5850     r = MsiViewModify(hview, MSIMODIFY_REFRESH, hrec);
5851     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5852
5853     size = MAX_PATH;
5854     r = MsiRecordGetStringA(hrec, 1, buffer, &size);
5855     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5856     ok(!lstrcmpA(buffer, "hello"), "Expected \"hello\", got \"%s\"\n", buffer);
5857     ok(size == 5, "Expected 5, got %d\n", size);
5858
5859     r = MsiRecordGetInteger(hrec, 2);
5860     ok(r == 2, "Expected 2, got %d\n", r);
5861
5862     MsiCloseHandle(hrec);
5863     MsiViewClose(hview);
5864     MsiCloseHandle(hview);
5865     MsiCloseHandle(hdb);
5866     DeleteFileA(msifile);
5867 }
5868
5869 static void test_where_viewmodify(void)
5870 {
5871     MSIHANDLE hdb, hview, hrec;
5872     const char *query;
5873     UINT r;
5874
5875     DeleteFile(msifile);
5876
5877     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
5878     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5879
5880     query = "CREATE TABLE `Table` ( `A` INT, `B` INT PRIMARY KEY `A` )";
5881     r = run_query(hdb, 0, query);
5882     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5883
5884     query = "INSERT INTO `Table` ( `A`, `B` ) VALUES ( 1, 2 )";
5885     r = run_query(hdb, 0, query);
5886     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5887
5888     query = "INSERT INTO `Table` ( `A`, `B` ) VALUES ( 3, 4 )";
5889     r = run_query(hdb, 0, query);
5890     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5891
5892     query = "INSERT INTO `Table` ( `A`, `B` ) VALUES ( 5, 6 )";
5893     r = run_query(hdb, 0, query);
5894     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5895
5896     /* `B` = 3 doesn't match, but the view shouldn't be executed */
5897     query = "SELECT * FROM `Table` WHERE `B` = 3";
5898     r = MsiDatabaseOpenView(hdb, query, &hview);
5899     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5900
5901     hrec = MsiCreateRecord(2);
5902     MsiRecordSetInteger(hrec, 1, 7);
5903     MsiRecordSetInteger(hrec, 2, 8);
5904
5905     r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec);
5906     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5907
5908     MsiCloseHandle(hrec);
5909     MsiViewClose(hview);
5910     MsiCloseHandle(hview);
5911
5912     query = "SELECT * FROM `Table` WHERE `A` = 7";
5913     r = MsiDatabaseOpenView(hdb, query, &hview);
5914     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5915     r = MsiViewExecute(hview, 0);
5916     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5917
5918     r = MsiViewFetch(hview, &hrec);
5919     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5920
5921     r = MsiRecordGetInteger(hrec, 1);
5922     ok(r == 7, "Expected 7, got %d\n", r);
5923
5924     r = MsiRecordGetInteger(hrec, 2);
5925     ok(r == 8, "Expected 8, got %d\n", r);
5926
5927     MsiRecordSetInteger(hrec, 2, 9);
5928
5929     r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
5930     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5931
5932     MsiCloseHandle(hrec);
5933     MsiViewClose(hview);
5934     MsiCloseHandle(hview);
5935
5936     query = "SELECT * FROM `Table` WHERE `A` = 7";
5937     r = MsiDatabaseOpenView(hdb, query, &hview);
5938     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5939     r = MsiViewExecute(hview, 0);
5940     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5941
5942     r = MsiViewFetch(hview, &hrec);
5943     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5944
5945     r = MsiRecordGetInteger(hrec, 1);
5946     ok(r == 7, "Expected 7, got %d\n", r);
5947
5948     r = MsiRecordGetInteger(hrec, 2);
5949     ok(r == 9, "Expected 9, got %d\n", r);
5950
5951     query = "UPDATE `Table` SET `B` = 10 WHERE `A` = 7";
5952     r = run_query(hdb, 0, query);
5953     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5954
5955     r = MsiViewModify(hview, MSIMODIFY_REFRESH, hrec);
5956     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5957
5958     r = MsiRecordGetInteger(hrec, 1);
5959     ok(r == 7, "Expected 7, got %d\n", r);
5960
5961     r = MsiRecordGetInteger(hrec, 2);
5962     ok(r == 10, "Expected 10, got %d\n", r);
5963
5964     MsiCloseHandle(hrec);
5965     MsiViewClose(hview);
5966     MsiCloseHandle(hview);
5967     MsiCloseHandle(hdb);
5968 }
5969
5970 static BOOL create_storage(LPCSTR name)
5971 {
5972     WCHAR nameW[MAX_PATH];
5973     IStorage *stg;
5974     IStream *stm;
5975     HRESULT hr;
5976     DWORD count;
5977     BOOL res = FALSE;
5978
5979     MultiByteToWideChar(CP_ACP, 0, name, -1, nameW, MAX_PATH);
5980     hr = StgCreateDocfile(nameW, STGM_CREATE | STGM_READWRITE |
5981                           STGM_DIRECT | STGM_SHARE_EXCLUSIVE, 0, &stg);
5982     if (FAILED(hr))
5983         return FALSE;
5984
5985     hr = IStorage_CreateStream(stg, nameW, STGM_WRITE | STGM_SHARE_EXCLUSIVE,
5986                                0, 0, &stm);
5987     if (FAILED(hr))
5988         goto done;
5989
5990     hr = IStream_Write(stm, "stgdata", 8, &count);
5991     if (SUCCEEDED(hr))
5992         res = TRUE;
5993
5994 done:
5995     IStream_Release(stm);
5996     IStorage_Release(stg);
5997
5998     return res;
5999 }
6000
6001 static void test_storages_table(void)
6002 {
6003     MSIHANDLE hdb, hview, hrec;
6004     IStorage *stg, *inner;
6005     IStream *stm;
6006     char file[MAX_PATH];
6007     char buf[MAX_PATH];
6008     WCHAR name[MAX_PATH];
6009     LPCSTR query;
6010     HRESULT hr;
6011     DWORD size;
6012     UINT r;
6013
6014     hdb = create_db();
6015     ok(hdb, "failed to create db\n");
6016
6017     r = MsiDatabaseCommit(hdb);
6018     ok(r == ERROR_SUCCESS , "Failed to commit database\n");
6019
6020     MsiCloseHandle(hdb);
6021
6022     r = MsiOpenDatabase(msifile, MSIDBOPEN_TRANSACT, &hdb);
6023     ok(r == ERROR_SUCCESS , "Failed to open database\n");
6024
6025     /* check the column types */
6026     hrec = get_column_info(hdb, "SELECT * FROM `_Storages`", MSICOLINFO_TYPES);
6027     ok(hrec, "failed to get column info hrecord\n");
6028     ok(check_record(hrec, 1, "s62"), "wrong hrecord type\n");
6029     ok(check_record(hrec, 2, "V0"), "wrong hrecord type\n");
6030
6031     MsiCloseHandle(hrec);
6032
6033     /* now try the names */
6034     hrec = get_column_info(hdb, "SELECT * FROM `_Storages`", MSICOLINFO_NAMES);
6035     ok(hrec, "failed to get column info hrecord\n");
6036     ok(check_record(hrec, 1, "Name"), "wrong hrecord type\n");
6037     ok(check_record(hrec, 2, "Data"), "wrong hrecord type\n");
6038
6039     MsiCloseHandle(hrec);
6040
6041     create_storage("storage.bin");
6042
6043     hrec = MsiCreateRecord(2);
6044     MsiRecordSetString(hrec, 1, "stgname");
6045
6046     r = MsiRecordSetStream(hrec, 2, "storage.bin");
6047     ok(r == ERROR_SUCCESS, "Failed to add stream data to the hrecord: %d\n", r);
6048
6049     DeleteFileA("storage.bin");
6050
6051     query = "INSERT INTO `_Storages` (`Name`, `Data`) VALUES (?, ?)";
6052     r = MsiDatabaseOpenView(hdb, query, &hview);
6053     ok(r == ERROR_SUCCESS, "Failed to open database hview: %d\n", r);
6054
6055     r = MsiViewExecute(hview, hrec);
6056     ok(r == ERROR_SUCCESS, "Failed to execute hview: %d\n", r);
6057
6058     MsiCloseHandle(hrec);
6059     MsiViewClose(hview);
6060     MsiCloseHandle(hview);
6061
6062     query = "SELECT `Name`, `Data` FROM `_Storages`";
6063     r = MsiDatabaseOpenView(hdb, query, &hview);
6064     ok(r == ERROR_SUCCESS, "Failed to open database hview: %d\n", r);
6065
6066     r = MsiViewExecute(hview, 0);
6067     ok(r == ERROR_SUCCESS, "Failed to execute hview: %d\n", r);
6068
6069     r = MsiViewFetch(hview, &hrec);
6070     ok(r == ERROR_SUCCESS, "Failed to fetch hrecord: %d\n", r);
6071
6072     size = MAX_PATH;
6073     r = MsiRecordGetString(hrec, 1, file, &size);
6074     ok(r == ERROR_SUCCESS, "Failed to get string: %d\n", r);
6075     ok(!lstrcmp(file, "stgname"), "Expected \"stgname\", got \"%s\"\n", file);
6076
6077     size = MAX_PATH;
6078     lstrcpyA(buf, "apple");
6079     r = MsiRecordReadStream(hrec, 2, buf, &size);
6080     ok(r == ERROR_INVALID_DATA, "Expected ERROR_INVALID_DATA, got %d\n", r);
6081     ok(!lstrcmp(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf);
6082     ok(size == 0, "Expected 0, got %d\n", size);
6083
6084     MsiCloseHandle(hrec);
6085
6086     r = MsiViewFetch(hview, &hrec);
6087     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6088
6089     MsiViewClose(hview);
6090     MsiCloseHandle(hview);
6091
6092     MsiDatabaseCommit(hdb);
6093     MsiCloseHandle(hdb);
6094
6095     MultiByteToWideChar(CP_ACP, 0, msifile, -1, name, MAX_PATH);
6096     hr = StgOpenStorage(name, NULL, STGM_DIRECT | STGM_READ |
6097                         STGM_SHARE_DENY_WRITE, NULL, 0, &stg);
6098     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
6099     ok(stg != NULL, "Expected non-NULL storage\n");
6100
6101     MultiByteToWideChar(CP_ACP, 0, "stgname", -1, name, MAX_PATH);
6102     hr = IStorage_OpenStorage(stg, name, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE,
6103                               NULL, 0, &inner);
6104     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
6105     ok(inner != NULL, "Expected non-NULL storage\n");
6106
6107     MultiByteToWideChar(CP_ACP, 0, "storage.bin", -1, name, MAX_PATH);
6108     hr = IStorage_OpenStream(inner, name, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm);
6109     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
6110     ok(stm != NULL, "Expected non-NULL stream\n");
6111
6112     hr = IStream_Read(stm, buf, MAX_PATH, &size);
6113     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
6114     ok(size == 8, "Expected 8, got %d\n", size);
6115     ok(!lstrcmpA(buf, "stgdata"), "Expected \"stgdata\", got \"%s\"\n", buf);
6116
6117     IStream_Release(stm);
6118     IStorage_Release(inner);
6119
6120     IStorage_Release(stg);
6121     DeleteFileA(msifile);
6122 }
6123
6124 static void test_dbtopackage(void)
6125 {
6126     MSIHANDLE hdb, hpkg;
6127     CHAR package[10];
6128     CHAR buf[MAX_PATH];
6129     DWORD size;
6130     UINT r;
6131
6132     /* create an empty database, transact mode */
6133     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
6134     ok(r == ERROR_SUCCESS, "Failed to create database\n");
6135
6136     set_summary_info(hdb);
6137
6138     r = create_directory_table(hdb);
6139     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6140
6141     r = create_custom_action_table(hdb);
6142     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6143
6144     r = add_custom_action_entry(hdb, "'SetProp', 51, 'MYPROP', 'grape'");
6145     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6146
6147     sprintf(package, "#%i", hdb);
6148     r = MsiOpenPackage(package, &hpkg);
6149     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6150
6151     /* property is not set yet */
6152     size = MAX_PATH;
6153     lstrcpyA(buf, "kiwi");
6154     r = MsiGetProperty(hpkg, "MYPROP", buf, &size);
6155     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6156     ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf);
6157     ok(size == 0, "Expected 0, got %d\n", size);
6158
6159     /* run the custom action to set the property */
6160     r = MsiDoAction(hpkg, "SetProp");
6161     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6162
6163     /* property is now set */
6164     size = MAX_PATH;
6165     lstrcpyA(buf, "kiwi");
6166     r = MsiGetProperty(hpkg, "MYPROP", buf, &size);
6167     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6168     ok(!lstrcmpA(buf, "grape"), "Expected \"grape\", got \"%s\"\n", buf);
6169     ok(size == 5, "Expected 5, got %d\n", size);
6170
6171     MsiCloseHandle(hpkg);
6172
6173     /* reset the package */
6174     r = MsiOpenPackage(package, &hpkg);
6175     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6176
6177     /* property is not set anymore */
6178     size = MAX_PATH;
6179     lstrcpyA(buf, "kiwi");
6180     r = MsiGetProperty(hpkg, "MYPROP", buf, &size);
6181     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6182     todo_wine
6183     {
6184         ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf);
6185         ok(size == 0, "Expected 0, got %d\n", size);
6186     }
6187
6188     MsiCloseHandle(hdb);
6189     MsiCloseHandle(hpkg);
6190
6191     /* create an empty database, direct mode */
6192     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATEDIRECT, &hdb);
6193     ok(r == ERROR_SUCCESS, "Failed to create database\n");
6194
6195     set_summary_info(hdb);
6196
6197     r = create_directory_table(hdb);
6198     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6199
6200     r = create_custom_action_table(hdb);
6201     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6202
6203     r = add_custom_action_entry(hdb, "'SetProp', 51, 'MYPROP', 'grape'");
6204     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6205
6206     sprintf(package, "#%i", hdb);
6207     r = MsiOpenPackage(package, &hpkg);
6208     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6209
6210     /* property is not set yet */
6211     size = MAX_PATH;
6212     lstrcpyA(buf, "kiwi");
6213     r = MsiGetProperty(hpkg, "MYPROP", buf, &size);
6214     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6215     ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf);
6216     ok(size == 0, "Expected 0, got %d\n", size);
6217
6218     /* run the custom action to set the property */
6219     r = MsiDoAction(hpkg, "SetProp");
6220     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6221
6222     /* property is now set */
6223     size = MAX_PATH;
6224     lstrcpyA(buf, "kiwi");
6225     r = MsiGetProperty(hpkg, "MYPROP", buf, &size);
6226     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6227     ok(!lstrcmpA(buf, "grape"), "Expected \"grape\", got \"%s\"\n", buf);
6228     ok(size == 5, "Expected 5, got %d\n", size);
6229
6230     MsiCloseHandle(hpkg);
6231
6232     /* reset the package */
6233     r = MsiOpenPackage(package, &hpkg);
6234     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6235
6236     /* property is not set anymore */
6237     size = MAX_PATH;
6238     lstrcpyA(buf, "kiwi");
6239     r = MsiGetProperty(hpkg, "MYPROP", buf, &size);
6240     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6241     todo_wine
6242     {
6243         ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf);
6244         ok(size == 0, "Expected 0, got %d\n", size);
6245     }
6246
6247     MsiCloseHandle(hdb);
6248     MsiCloseHandle(hpkg);
6249     DeleteFileA(msifile);
6250 }
6251
6252 static void test_droptable(void)
6253 {
6254     MSIHANDLE hdb, hview, hrec;
6255     CHAR buf[MAX_PATH];
6256     LPCSTR query;
6257     DWORD size;
6258     UINT r;
6259
6260     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
6261     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6262
6263     query = "CREATE TABLE `One` ( `A` INT PRIMARY KEY `A` )";
6264     r = run_query(hdb, 0, query);
6265     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6266
6267     query = "SELECT * FROM `One`";
6268     r = do_query(hdb, query, &hrec);
6269     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6270
6271     query = "SELECT * FROM `_Tables` WHERE `Name` = 'One'";
6272     r = MsiDatabaseOpenViewA(hdb, query, &hview);
6273     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6274     r = MsiViewExecute(hview, 0);
6275     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6276
6277     r = MsiViewFetch(hview, &hrec);
6278     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6279
6280     size = MAX_PATH;
6281     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6282     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6283     ok(!lstrcmpA(buf, "One"), "Expected \"One\", got \"%s\"\n", buf);
6284
6285     MsiCloseHandle(hrec);
6286     MsiViewClose(hview);
6287     MsiCloseHandle(hview);
6288
6289     query = "SELECT * FROM `_Columns` WHERE `Table` = 'One'";
6290     r = MsiDatabaseOpenViewA(hdb, query, &hview);
6291     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6292     r = MsiViewExecute(hview, 0);
6293     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6294
6295     r = MsiViewFetch(hview, &hrec);
6296     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6297
6298     size = MAX_PATH;
6299     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6300     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6301     ok(!lstrcmpA(buf, "One"), "Expected \"One\", got \"%s\"\n", buf);
6302
6303     r = MsiRecordGetInteger(hrec, 2);
6304     ok(r == 1, "Expected 1, got %d\n", r);
6305
6306     size = MAX_PATH;
6307     r = MsiRecordGetStringA(hrec, 3, buf, &size);
6308     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6309     ok(!lstrcmpA(buf, "A"), "Expected \"A\", got \"%s\"\n", buf);
6310
6311     MsiCloseHandle(hrec);
6312
6313     r = MsiViewFetch(hview, &hrec);
6314     ok(r == ERROR_NO_MORE_ITEMS,
6315        "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6316
6317     MsiViewClose(hview);
6318     MsiCloseHandle(hview);
6319
6320     query = "DROP `One`";
6321     r = run_query(hdb, 0, query);
6322     ok(r == ERROR_BAD_QUERY_SYNTAX,
6323        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6324
6325     query = "DROP TABLE";
6326     r = run_query(hdb, 0, query);
6327     ok(r == ERROR_BAD_QUERY_SYNTAX,
6328        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6329
6330     query = "DROP TABLE `One`";
6331     hview = 0;
6332     r = MsiDatabaseOpenViewA(hdb, query, &hview);
6333     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6334     r = MsiViewExecute(hview, 0);
6335     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6336
6337     r = MsiViewFetch(hview, &hrec);
6338     ok(r == ERROR_FUNCTION_FAILED,
6339        "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
6340
6341     MsiViewClose(hview);
6342     MsiCloseHandle(hview);
6343
6344     query = "SELECT * FROM `IDontExist`";
6345     r = do_query(hdb, query, &hrec);
6346     ok(r == ERROR_BAD_QUERY_SYNTAX,
6347        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6348
6349     query = "SELECT * FROM `One`";
6350     r = do_query(hdb, query, &hrec);
6351     ok(r == ERROR_BAD_QUERY_SYNTAX,
6352        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6353
6354     query = "CREATE TABLE `One` ( `A` INT PRIMARY KEY `A` )";
6355     r = run_query(hdb, 0, query);
6356     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6357
6358     query = "DROP TABLE One";
6359     r = run_query(hdb, 0, query);
6360     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6361
6362     query = "SELECT * FROM `One`";
6363     r = do_query(hdb, query, &hrec);
6364     ok(r == ERROR_BAD_QUERY_SYNTAX,
6365        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6366
6367     query = "SELECT * FROM `_Tables` WHERE `Name` = 'One'";
6368     r = do_query(hdb, query, &hrec);
6369     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6370
6371     query = "SELECT * FROM `_Columns` WHERE `Table` = 'One'";
6372     r = do_query(hdb, query, &hrec);
6373     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6374
6375     query = "CREATE TABLE `One` ( `B` INT, `C` INT PRIMARY KEY `B` )";
6376     r = run_query(hdb, 0, query);
6377     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6378
6379     query = "SELECT * FROM `One`";
6380     r = do_query(hdb, query, &hrec);
6381     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6382
6383     query = "SELECT * FROM `_Tables` WHERE `Name` = 'One'";
6384     r = MsiDatabaseOpenViewA(hdb, query, &hview);
6385     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6386     r = MsiViewExecute(hview, 0);
6387     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6388
6389     r = MsiViewFetch(hview, &hrec);
6390     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6391
6392     size = MAX_PATH;
6393     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6394     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6395     ok(!lstrcmpA(buf, "One"), "Expected \"One\", got \"%s\"\n", buf);
6396
6397     MsiCloseHandle(hrec);
6398     MsiViewClose(hview);
6399     MsiCloseHandle(hview);
6400
6401     query = "SELECT * FROM `_Columns` WHERE `Table` = 'One'";
6402     r = MsiDatabaseOpenViewA(hdb, query, &hview);
6403     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6404     r = MsiViewExecute(hview, 0);
6405     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6406
6407     r = MsiViewFetch(hview, &hrec);
6408     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6409
6410     size = MAX_PATH;
6411     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6412     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6413     ok(!lstrcmpA(buf, "One"), "Expected \"One\", got \"%s\"\n", buf);
6414
6415     r = MsiRecordGetInteger(hrec, 2);
6416     ok(r == 1, "Expected 1, got %d\n", r);
6417
6418     size = MAX_PATH;
6419     r = MsiRecordGetStringA(hrec, 3, buf, &size);
6420     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6421     ok(!lstrcmpA(buf, "B"), "Expected \"B\", got \"%s\"\n", buf);
6422
6423     MsiCloseHandle(hrec);
6424
6425     r = MsiViewFetch(hview, &hrec);
6426     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6427
6428     size = MAX_PATH;
6429     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6430     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6431     ok(!lstrcmpA(buf, "One"), "Expected \"One\", got \"%s\"\n", buf);
6432
6433     r = MsiRecordGetInteger(hrec, 2);
6434     ok(r == 2, "Expected 2, got %d\n", r);
6435
6436     size = MAX_PATH;
6437     r = MsiRecordGetStringA(hrec, 3, buf, &size);
6438     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6439     ok(!lstrcmpA(buf, "C"), "Expected \"C\", got \"%s\"\n", buf);
6440
6441     MsiCloseHandle(hrec);
6442
6443     r = MsiViewFetch(hview, &hrec);
6444     ok(r == ERROR_NO_MORE_ITEMS,
6445        "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6446
6447     MsiViewClose(hview);
6448     MsiCloseHandle(hview);
6449
6450     query = "DROP TABLE One";
6451     r = run_query(hdb, 0, query);
6452     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6453
6454     query = "SELECT * FROM `One`";
6455     r = do_query(hdb, query, &hrec);
6456     ok(r == ERROR_BAD_QUERY_SYNTAX,
6457        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6458
6459     query = "SELECT * FROM `_Tables` WHERE `Name` = 'One'";
6460     r = do_query(hdb, query, &hrec);
6461     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6462
6463     query = "SELECT * FROM `_Columns` WHERE `Table` = 'One'";
6464     r = do_query(hdb, query, &hrec);
6465     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6466
6467     MsiCloseHandle(hdb);
6468     DeleteFileA(msifile);
6469 }
6470
6471 static void test_dbmerge(void)
6472 {
6473     MSIHANDLE hdb, href, hview, hrec;
6474     CHAR buf[MAX_PATH];
6475     LPCSTR query;
6476     DWORD size;
6477     UINT r;
6478
6479     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
6480     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6481
6482     r = MsiOpenDatabase("refdb.msi", MSIDBOPEN_CREATE, &href);
6483     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6484
6485     /* hDatabase is invalid */
6486     r = MsiDatabaseMergeA(0, href, "MergeErrors");
6487     ok(r == ERROR_INVALID_HANDLE,
6488        "Expected ERROR_INVALID_HANDLE, got %d\n", r);
6489
6490     /* hDatabaseMerge is invalid */
6491     r = MsiDatabaseMergeA(hdb, 0, "MergeErrors");
6492     ok(r == ERROR_INVALID_HANDLE,
6493        "Expected ERROR_INVALID_HANDLE, got %d\n", r);
6494
6495     /* szTableName is NULL */
6496     r = MsiDatabaseMergeA(hdb, href, NULL);
6497     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6498
6499     /* szTableName is empty */
6500     r = MsiDatabaseMergeA(hdb, href, "");
6501     ok(r == ERROR_INVALID_TABLE, "Expected ERROR_INVALID_TABLE, got %d\n", r);
6502
6503     /* both DBs empty, szTableName is valid */
6504     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
6505     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6506
6507     query = "CREATE TABLE `One` ( `A` INT PRIMARY KEY `A` )";
6508     r = run_query(hdb, 0, query);
6509     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6510
6511     query = "CREATE TABLE `One` ( `A` CHAR(72) PRIMARY KEY `A` )";
6512     r = run_query(href, 0, query);
6513     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6514
6515     /* column types don't match */
6516     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
6517     ok(r == ERROR_DATATYPE_MISMATCH,
6518        "Expected ERROR_DATATYPE_MISMATCH, got %d\n", r);
6519
6520     /* nothing in MergeErrors */
6521     query = "SELECT * FROM `MergeErrors`";
6522     r = do_query(hdb, query, &hrec);
6523     ok(r == ERROR_BAD_QUERY_SYNTAX,
6524        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6525
6526     query = "DROP TABLE `One`";
6527     r = run_query(hdb, 0, query);
6528     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6529
6530     query = "DROP TABLE `One`";
6531     r = run_query(href, 0, query);
6532     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6533
6534     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A` )";
6535     r = run_query(hdb, 0, query);
6536     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6537
6538     query = "CREATE TABLE `One` ( `A` INT, `C` INT PRIMARY KEY `A` )";
6539     r = run_query(href, 0, query);
6540     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6541
6542     /* column names don't match */
6543     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
6544     ok(r == ERROR_DATATYPE_MISMATCH,
6545        "Expected ERROR_DATATYPE_MISMATCH, got %d\n", r);
6546
6547     /* nothing in MergeErrors */
6548     query = "SELECT * FROM `MergeErrors`";
6549     r = do_query(hdb, query, &hrec);
6550     ok(r == ERROR_BAD_QUERY_SYNTAX,
6551        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6552
6553     query = "DROP TABLE `One`";
6554     r = run_query(hdb, 0, query);
6555     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6556
6557     query = "DROP TABLE `One`";
6558     r = run_query(href, 0, query);
6559     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6560
6561     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A` )";
6562     r = run_query(hdb, 0, query);
6563     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6564
6565     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `B` )";
6566     r = run_query(href, 0, query);
6567     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6568
6569     /* primary keys don't match */
6570     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
6571     ok(r == ERROR_DATATYPE_MISMATCH,
6572        "Expected ERROR_DATATYPE_MISMATCH, got %d\n", r);
6573
6574     /* nothing in MergeErrors */
6575     query = "SELECT * FROM `MergeErrors`";
6576     r = do_query(hdb, query, &hrec);
6577     ok(r == ERROR_BAD_QUERY_SYNTAX,
6578        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6579
6580     query = "DROP TABLE `One`";
6581     r = run_query(hdb, 0, query);
6582     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6583
6584     query = "DROP TABLE `One`";
6585     r = run_query(href, 0, query);
6586     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6587
6588     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A` )";
6589     r = run_query(hdb, 0, query);
6590     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6591
6592     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A`, `B` )";
6593     r = run_query(href, 0, query);
6594     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6595
6596     /* number of primary keys doesn't match */
6597     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
6598     ok(r == ERROR_DATATYPE_MISMATCH,
6599        "Expected ERROR_DATATYPE_MISMATCH, got %d\n", r);
6600
6601     /* nothing in MergeErrors */
6602     query = "SELECT * FROM `MergeErrors`";
6603     r = do_query(hdb, query, &hrec);
6604     ok(r == ERROR_BAD_QUERY_SYNTAX,
6605        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6606
6607     query = "DROP TABLE `One`";
6608     r = run_query(hdb, 0, query);
6609     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6610
6611     query = "DROP TABLE `One`";
6612     r = run_query(href, 0, query);
6613     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6614
6615     query = "CREATE TABLE `One` ( `A` INT, `B` INT, `C` INT PRIMARY KEY `A` )";
6616     r = run_query(hdb, 0, query);
6617     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6618
6619     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A` )";
6620     r = run_query(href, 0, query);
6621     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6622
6623     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 1, 2 )";
6624     r = run_query(href, 0, query);
6625     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6626
6627     /* number of columns doesn't match */
6628     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
6629     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6630
6631     query = "SELECT * FROM `One`";
6632     r = do_query(hdb, query, &hrec);
6633     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6634
6635     r = MsiRecordGetInteger(hrec, 1);
6636     ok(r == 1, "Expected 1, got %d\n", r);
6637
6638     r = MsiRecordGetInteger(hrec, 2);
6639     ok(r == 2, "Expected 2, got %d\n", r);
6640
6641     r = MsiRecordGetInteger(hrec, 3);
6642     ok(r == MSI_NULL_INTEGER, "Expected MSI_NULL_INTEGER, got %d\n", r);
6643
6644     MsiCloseHandle(hrec);
6645
6646     /* nothing in MergeErrors */
6647     query = "SELECT * FROM `MergeErrors`";
6648     r = do_query(hdb, query, &hrec);
6649     ok(r == ERROR_BAD_QUERY_SYNTAX,
6650        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6651
6652     query = "DROP TABLE `One`";
6653     r = run_query(hdb, 0, query);
6654     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6655
6656     query = "DROP TABLE `One`";
6657     r = run_query(href, 0, query);
6658     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6659
6660     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A` )";
6661     r = run_query(hdb, 0, query);
6662     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6663
6664     query = "CREATE TABLE `One` ( `A` INT, `B` INT, `C` INT PRIMARY KEY `A` )";
6665     r = run_query(href, 0, query);
6666     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6667
6668     query = "INSERT INTO `One` ( `A`, `B`, `C` ) VALUES ( 1, 2, 3 )";
6669     r = run_query(href, 0, query);
6670     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6671
6672     /* number of columns doesn't match */
6673     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
6674     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6675
6676     query = "SELECT * FROM `One`";
6677     r = do_query(hdb, query, &hrec);
6678     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6679
6680     r = MsiRecordGetInteger(hrec, 1);
6681     ok(r == 1, "Expected 1, got %d\n", r);
6682
6683     r = MsiRecordGetInteger(hrec, 2);
6684     ok(r == 2, "Expected 2, got %d\n", r);
6685
6686     r = MsiRecordGetInteger(hrec, 3);
6687     ok(r == MSI_NULL_INTEGER, "Expected MSI_NULL_INTEGER, got %d\n", r);
6688
6689     MsiCloseHandle(hrec);
6690
6691     /* nothing in MergeErrors */
6692     query = "SELECT * FROM `MergeErrors`";
6693     r = do_query(hdb, query, &hrec);
6694     ok(r == ERROR_BAD_QUERY_SYNTAX,
6695        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6696
6697     query = "DROP TABLE `One`";
6698     r = run_query(hdb, 0, query);
6699     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6700
6701     query = "DROP TABLE `One`";
6702     r = run_query(href, 0, query);
6703     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6704
6705     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A` )";
6706     r = run_query(hdb, 0, query);
6707     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6708
6709     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 1, 1 )";
6710     r = run_query(hdb, 0, query);
6711     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6712
6713     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 2, 2 )";
6714     r = run_query(hdb, 0, query);
6715     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6716
6717     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A` )";
6718     r = run_query(href, 0, query);
6719     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6720
6721     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 1, 2 )";
6722     r = run_query(href, 0, query);
6723     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6724
6725     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 2, 3 )";
6726     r = run_query(href, 0, query);
6727     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6728
6729     /* primary keys match, rows do not */
6730     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
6731     ok(r == ERROR_FUNCTION_FAILED,
6732        "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
6733
6734     /* nothing in MergeErrors */
6735     query = "SELECT * FROM `MergeErrors`";
6736     r = do_query(hdb, query, &hrec);
6737     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6738
6739     size = MAX_PATH;
6740     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6741     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6742     ok(!lstrcmpA(buf, "One"), "Expected \"One\", got \"%s\"\n", buf);
6743
6744     r = MsiRecordGetInteger(hrec, 2);
6745     ok(r == 2, "Expected 2, got %d\n", r);
6746
6747     MsiCloseHandle(hrec);
6748
6749     r = MsiDatabaseOpenViewA(hdb, "SELECT * FROM `MergeErrors`", &hview);
6750     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6751
6752     r = MsiViewGetColumnInfo(hview, MSICOLINFO_NAMES, &hrec);
6753     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6754
6755     size = MAX_PATH;
6756     r = MsiRecordGetString(hrec, 1, buf, &size);
6757     ok(!lstrcmpA(buf, "Table"), "Expected \"Table\", got \"%s\"\n", buf);
6758
6759     size = MAX_PATH;
6760     r = MsiRecordGetString(hrec, 2, buf, &size);
6761     ok(!lstrcmpA(buf, "NumRowMergeConflicts"),
6762        "Expected \"NumRowMergeConflicts\", got \"%s\"\n", buf);
6763
6764     MsiCloseHandle(hrec);
6765
6766     r = MsiViewGetColumnInfo(hview, MSICOLINFO_TYPES, &hrec);
6767     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6768
6769     size = MAX_PATH;
6770     r = MsiRecordGetString(hrec, 1, buf, &size);
6771     ok(!lstrcmpA(buf, "s255"), "Expected \"s255\", got \"%s\"\n", buf);
6772
6773     size = MAX_PATH;
6774     r = MsiRecordGetString(hrec, 2, buf, &size);
6775     ok(!lstrcmpA(buf, "i2"), "Expected \"i2\", got \"%s\"\n", buf);
6776
6777     MsiCloseHandle(hrec);
6778     MsiViewClose(hview);
6779     MsiCloseHandle(hview);
6780
6781     query = "DROP TABLE `MergeErrors`";
6782     r = run_query(hdb, 0, query);
6783     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6784
6785     create_file_data("codepage.idt", "\r\n\r\n850\t_ForceCodepage\r\n", 0);
6786
6787     GetCurrentDirectoryA(MAX_PATH, buf);
6788     r = MsiDatabaseImportA(hdb, buf, "codepage.idt");
6789     todo_wine
6790     {
6791         ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6792     }
6793
6794     query = "DROP TABLE `One`";
6795     r = run_query(hdb, 0, query);
6796     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6797
6798     query = "DROP TABLE `One`";
6799     r = run_query(href, 0, query);
6800     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6801
6802     query = "CREATE TABLE `One` ( "
6803             "`A` INT, `B` CHAR(72) LOCALIZABLE PRIMARY KEY `A` )";
6804     r = run_query(hdb, 0, query);
6805     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6806
6807     query = "CREATE TABLE `One` ( "
6808             "`A` INT, `B` CHAR(72) LOCALIZABLE PRIMARY KEY `A` )";
6809     r = run_query(href, 0, query);
6810     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6811
6812     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 1, 'hi' )";
6813     r = run_query(href, 0, query);
6814     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6815
6816     /* code page does not match */
6817     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
6818     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6819
6820     query = "SELECT * FROM `One`";
6821     r = do_query(hdb, query, &hrec);
6822     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6823
6824     r = MsiRecordGetInteger(hrec, 1);
6825     ok(r == 1, "Expected 1, got %d\n", r);
6826
6827     size = MAX_PATH;
6828     r = MsiRecordGetStringA(hrec, 2, buf, &size);
6829     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6830     ok(!lstrcmpA(buf, "hi"), "Expected \"hi\", got \"%s\"\n", buf);
6831
6832     MsiCloseHandle(hrec);
6833
6834     /* nothing in MergeErrors */
6835     query = "SELECT * FROM `MergeErrors`";
6836     r = do_query(hdb, query, &hrec);
6837     ok(r == ERROR_BAD_QUERY_SYNTAX,
6838        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6839
6840     query = "DROP TABLE `One`";
6841     r = run_query(hdb, 0, query);
6842     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6843
6844     query = "DROP TABLE `One`";
6845     r = run_query(href, 0, query);
6846     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6847
6848     query = "CREATE TABLE `One` ( `A` INT, `B` OBJECT PRIMARY KEY `A` )";
6849     r = run_query(hdb, 0, query);
6850     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6851
6852     query = "CREATE TABLE `One` ( `A` INT, `B` OBJECT PRIMARY KEY `A` )";
6853     r = run_query(href, 0, query);
6854     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6855
6856     create_file("binary.dat");
6857     hrec = MsiCreateRecord(1);
6858     MsiRecordSetStreamA(hrec, 1, "binary.dat");
6859
6860     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 1, ? )";
6861     r = run_query(href, hrec, query);
6862     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6863
6864     MsiCloseHandle(hrec);
6865
6866     /* binary data to merge */
6867     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
6868     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6869
6870     query = "SELECT * FROM `One`";
6871     r = do_query(hdb, query, &hrec);
6872     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6873
6874     r = MsiRecordGetInteger(hrec, 1);
6875     ok(r == 1, "Expected 1, got %d\n", r);
6876
6877     size = MAX_PATH;
6878     ZeroMemory(buf, MAX_PATH);
6879     r = MsiRecordReadStream(hrec, 2, buf, &size);
6880     todo_wine
6881     {
6882         ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6883         ok(!lstrcmpA(buf, "binary.dat\n"),
6884            "Expected \"binary.dat\\n\", got \"%s\"\n", buf);
6885     }
6886
6887     MsiCloseHandle(hrec);
6888
6889     /* nothing in MergeErrors */
6890     query = "SELECT * FROM `MergeErrors`";
6891     r = do_query(hdb, query, &hrec);
6892     ok(r == ERROR_BAD_QUERY_SYNTAX,
6893        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6894
6895     MsiCloseHandle(hdb);
6896     MsiCloseHandle(href);
6897     DeleteFileA(msifile);
6898     DeleteFileA("refdb.msi");
6899     DeleteFileA("codepage.idt");
6900     DeleteFileA("binary.dat");
6901 }
6902
6903 UINT ordervals[6][3] =
6904 {
6905     { MSI_NULL_INTEGER, 12, 13 },
6906     { 1, 2, 3 },
6907     { 6, 4, 5 },
6908     { 8, 9, 7 },
6909     { 10, 11, MSI_NULL_INTEGER },
6910     { 14, MSI_NULL_INTEGER, 15 }
6911 };
6912
6913 static void test_insertorder(void)
6914 {
6915     MSIHANDLE hdb, view, rec;
6916     LPCSTR query;
6917     UINT r;
6918     int i;
6919
6920     hdb = create_db();
6921     ok(hdb, "failed to create db\n");
6922
6923     query = "CREATE TABLE `T` ( `A` SHORT, `B` SHORT, `C` SHORT PRIMARY KEY `A`)";
6924     r = run_query(hdb, 0, query);
6925     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6926
6927     query = "INSERT INTO `T` ( `A`, `B`, `C` ) VALUES ( 1, 2, 3 )";
6928     r = run_query(hdb, 0, query);
6929     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6930
6931     query = "INSERT INTO `T` ( `B`, `C`, `A` ) VALUES ( 4, 5, 6 )";
6932     r = run_query(hdb, 0, query);
6933     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6934
6935     query = "INSERT INTO `T` ( `C`, `A`, `B` ) VALUES ( 7, 8, 9 )";
6936     r = run_query(hdb, 0, query);
6937     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6938
6939     query = "INSERT INTO `T` ( `A`, `B` ) VALUES ( 10, 11 )";
6940     r = run_query(hdb, 0, query);
6941     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6942
6943     query = "INSERT INTO `T` ( `B`, `C` ) VALUES ( 12, 13 )";
6944     r = run_query(hdb, 0, query);
6945     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6946
6947     /* fails because the primary key already
6948      * has an MSI_NULL_INTEGER value set above
6949      */
6950     query = "INSERT INTO `T` ( `C` ) VALUES ( 14 )";
6951     r = run_query(hdb, 0, query);
6952     ok(r == ERROR_FUNCTION_FAILED,
6953        "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
6954
6955     /* replicate the error where primary key is set twice */
6956     query = "INSERT INTO `T` ( `A`, `C` ) VALUES ( 1, 14 )";
6957     r = run_query(hdb, 0, query);
6958     ok(r == ERROR_FUNCTION_FAILED,
6959        "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
6960
6961     query = "INSERT INTO `T` ( `A`, `C` ) VALUES ( 14, 15 )";
6962     r = run_query(hdb, 0, query);
6963     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6964
6965     query = "INSERT INTO `T` VALUES ( 16 )";
6966     r = run_query(hdb, 0, query);
6967     ok(r == ERROR_BAD_QUERY_SYNTAX,
6968        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6969
6970     query = "INSERT INTO `T` VALUES ( 17, 18 )";
6971     r = run_query(hdb, 0, query);
6972     ok(r == ERROR_BAD_QUERY_SYNTAX,
6973        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6974
6975     query = "INSERT INTO `T` VALUES ( 19, 20, 21 )";
6976     r = run_query(hdb, 0, query);
6977     ok(r == ERROR_BAD_QUERY_SYNTAX,
6978        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6979
6980     query = "SELECT * FROM `T`";
6981     r = MsiDatabaseOpenView(hdb, query, &view);
6982     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6983     r = MsiViewExecute(view, 0);
6984     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6985
6986     for (i = 0; i < 6; i++)
6987     {
6988         r = MsiViewFetch(view, &rec);
6989         ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6990
6991         r = MsiRecordGetInteger(rec, 1);
6992         ok(r == ordervals[i][0], "Expected %d, got %d\n", ordervals[i][0], r);
6993
6994         r = MsiRecordGetInteger(rec, 2);
6995         ok(r == ordervals[i][1], "Expected %d, got %d\n", ordervals[i][1], r);
6996
6997         r = MsiRecordGetInteger(rec, 3);
6998         ok(r == ordervals[i][2], "Expected %d, got %d\n", ordervals[i][2], r);
6999
7000         MsiCloseHandle(rec);
7001     }
7002
7003     r = MsiViewFetch(view, &rec);
7004     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7005
7006     MsiViewClose(view);
7007     MsiCloseHandle(view);
7008     MsiCloseHandle(hdb);
7009     DeleteFileA(msifile);
7010 }
7011
7012 static void test_columnorder(void)
7013 {
7014     MSIHANDLE hdb, view, rec;
7015     char buf[MAX_PATH];
7016     LPCSTR query;
7017     DWORD sz;
7018     UINT r;
7019
7020     hdb = create_db();
7021     ok(hdb, "failed to create db\n");
7022
7023     /* Each column is a slot:
7024      * ---------------------
7025      * | B | C | A | E | D |
7026      * ---------------------
7027      *
7028      * When a column is selected as a primary key,
7029      * the column occupying the nth primary key slot is swapped
7030      * with the current position of the primary key in question:
7031      *
7032      * set primary key `D`
7033      * ---------------------    ---------------------
7034      * | B | C | A | E | D | -> | D | C | A | E | B |
7035      * ---------------------    ---------------------
7036      *
7037      * set primary key `E`
7038      * ---------------------    ---------------------
7039      * | D | C | A | E | B | -> | D | E | A | C | B |
7040      * ---------------------    ---------------------
7041      */
7042
7043     query = "CREATE TABLE `T` ( `B` SHORT NOT NULL, `C` SHORT NOT NULL, "
7044             "`A` CHAR(255), `E` INT, `D` CHAR(255) NOT NULL "
7045             "PRIMARY KEY `D`, `E`)";
7046     r = run_query(hdb, 0, query);
7047     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7048
7049     query = "SELECT * FROM `T`";
7050     r = MsiDatabaseOpenView(hdb, query, &view);
7051     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7052
7053     r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
7054     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7055
7056     sz = MAX_PATH;
7057     lstrcpyA(buf, "kiwi");
7058     r = MsiRecordGetString(rec, 1, buf, &sz);
7059     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7060     ok(!lstrcmpA("s255", buf), "Expected \"s255\", got \"%s\"\n", buf);
7061
7062     sz = MAX_PATH;
7063     lstrcpyA(buf, "kiwi");
7064     r = MsiRecordGetString(rec, 2, buf, &sz);
7065     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7066     ok(!lstrcmpA("I2", buf), "Expected \"I2\", got \"%s\"\n", buf);
7067
7068     sz = MAX_PATH;
7069     lstrcpyA(buf, "kiwi");
7070     r = MsiRecordGetString(rec, 3, buf, &sz);
7071     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7072     ok(!lstrcmpA("S255", buf), "Expected \"S255\", got \"%s\"\n", buf);
7073
7074     sz = MAX_PATH;
7075     lstrcpyA(buf, "kiwi");
7076     r = MsiRecordGetString(rec, 4, buf, &sz);
7077     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7078     ok(!lstrcmpA("i2", buf), "Expected \"i2\", got \"%s\"\n", buf);
7079
7080     sz = MAX_PATH;
7081     lstrcpyA(buf, "kiwi");
7082     r = MsiRecordGetString(rec, 5, buf, &sz);
7083     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7084     ok(!lstrcmpA("i2", buf), "Expected \"i2\", got \"%s\"\n", buf);
7085
7086     MsiCloseHandle(rec);
7087
7088     r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec);
7089     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7090
7091     sz = MAX_PATH;
7092     lstrcpyA(buf, "kiwi");
7093     r = MsiRecordGetString(rec, 1, buf, &sz);
7094     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7095     ok(!lstrcmpA("D", buf), "Expected \"D\", got \"%s\"\n", buf);
7096
7097     sz = MAX_PATH;
7098     lstrcpyA(buf, "kiwi");
7099     r = MsiRecordGetString(rec, 2, buf, &sz);
7100     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7101     ok(!lstrcmpA("E", buf), "Expected \"E\", got \"%s\"\n", buf);
7102
7103     sz = MAX_PATH;
7104     lstrcpyA(buf, "kiwi");
7105     r = MsiRecordGetString(rec, 3, buf, &sz);
7106     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7107     ok(!lstrcmpA("A", buf), "Expected \"A\", got \"%s\"\n", buf);
7108
7109     sz = MAX_PATH;
7110     lstrcpyA(buf, "kiwi");
7111     r = MsiRecordGetString(rec, 4, buf, &sz);
7112     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7113     ok(!lstrcmpA("C", buf), "Expected \"C\", got \"%s\"\n", buf);
7114
7115     sz = MAX_PATH;
7116     lstrcpyA(buf, "kiwi");
7117     r = MsiRecordGetString(rec, 5, buf, &sz);
7118     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7119     ok(!lstrcmpA("B", buf), "Expected \"B\", got \"%s\"\n", buf);
7120
7121     MsiCloseHandle(rec);
7122     MsiViewClose(view);
7123     MsiCloseHandle(view);
7124
7125     query = "INSERT INTO `T` ( `B`, `C`, `A`, `E`, `D` ) "
7126             "VALUES ( 1, 2, 'a', 3, 'bc' )";
7127     r = run_query(hdb, 0, query);
7128     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7129
7130     query = "SELECT * FROM `T`";
7131     r = do_query(hdb, query, &rec);
7132
7133     sz = MAX_PATH;
7134     lstrcpyA(buf, "kiwi");
7135     r = MsiRecordGetString(rec, 1, buf, &sz);
7136     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7137     ok(!lstrcmpA("bc", buf), "Expected \"bc\", got \"%s\"\n", buf);
7138
7139     r = MsiRecordGetInteger(rec, 2);
7140     ok(r == 3, "Expected 3, got %d\n", r);
7141
7142     sz = MAX_PATH;
7143     lstrcpyA(buf, "kiwi");
7144     r = MsiRecordGetString(rec, 3, buf, &sz);
7145     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7146     ok(!lstrcmpA("a", buf), "Expected \"a\", got \"%s\"\n", buf);
7147
7148     r = MsiRecordGetInteger(rec, 4);
7149     ok(r == 2, "Expected 2, got %d\n", r);
7150
7151     r = MsiRecordGetInteger(rec, 5);
7152     ok(r == 1, "Expected 1, got %d\n", r);
7153
7154     MsiCloseHandle(rec);
7155
7156     query = "SELECT * FROM `_Columns` WHERE `Table` = 'T'";
7157     r = MsiDatabaseOpenView(hdb, query, &view);
7158     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7159     r = MsiViewExecute(view, 0);
7160     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7161
7162     r = MsiViewFetch(view, &rec);
7163     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
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("T", buf), "Expected \"T\", got \"%s\"\n", buf);
7170
7171     r = MsiRecordGetInteger(rec, 2);
7172     ok(r == 1, "Expected 1, 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("D", buf), "Expected \"D\", got \"%s\"\n", buf);
7179
7180     MsiCloseHandle(rec);
7181
7182     r = MsiViewFetch(view, &rec);
7183     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7184
7185     sz = MAX_PATH;
7186     lstrcpyA(buf, "kiwi");
7187     r = MsiRecordGetString(rec, 1, buf, &sz);
7188     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7189     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
7190
7191     r = MsiRecordGetInteger(rec, 2);
7192     ok(r == 2, "Expected 2, got %d\n", r);
7193
7194     sz = MAX_PATH;
7195     lstrcpyA(buf, "kiwi");
7196     r = MsiRecordGetString(rec, 3, buf, &sz);
7197     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7198     ok(!lstrcmpA("E", buf), "Expected \"E\", got \"%s\"\n", buf);
7199
7200     MsiCloseHandle(rec);
7201
7202     r = MsiViewFetch(view, &rec);
7203     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7204
7205     sz = MAX_PATH;
7206     lstrcpyA(buf, "kiwi");
7207     r = MsiRecordGetString(rec, 1, buf, &sz);
7208     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7209     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
7210
7211     r = MsiRecordGetInteger(rec, 2);
7212     ok(r == 3, "Expected 3, got %d\n", r);
7213
7214     sz = MAX_PATH;
7215     lstrcpyA(buf, "kiwi");
7216     r = MsiRecordGetString(rec, 3, buf, &sz);
7217     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7218     ok(!lstrcmpA("A", buf), "Expected \"A\", got \"%s\"\n", buf);
7219
7220     MsiCloseHandle(rec);
7221
7222     r = MsiViewFetch(view, &rec);
7223     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7224
7225     sz = MAX_PATH;
7226     lstrcpyA(buf, "kiwi");
7227     r = MsiRecordGetString(rec, 1, buf, &sz);
7228     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7229     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
7230
7231     r = MsiRecordGetInteger(rec, 2);
7232     ok(r == 4, "Expected 4, got %d\n", r);
7233
7234     sz = MAX_PATH;
7235     lstrcpyA(buf, "kiwi");
7236     r = MsiRecordGetString(rec, 3, buf, &sz);
7237     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7238     ok(!lstrcmpA("C", buf), "Expected \"C\", got \"%s\"\n", buf);
7239
7240     MsiCloseHandle(rec);
7241
7242     r = MsiViewFetch(view, &rec);
7243     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7244
7245     sz = MAX_PATH;
7246     lstrcpyA(buf, "kiwi");
7247     r = MsiRecordGetString(rec, 1, buf, &sz);
7248     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7249     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
7250
7251     r = MsiRecordGetInteger(rec, 2);
7252     ok(r == 5, "Expected 5, got %d\n", r);
7253
7254     sz = MAX_PATH;
7255     lstrcpyA(buf, "kiwi");
7256     r = MsiRecordGetString(rec, 3, buf, &sz);
7257     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7258     ok(!lstrcmpA("B", buf), "Expected \"B\", got \"%s\"\n", buf);
7259
7260     MsiCloseHandle(rec);
7261
7262     r = MsiViewFetch(view, &rec);
7263     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7264
7265     MsiViewClose(view);
7266     MsiCloseHandle(view);
7267
7268     query = "CREATE TABLE `Z` ( `B` SHORT NOT NULL, `C` SHORT NOT NULL, "
7269             "`A` CHAR(255), `E` INT, `D` CHAR(255) NOT NULL "
7270             "PRIMARY KEY `C`, `A`, `D`)";
7271     r = run_query(hdb, 0, query);
7272     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7273
7274     query = "SELECT * FROM `Z`";
7275     r = MsiDatabaseOpenView(hdb, query, &view);
7276     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7277
7278     r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
7279     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7280
7281     sz = MAX_PATH;
7282     lstrcpyA(buf, "kiwi");
7283     r = MsiRecordGetString(rec, 1, buf, &sz);
7284     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7285     ok(!lstrcmpA("i2", buf), "Expected \"i2\", got \"%s\"\n", buf);
7286
7287     sz = MAX_PATH;
7288     lstrcpyA(buf, "kiwi");
7289     r = MsiRecordGetString(rec, 2, buf, &sz);
7290     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7291     ok(!lstrcmpA("S255", buf), "Expected \"S255\", got \"%s\"\n", buf);
7292
7293     sz = MAX_PATH;
7294     lstrcpyA(buf, "kiwi");
7295     r = MsiRecordGetString(rec, 3, buf, &sz);
7296     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7297     ok(!lstrcmpA("s255", buf), "Expected \"s255\", got \"%s\"\n", buf);
7298
7299     sz = MAX_PATH;
7300     lstrcpyA(buf, "kiwi");
7301     r = MsiRecordGetString(rec, 4, buf, &sz);
7302     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7303     ok(!lstrcmpA("I2", buf), "Expected \"I2\", got \"%s\"\n", buf);
7304
7305     sz = MAX_PATH;
7306     lstrcpyA(buf, "kiwi");
7307     r = MsiRecordGetString(rec, 5, buf, &sz);
7308     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7309     ok(!lstrcmpA("i2", buf), "Expected \"i2\", got \"%s\"\n", buf);
7310
7311     MsiCloseHandle(rec);
7312
7313     r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec);
7314     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7315
7316     sz = MAX_PATH;
7317     lstrcpyA(buf, "kiwi");
7318     r = MsiRecordGetString(rec, 1, buf, &sz);
7319     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7320     ok(!lstrcmpA("C", buf), "Expected \"C\", got \"%s\"\n", buf);
7321
7322     sz = MAX_PATH;
7323     lstrcpyA(buf, "kiwi");
7324     r = MsiRecordGetString(rec, 2, buf, &sz);
7325     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7326     ok(!lstrcmpA("A", buf), "Expected \"A\", got \"%s\"\n", buf);
7327
7328     sz = MAX_PATH;
7329     lstrcpyA(buf, "kiwi");
7330     r = MsiRecordGetString(rec, 3, buf, &sz);
7331     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7332     ok(!lstrcmpA("D", buf), "Expected \"D\", got \"%s\"\n", buf);
7333
7334     sz = MAX_PATH;
7335     lstrcpyA(buf, "kiwi");
7336     r = MsiRecordGetString(rec, 4, buf, &sz);
7337     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7338     ok(!lstrcmpA("E", buf), "Expected \"E\", got \"%s\"\n", buf);
7339
7340     sz = MAX_PATH;
7341     lstrcpyA(buf, "kiwi");
7342     r = MsiRecordGetString(rec, 5, buf, &sz);
7343     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7344     ok(!lstrcmpA("B", buf), "Expected \"B\", got \"%s\"\n", buf);
7345
7346     MsiCloseHandle(rec);
7347     MsiViewClose(view);
7348     MsiCloseHandle(view);
7349
7350     query = "INSERT INTO `Z` ( `B`, `C`, `A`, `E`, `D` ) "
7351             "VALUES ( 1, 2, 'a', 3, 'bc' )";
7352     r = run_query(hdb, 0, query);
7353     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7354
7355     query = "SELECT * FROM `Z`";
7356     r = do_query(hdb, query, &rec);
7357
7358     r = MsiRecordGetInteger(rec, 1);
7359     ok(r == 2, "Expected 2, got %d\n", r);
7360
7361     sz = MAX_PATH;
7362     lstrcpyA(buf, "kiwi");
7363     r = MsiRecordGetString(rec, 2, buf, &sz);
7364     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7365     ok(!lstrcmpA("a", buf), "Expected \"a\", got \"%s\"\n", buf);
7366
7367     sz = MAX_PATH;
7368     lstrcpyA(buf, "kiwi");
7369     r = MsiRecordGetString(rec, 3, buf, &sz);
7370     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7371     ok(!lstrcmpA("bc", buf), "Expected \"bc\", got \"%s\"\n", buf);
7372
7373     r = MsiRecordGetInteger(rec, 4);
7374     ok(r == 3, "Expected 3, got %d\n", r);
7375
7376     r = MsiRecordGetInteger(rec, 5);
7377     ok(r == 1, "Expected 1, got %d\n", r);
7378
7379     MsiCloseHandle(rec);
7380
7381     query = "SELECT * FROM `_Columns` WHERE `Table` = 'T'";
7382     r = MsiDatabaseOpenView(hdb, query, &view);
7383     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7384     r = MsiViewExecute(view, 0);
7385     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7386
7387     r = MsiViewFetch(view, &rec);
7388     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7389
7390     sz = MAX_PATH;
7391     lstrcpyA(buf, "kiwi");
7392     r = MsiRecordGetString(rec, 1, buf, &sz);
7393     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7394     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
7395
7396     r = MsiRecordGetInteger(rec, 2);
7397     ok(r == 1, "Expected 1, got %d\n", r);
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("D", buf), "Expected \"D\", got \"%s\"\n", buf);
7404
7405     MsiCloseHandle(rec);
7406
7407     r = MsiViewFetch(view, &rec);
7408     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7409
7410     sz = MAX_PATH;
7411     lstrcpyA(buf, "kiwi");
7412     r = MsiRecordGetString(rec, 1, buf, &sz);
7413     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7414     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
7415
7416     r = MsiRecordGetInteger(rec, 2);
7417     ok(r == 2, "Expected 2, got %d\n", r);
7418
7419     sz = MAX_PATH;
7420     lstrcpyA(buf, "kiwi");
7421     r = MsiRecordGetString(rec, 3, buf, &sz);
7422     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7423     ok(!lstrcmpA("E", buf), "Expected \"E\", got \"%s\"\n", buf);
7424
7425     MsiCloseHandle(rec);
7426
7427     r = MsiViewFetch(view, &rec);
7428     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7429
7430     sz = MAX_PATH;
7431     lstrcpyA(buf, "kiwi");
7432     r = MsiRecordGetString(rec, 1, buf, &sz);
7433     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7434     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
7435
7436     r = MsiRecordGetInteger(rec, 2);
7437     ok(r == 3, "Expected 3, got %d\n", r);
7438
7439     sz = MAX_PATH;
7440     lstrcpyA(buf, "kiwi");
7441     r = MsiRecordGetString(rec, 3, buf, &sz);
7442     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7443     ok(!lstrcmpA("A", buf), "Expected \"A\", got \"%s\"\n", buf);
7444
7445     MsiCloseHandle(rec);
7446
7447     r = MsiViewFetch(view, &rec);
7448     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7449
7450     sz = MAX_PATH;
7451     lstrcpyA(buf, "kiwi");
7452     r = MsiRecordGetString(rec, 1, buf, &sz);
7453     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7454     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
7455
7456     r = MsiRecordGetInteger(rec, 2);
7457     ok(r == 4, "Expected 4, got %d\n", r);
7458
7459     sz = MAX_PATH;
7460     lstrcpyA(buf, "kiwi");
7461     r = MsiRecordGetString(rec, 3, buf, &sz);
7462     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7463     ok(!lstrcmpA("C", buf), "Expected \"C\", got \"%s\"\n", buf);
7464
7465     MsiCloseHandle(rec);
7466
7467     r = MsiViewFetch(view, &rec);
7468     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7469
7470     sz = MAX_PATH;
7471     lstrcpyA(buf, "kiwi");
7472     r = MsiRecordGetString(rec, 1, buf, &sz);
7473     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7474     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
7475
7476     r = MsiRecordGetInteger(rec, 2);
7477     ok(r == 5, "Expected 5, got %d\n", r);
7478
7479     sz = MAX_PATH;
7480     lstrcpyA(buf, "kiwi");
7481     r = MsiRecordGetString(rec, 3, buf, &sz);
7482     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7483     ok(!lstrcmpA("B", buf), "Expected \"B\", got \"%s\"\n", buf);
7484
7485     MsiCloseHandle(rec);
7486
7487     r = MsiViewFetch(view, &rec);
7488     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7489
7490     MsiViewClose(view);
7491     MsiCloseHandle(view);
7492
7493     MsiCloseHandle(hdb);
7494     DeleteFileA(msifile);
7495 }
7496
7497 START_TEST(db)
7498 {
7499     test_msidatabase();
7500     test_msiinsert();
7501     test_msidecomposedesc();
7502     test_msibadqueries();
7503     test_viewmodify();
7504     test_viewgetcolumninfo();
7505     test_getcolinfo();
7506     test_msiexport();
7507     test_longstrings();
7508     test_streamtable();
7509     test_where();
7510     test_msiimport();
7511     test_markers();
7512     test_handle_limit();
7513     test_try_transform();
7514     test_join();
7515     test_temporary_table();
7516     test_alter();
7517     test_integers();
7518     test_update();
7519     test_special_tables();
7520     test_select_markers();
7521     test_viewmodify_update();
7522     test_stringtable();
7523     test_viewmodify_delete();
7524     test_defaultdatabase();
7525     test_order();
7526     test_viewmodify_delete_temporary();
7527     test_deleterow();
7528     test_quotes();
7529     test_carriagereturn();
7530     test_noquotes();
7531     test_forcecodepage();
7532     test_viewmodify_refresh();
7533     test_where_viewmodify();
7534     test_storages_table();
7535     test_dbtopackage();
7536     test_droptable();
7537     test_dbmerge();
7538     test_insertorder();
7539     test_columnorder();
7540 }