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