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