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