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