wined3d: Handle stateblock capture for default lights created while recording.
[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     MsiCloseHandle(hdb);
3649     DeleteFile(msifile);
3650 }
3651
3652 static void test_temporary_table(void)
3653 {
3654     MSICONDITION cond;
3655     MSIHANDLE hdb = 0, view = 0, rec;
3656     const char *query;
3657     UINT r;
3658     char buf[0x10];
3659     DWORD sz;
3660
3661     cond = MsiDatabaseIsTablePersistent(0, NULL);
3662     ok( cond == MSICONDITION_ERROR, "wrong return condition\n");
3663
3664     hdb = create_db();
3665     ok( hdb, "failed to create db\n");
3666
3667     cond = MsiDatabaseIsTablePersistent(hdb, NULL);
3668     ok( cond == MSICONDITION_ERROR, "wrong return condition\n");
3669
3670     cond = MsiDatabaseIsTablePersistent(hdb, "_Tables");
3671     ok( cond == MSICONDITION_NONE, "wrong return condition\n");
3672
3673     cond = MsiDatabaseIsTablePersistent(hdb, "_Columns");
3674     ok( cond == MSICONDITION_NONE, "wrong return condition\n");
3675
3676     cond = MsiDatabaseIsTablePersistent(hdb, "_Storages");
3677     ok( cond == MSICONDITION_NONE, "wrong return condition\n");
3678
3679     cond = MsiDatabaseIsTablePersistent(hdb, "_Streams");
3680     ok( cond == MSICONDITION_NONE, "wrong return condition\n");
3681
3682     query = "CREATE TABLE `P` ( `B` SHORT NOT NULL, `C` CHAR(255) PRIMARY KEY `C`)";
3683     r = run_query(hdb, 0, query);
3684     ok(r == ERROR_SUCCESS, "failed to add table\n");
3685
3686     cond = MsiDatabaseIsTablePersistent(hdb, "P");
3687     ok( cond == MSICONDITION_TRUE, "wrong return condition\n");
3688
3689     query = "CREATE TABLE `P2` ( `B` SHORT NOT NULL, `C` CHAR(255) PRIMARY KEY `C`) HOLD";
3690     r = run_query(hdb, 0, query);
3691     ok(r == ERROR_SUCCESS, "failed to add table\n");
3692
3693     cond = MsiDatabaseIsTablePersistent(hdb, "P2");
3694     ok( cond == MSICONDITION_TRUE, "wrong return condition\n");
3695
3696     query = "CREATE TABLE `T` ( `B` SHORT NOT NULL TEMPORARY, `C` CHAR(255) TEMPORARY PRIMARY KEY `C`) HOLD";
3697     r = run_query(hdb, 0, query);
3698     ok(r == ERROR_SUCCESS, "failed to add table\n");
3699
3700     cond = MsiDatabaseIsTablePersistent(hdb, "T");
3701     ok( cond == MSICONDITION_FALSE, "wrong return condition\n");
3702
3703     query = "CREATE TABLE `T2` ( `B` SHORT NOT NULL TEMPORARY, `C` CHAR(255) TEMPORARY PRIMARY KEY `C`)";
3704     r = run_query(hdb, 0, query);
3705     ok(r == ERROR_SUCCESS, "failed to add table\n");
3706
3707     query = "SELECT * FROM `T2`";
3708     r = MsiDatabaseOpenView(hdb, query, &view);
3709     ok(r == ERROR_BAD_QUERY_SYNTAX,
3710        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
3711
3712     cond = MsiDatabaseIsTablePersistent(hdb, "T2");
3713     ok( cond == MSICONDITION_NONE, "wrong return condition\n");
3714
3715     query = "CREATE TABLE `T3` ( `B` SHORT NOT NULL TEMPORARY, `C` CHAR(255) PRIMARY KEY `C`)";
3716     r = run_query(hdb, 0, query);
3717     ok(r == ERROR_SUCCESS, "failed to add table\n");
3718
3719     cond = MsiDatabaseIsTablePersistent(hdb, "T3");
3720     ok( cond == MSICONDITION_TRUE, "wrong return condition\n");
3721
3722     query = "CREATE TABLE `T4` ( `B` SHORT NOT NULL, `C` CHAR(255) TEMPORARY PRIMARY KEY `C`)";
3723     r = run_query(hdb, 0, query);
3724     ok(r == ERROR_FUNCTION_FAILED, "failed to add table\n");
3725
3726     cond = MsiDatabaseIsTablePersistent(hdb, "T4");
3727     ok( cond == MSICONDITION_NONE, "wrong return condition\n");
3728
3729     query = "CREATE TABLE `T5` ( `B` SHORT NOT NULL TEMP, `C` CHAR(255) TEMP PRIMARY KEY `C`) HOLD";
3730     r = run_query(hdb, 0, query);
3731     ok(r == ERROR_BAD_QUERY_SYNTAX, "failed to add table\n");
3732
3733     query = "select * from `T`";
3734     r = MsiDatabaseOpenView(hdb, query, &view);
3735     ok(r == ERROR_SUCCESS, "failed to query table\n");
3736     r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
3737     ok(r == ERROR_SUCCESS, "failed to get column info\n");
3738
3739     sz = sizeof buf;
3740     r = MsiRecordGetString(rec, 1, buf, &sz);
3741     ok(r == ERROR_SUCCESS, "failed to get string\n");
3742     ok( 0 == strcmp("G255", buf), "wrong column type\n");
3743
3744     sz = sizeof buf;
3745     r = MsiRecordGetString(rec, 2, buf, &sz);
3746     ok(r == ERROR_SUCCESS, "failed to get string\n");
3747     ok( 0 == strcmp("j2", buf), "wrong column type\n");
3748
3749     MsiCloseHandle( rec );
3750     MsiViewClose( view );
3751     MsiCloseHandle( view );
3752
3753     /* query the table data */
3754     rec = 0;
3755     r = do_query(hdb, "select * from `_Tables` where `Name` = 'T'", &rec);
3756     ok( r == ERROR_SUCCESS, "temporary table exists in _Tables\n");
3757     MsiCloseHandle( rec );
3758
3759     /* query the column data */
3760     rec = 0;
3761     r = do_query(hdb, "select * from `_Columns` where `Table` = 'T' AND `Name` = 'B'", &rec);
3762     ok( r == ERROR_NO_MORE_ITEMS, "temporary table exists in _Columns\n");
3763     if (rec) MsiCloseHandle( rec );
3764
3765     r = do_query(hdb, "select * from `_Columns` where `Table` = 'T' AND `Name` = 'C'", &rec);
3766     ok( r == ERROR_NO_MORE_ITEMS, "temporary table exists in _Columns\n");
3767     if (rec) MsiCloseHandle( rec );
3768
3769     MsiCloseHandle( hdb );
3770
3771     DeleteFile(msifile);
3772 }
3773
3774 static void test_alter(void)
3775 {
3776     MSICONDITION cond;
3777     MSIHANDLE hdb = 0;
3778     const char *query;
3779     UINT r;
3780
3781     hdb = create_db();
3782     ok( hdb, "failed to create db\n");
3783
3784     query = "CREATE TABLE `T` ( `B` SHORT NOT NULL TEMPORARY, `C` CHAR(255) TEMPORARY PRIMARY KEY `C`) HOLD";
3785     r = run_query(hdb, 0, query);
3786     ok(r == ERROR_SUCCESS, "failed to add table\n");
3787
3788     cond = MsiDatabaseIsTablePersistent(hdb, "T");
3789     ok( cond == MSICONDITION_FALSE, "wrong return condition\n");
3790
3791     query = "ALTER TABLE `T` HOLD";
3792     r = run_query(hdb, 0, query);
3793     ok(r == ERROR_SUCCESS, "failed to hold table %d\n", r);
3794
3795     query = "ALTER TABLE `T` FREE";
3796     r = run_query(hdb, 0, query);
3797     ok(r == ERROR_SUCCESS, "failed to free table\n");
3798
3799     query = "ALTER TABLE `T` FREE";
3800     r = run_query(hdb, 0, query);
3801     ok(r == ERROR_SUCCESS, "failed to free table\n");
3802
3803     query = "ALTER TABLE `T` FREE";
3804     r = run_query(hdb, 0, query);
3805     ok(r == ERROR_BAD_QUERY_SYNTAX, "failed to free table\n");
3806
3807     query = "ALTER TABLE `T` HOLD";
3808     r = run_query(hdb, 0, query);
3809     ok(r == ERROR_BAD_QUERY_SYNTAX, "failed to hold table %d\n", r);
3810
3811     /* table T is removed */
3812     query = "SELECT * FROM `T`";
3813     r = run_query(hdb, 0, query);
3814     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
3815
3816     /* create the table again */
3817     query = "CREATE TABLE `U` ( `A` INTEGER, `B` INTEGER PRIMARY KEY `B`)";
3818     r = run_query(hdb, 0, query);
3819     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3820
3821     /* up the ref count */
3822     query = "ALTER TABLE `U` HOLD";
3823     r = run_query(hdb, 0, query);
3824     ok(r == ERROR_SUCCESS, "failed to free table\n");
3825
3826     /* add column, no data type */
3827     query = "ALTER TABLE `U` ADD `C`";
3828     r = run_query(hdb, 0, query);
3829     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
3830
3831     query = "ALTER TABLE `U` ADD `C` INTEGER";
3832     r = run_query(hdb, 0, query);
3833     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3834
3835     /* add column C again */
3836     query = "ALTER TABLE `U` ADD `C` INTEGER";
3837     r = run_query(hdb, 0, query);
3838     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
3839
3840     query = "ALTER TABLE `U` ADD `D` INTEGER TEMPORARY";
3841     r = run_query(hdb, 0, query);
3842     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3843
3844     query = "INSERT INTO `U` ( `A`, `B`, `C`, `D` ) VALUES ( 1, 2, 3, 4 )";
3845     r = run_query(hdb, 0, query);
3846     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3847
3848     query = "ALTER TABLE `U` ADD `D` INTEGER TEMPORARY HOLD";
3849     r = run_query(hdb, 0, query);
3850     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
3851
3852     query = "INSERT INTO `U` ( `A`, `B`, `C`, `D` ) VALUES ( 5, 6, 7, 8 )";
3853     r = run_query(hdb, 0, query);
3854     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3855
3856     query = "SELECT * FROM `U` WHERE `D` = 8";
3857     r = run_query(hdb, 0, query);
3858     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3859
3860     query = "ALTER TABLE `U` ADD `D` INTEGER TEMPORARY FREE";
3861     r = run_query(hdb, 0, query);
3862     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
3863
3864     query = "ALTER COLUMN `D` FREE";
3865     r = run_query(hdb, 0, query);
3866     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
3867
3868     /* drop the ref count */
3869     query = "ALTER TABLE `U` FREE";
3870     r = run_query(hdb, 0, query);
3871     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3872
3873     /* table is not empty */
3874     query = "SELECT * FROM `U`";
3875     r = run_query(hdb, 0, query);
3876     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3877
3878     /* column D is removed */
3879     query = "SELECT * FROM `U` WHERE `D` = 8";
3880     r = run_query(hdb, 0, query);
3881     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
3882
3883     query = "INSERT INTO `U` ( `A`, `B`, `C`, `D` ) VALUES ( 9, 10, 11, 12 )";
3884     r = run_query(hdb, 0, query);
3885     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
3886
3887     /* add the column again */
3888     query = "ALTER TABLE `U` ADD `E` INTEGER TEMPORARY HOLD";
3889     r = run_query(hdb, 0, query);
3890     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3891
3892     /* up the ref count */
3893     query = "ALTER TABLE `U` HOLD";
3894     r = run_query(hdb, 0, query);
3895     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3896
3897     query = "INSERT INTO `U` ( `A`, `B`, `C`, `E` ) VALUES ( 13, 14, 15, 16 )";
3898     r = run_query(hdb, 0, query);
3899     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3900
3901     query = "SELECT * FROM `U` WHERE `E` = 16";
3902     r = run_query(hdb, 0, query);
3903     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3904
3905     /* drop the ref count */
3906     query = "ALTER TABLE `U` FREE";
3907     r = run_query(hdb, 0, query);
3908     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3909
3910     query = "INSERT INTO `U` ( `A`, `B`, `C`, `E` ) VALUES ( 17, 18, 19, 20 )";
3911     r = run_query(hdb, 0, query);
3912     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3913
3914     query = "SELECT * FROM `U` WHERE `E` = 20";
3915     r = run_query(hdb, 0, query);
3916     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3917
3918     /* drop the ref count */
3919     query = "ALTER TABLE `U` FREE";
3920     r = run_query(hdb, 0, query);
3921     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3922
3923     /* table still exists */
3924     query = "SELECT * FROM `U`";
3925     r = run_query(hdb, 0, query);
3926     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3927
3928     /* col E is removed */
3929     query = "SELECT * FROM `U` WHERE `E` = 20";
3930     r = run_query(hdb, 0, query);
3931     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
3932
3933     query = "INSERT INTO `U` ( `A`, `B`, `C`, `E` ) VALUES ( 20, 21, 22, 23 )";
3934     r = run_query(hdb, 0, query);
3935     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
3936
3937     /* drop the ref count once more */
3938     query = "ALTER TABLE `U` FREE";
3939     r = run_query(hdb, 0, query);
3940     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3941
3942     /* table still exists */
3943     query = "SELECT * FROM `U`";
3944     r = run_query(hdb, 0, query);
3945     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3946
3947     MsiCloseHandle( hdb );
3948     DeleteFile(msifile);
3949 }
3950
3951 static void test_integers(void)
3952 {
3953     MSIHANDLE hdb = 0, view = 0, rec = 0;
3954     DWORD count, i;
3955     const char *query;
3956     UINT r;
3957
3958     /* just MsiOpenDatabase should not create a file */
3959     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
3960     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
3961
3962     /* create a table */
3963     query = "CREATE TABLE `integers` ( "
3964             "`one` SHORT, `two` INT, `three` INTEGER, `four` LONG, "
3965             "`five` SHORT NOT NULL, `six` INT NOT NULL, "
3966             "`seven` INTEGER NOT NULL, `eight` LONG NOT NULL "
3967             "PRIMARY KEY `one`)";
3968     r = MsiDatabaseOpenView(hdb, query, &view);
3969     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
3970     r = MsiViewExecute(view, 0);
3971     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
3972     r = MsiViewClose(view);
3973     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
3974     r = MsiCloseHandle(view);
3975     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
3976
3977     query = "SELECT * FROM `integers`";
3978     r = MsiDatabaseOpenView(hdb, query, &view);
3979     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3980
3981     r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec);
3982     count = MsiRecordGetFieldCount(rec);
3983     ok(count == 8, "Expected 8, got %d\n", count);
3984     ok(check_record(rec, 1, "one"), "Expected one\n");
3985     ok(check_record(rec, 2, "two"), "Expected two\n");
3986     ok(check_record(rec, 3, "three"), "Expected three\n");
3987     ok(check_record(rec, 4, "four"), "Expected four\n");
3988     ok(check_record(rec, 5, "five"), "Expected five\n");
3989     ok(check_record(rec, 6, "six"), "Expected six\n");
3990     ok(check_record(rec, 7, "seven"), "Expected seven\n");
3991     ok(check_record(rec, 8, "eight"), "Expected eight\n");
3992     MsiCloseHandle(rec);
3993
3994     r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
3995     count = MsiRecordGetFieldCount(rec);
3996     ok(count == 8, "Expected 8, got %d\n", count);
3997     ok(check_record(rec, 1, "I2"), "Expected I2\n");
3998     ok(check_record(rec, 2, "I2"), "Expected I2\n");
3999     ok(check_record(rec, 3, "I2"), "Expected I2\n");
4000     ok(check_record(rec, 4, "I4"), "Expected I4\n");
4001     ok(check_record(rec, 5, "i2"), "Expected i2\n");
4002     ok(check_record(rec, 6, "i2"), "Expected i2\n");
4003     ok(check_record(rec, 7, "i2"), "Expected i2\n");
4004     ok(check_record(rec, 8, "i4"), "Expected i4\n");
4005     MsiCloseHandle(rec);
4006
4007     MsiViewClose(view);
4008     MsiCloseHandle(view);
4009
4010     /* insert values into it, NULL where NOT NULL is specified */
4011     query = "INSERT INTO `integers` ( `one`, `two`, `three`, `four`, `five`, `six`, `seven`, `eight` )"
4012         "VALUES('', '', '', '', '', '', '', '')";
4013     r = MsiDatabaseOpenView(hdb, query, &view);
4014     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4015     r = MsiViewExecute(view, 0);
4016     ok(r == ERROR_FUNCTION_FAILED, "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
4017
4018     MsiViewClose(view);
4019     MsiCloseHandle(view);
4020
4021     query = "SELECT * FROM `integers`";
4022     r = do_query(hdb, query, &rec);
4023     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
4024
4025     r = MsiRecordGetFieldCount(rec);
4026     ok(r == -1, "record count wrong: %d\n", r);
4027
4028     MsiCloseHandle(rec);
4029
4030     /* insert legitimate values into it */
4031     query = "INSERT INTO `integers` ( `one`, `two`, `three`, `four`, `five`, `six`, `seven`, `eight` )"
4032         "VALUES('', '2', '', '4', '5', '6', '7', '8')";
4033     r = MsiDatabaseOpenView(hdb, query, &view);
4034     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4035     r = MsiViewExecute(view, 0);
4036     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4037
4038     query = "SELECT * FROM `integers`";
4039     r = do_query(hdb, query, &rec);
4040     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4041
4042     r = MsiRecordGetFieldCount(rec);
4043     ok(r == 8, "record count wrong: %d\n", r);
4044
4045     i = MsiRecordGetInteger(rec, 1);
4046     ok(i == MSI_NULL_INTEGER, "Expected MSI_NULL_INTEGER, got %d\n", i);
4047     i = MsiRecordGetInteger(rec, 3);
4048     ok(i == MSI_NULL_INTEGER, "Expected MSI_NULL_INTEGER, got %d\n", i);
4049     i = MsiRecordGetInteger(rec, 2);
4050     ok(i == 2, "Expected 2, got %d\n", i);
4051     i = MsiRecordGetInteger(rec, 4);
4052     ok(i == 4, "Expected 4, got %d\n", i);
4053     i = MsiRecordGetInteger(rec, 5);
4054     ok(i == 5, "Expected 5, got %d\n", i);
4055     i = MsiRecordGetInteger(rec, 6);
4056     ok(i == 6, "Expected 6, got %d\n", i);
4057     i = MsiRecordGetInteger(rec, 7);
4058     ok(i == 7, "Expected 7, got %d\n", i);
4059     i = MsiRecordGetInteger(rec, 8);
4060     ok(i == 8, "Expected 8, got %d\n", i);
4061
4062     MsiCloseHandle(rec);
4063     MsiViewClose(view);
4064     MsiCloseHandle(view);
4065
4066     r = MsiDatabaseCommit(hdb);
4067     ok(r == ERROR_SUCCESS, "MsiDatabaseCommit failed\n");
4068
4069     r = MsiCloseHandle(hdb);
4070     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4071
4072     r = DeleteFile(msifile);
4073     ok(r == TRUE, "file didn't exist after commit\n");
4074 }
4075
4076 static void test_update(void)
4077 {
4078     MSIHANDLE hdb = 0, view = 0, rec = 0;
4079     CHAR result[MAX_PATH];
4080     const char *query;
4081     DWORD size;
4082     UINT r;
4083
4084     /* just MsiOpenDatabase should not create a file */
4085     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
4086     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
4087
4088     /* create the Control table */
4089     query = "CREATE TABLE `Control` ( "
4090         "`Dialog_` CHAR(72) NOT NULL, `Control` CHAR(50) NOT NULL, `Type` SHORT NOT NULL, "
4091         "`X` SHORT NOT NULL, `Y` SHORT NOT NULL, `Width` SHORT NOT NULL, `Height` SHORT NOT NULL,"
4092         "`Attributes` LONG, `Property` CHAR(50), `Text` CHAR(0) LOCALIZABLE, "
4093         "`Control_Next` CHAR(50), `Help` CHAR(50) LOCALIZABLE PRIMARY KEY `Dialog_`, `Control`)";
4094     r = MsiDatabaseOpenView(hdb, query, &view);
4095     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
4096     r = MsiViewExecute(view, 0);
4097     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
4098     r = MsiViewClose(view);
4099     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4100     r = MsiCloseHandle(view);
4101     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4102
4103     /* add a control */
4104     query = "INSERT INTO `Control` ( "
4105         "`Dialog_`, `Control`, `Type`, `X`, `Y`, `Width`, `Height`, "
4106         "`Property`, `Text`, `Control_Next`, `Help` )"
4107         "VALUES('ErrorDialog', 'ErrorText', '1', '5', '5', '5', '5', '', '', '', '')";
4108     r = MsiDatabaseOpenView(hdb, query, &view);
4109     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4110     r = MsiViewExecute(view, 0);
4111     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4112     r = MsiViewClose(view);
4113     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4114     r = MsiCloseHandle(view);
4115     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4116
4117     /* add a second control */
4118     query = "INSERT INTO `Control` ( "
4119         "`Dialog_`, `Control`, `Type`, `X`, `Y`, `Width`, `Height`, "
4120         "`Property`, `Text`, `Control_Next`, `Help` )"
4121         "VALUES('ErrorDialog', 'Button', '1', '5', '5', '5', '5', '', '', '', '')";
4122     r = MsiDatabaseOpenView(hdb, query, &view);
4123     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4124     r = MsiViewExecute(view, 0);
4125     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4126     r = MsiViewClose(view);
4127     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4128     r = MsiCloseHandle(view);
4129     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4130
4131     /* add a third control */
4132     query = "INSERT INTO `Control` ( "
4133         "`Dialog_`, `Control`, `Type`, `X`, `Y`, `Width`, `Height`, "
4134         "`Property`, `Text`, `Control_Next`, `Help` )"
4135         "VALUES('AnotherDialog', 'ErrorText', '1', '5', '5', '5', '5', '', '', '', '')";
4136     r = MsiDatabaseOpenView(hdb, query, &view);
4137     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4138     r = MsiViewExecute(view, 0);
4139     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4140     r = MsiViewClose(view);
4141     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4142     r = MsiCloseHandle(view);
4143     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4144
4145     /* bad table */
4146     query = "UPDATE `NotATable` SET `Text` = 'this is text' WHERE `Dialog_` = 'ErrorDialog'";
4147     r = MsiDatabaseOpenView(hdb, query, &view);
4148     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
4149
4150     /* bad set column */
4151     query = "UPDATE `Control` SET `NotAColumn` = 'this is text' WHERE `Dialog_` = 'ErrorDialog'";
4152     r = MsiDatabaseOpenView(hdb, query, &view);
4153     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
4154
4155     /* bad where condition */
4156     query = "UPDATE `Control` SET `Text` = 'this is text' WHERE `NotAColumn` = 'ErrorDialog'";
4157     r = MsiDatabaseOpenView(hdb, query, &view);
4158     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
4159
4160     /* just the dialog_ specified */
4161     query = "UPDATE `Control` SET `Text` = 'this is text' WHERE `Dialog_` = 'ErrorDialog'";
4162     r = MsiDatabaseOpenView(hdb, query, &view);
4163     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4164     r = MsiViewExecute(view, 0);
4165     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4166     r = MsiViewClose(view);
4167     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4168     r = MsiCloseHandle(view);
4169     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4170
4171     /* check the modified text */
4172     query = "SELECT `Text` FROM `Control` WHERE `Control` = 'ErrorText'";
4173     r = MsiDatabaseOpenView(hdb, query, &view);
4174     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4175     r = MsiViewExecute(view, 0);
4176     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4177
4178     r = MsiViewFetch(view, &rec);
4179     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4180
4181     size = MAX_PATH;
4182     r = MsiRecordGetString(rec, 1, result, &size);
4183     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4184     ok(!lstrcmp(result, "this is text"), "Expected `this is text`, got %s\n", result);
4185
4186     MsiCloseHandle(rec);
4187
4188     r = MsiViewFetch(view, &rec);
4189     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4190
4191     size = MAX_PATH;
4192     r = MsiRecordGetString(rec, 1, result, &size);
4193     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4194     ok(!lstrlen(result), "Expected an empty string, got %s\n", result);
4195
4196     MsiCloseHandle(rec);
4197
4198     r = MsiViewFetch(view, &rec);
4199     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
4200
4201     r = MsiViewClose(view);
4202     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4203     r = MsiCloseHandle(view);
4204     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4205
4206     /* dialog_ and control specified */
4207     query = "UPDATE `Control` SET `Text` = 'this is text' WHERE `Dialog_` = 'ErrorDialog' AND `Control` = 'ErrorText'";
4208     r = MsiDatabaseOpenView(hdb, query, &view);
4209     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4210     r = MsiViewExecute(view, 0);
4211     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4212     r = MsiViewClose(view);
4213     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4214     r = MsiCloseHandle(view);
4215     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4216
4217     /* check the modified text */
4218     query = "SELECT `Text` FROM `Control` WHERE `Control` = 'ErrorText'";
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
4224     r = MsiViewFetch(view, &rec);
4225     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4226
4227     size = MAX_PATH;
4228     r = MsiRecordGetString(rec, 1, result, &size);
4229     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4230     ok(!lstrcmp(result, "this is text"), "Expected `this is text`, got %s\n", result);
4231
4232     MsiCloseHandle(rec);
4233
4234     r = MsiViewFetch(view, &rec);
4235     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4236
4237     size = MAX_PATH;
4238     r = MsiRecordGetString(rec, 1, result, &size);
4239     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4240     ok(!lstrlen(result), "Expected an empty string, got %s\n", result);
4241
4242     MsiCloseHandle(rec);
4243
4244     r = MsiViewFetch(view, &rec);
4245     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
4246
4247     r = MsiViewClose(view);
4248     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4249     r = MsiCloseHandle(view);
4250     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4251
4252     /* no where condition */
4253     query = "UPDATE `Control` SET `Text` = 'this is text'";
4254     r = MsiDatabaseOpenView(hdb, query, &view);
4255     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4256     r = MsiViewExecute(view, 0);
4257     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
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     /* check the modified text */
4264     query = "SELECT `Text` FROM `Control`";
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
4270     r = MsiViewFetch(view, &rec);
4271     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4272
4273     size = MAX_PATH;
4274     r = MsiRecordGetString(rec, 1, result, &size);
4275     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4276     ok(!lstrcmp(result, "this is text"), "Expected `this is text`, got %s\n", result);
4277
4278     MsiCloseHandle(rec);
4279
4280     r = MsiViewFetch(view, &rec);
4281     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4282
4283     size = MAX_PATH;
4284     r = MsiRecordGetString(rec, 1, result, &size);
4285     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4286     ok(!lstrcmp(result, "this is text"), "Expected `this is text`, got %s\n", result);
4287
4288     MsiCloseHandle(rec);
4289
4290     r = MsiViewFetch(view, &rec);
4291     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4292
4293     size = MAX_PATH;
4294     r = MsiRecordGetString(rec, 1, result, &size);
4295     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4296     ok(!lstrcmp(result, "this is text"), "Expected `this is text`, got %s\n", result);
4297
4298     MsiCloseHandle(rec);
4299
4300     r = MsiViewFetch(view, &rec);
4301     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
4302
4303     r = MsiViewClose(view);
4304     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4305     r = MsiCloseHandle(view);
4306     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4307
4308     query = "CREATE TABLE `Apple` ( `Banana` CHAR(72) NOT NULL, "
4309         "`Orange` CHAR(72),  `Pear` INT PRIMARY KEY `Banana`)";
4310     r = run_query(hdb, 0, query);
4311     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4312
4313     query = "INSERT INTO `Apple` ( `Banana`, `Orange`, `Pear` )"
4314         "VALUES('one', 'two', 3)";
4315     r = run_query(hdb, 0, query);
4316     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4317
4318     query = "INSERT INTO `Apple` ( `Banana`, `Orange`, `Pear` )"
4319         "VALUES('three', 'four', 5)";
4320     r = run_query(hdb, 0, query);
4321     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4322
4323     query = "INSERT INTO `Apple` ( `Banana`, `Orange`, `Pear` )"
4324         "VALUES('six', 'two', 7)";
4325     r = run_query(hdb, 0, query);
4326     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4327
4328     rec = MsiCreateRecord(2);
4329     MsiRecordSetInteger(rec, 1, 8);
4330     MsiRecordSetString(rec, 2, "two");
4331
4332     query = "UPDATE `Apple` SET `Pear` = ? WHERE `Orange` = ?";
4333     r = run_query(hdb, rec, query);
4334     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4335
4336     MsiCloseHandle(rec);
4337
4338     query = "SELECT `Pear` FROM `Apple` ORDER BY `Orange`";
4339     r = MsiDatabaseOpenView(hdb, query, &view);
4340     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4341     r = MsiViewExecute(view, 0);
4342     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4343
4344     r = MsiViewFetch(view, &rec);
4345     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4346
4347     r = MsiRecordGetInteger(rec, 1);
4348     ok(r == 8, "Expected 8, got %d\n", r);
4349
4350     MsiCloseHandle(rec);
4351
4352     r = MsiViewFetch(view, &rec);
4353     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4354
4355     r = MsiRecordGetInteger(rec, 1);
4356     ok(r == 8, "Expected 8, got %d\n", r);
4357
4358     MsiCloseHandle(rec);
4359
4360     r = MsiViewFetch(view, &rec);
4361     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4362
4363     r = MsiRecordGetInteger(rec, 1);
4364     ok(r == 5, "Expected 5, got %d\n", r);
4365
4366     MsiCloseHandle(rec);
4367
4368     r = MsiViewFetch(view, &rec);
4369     ok(r == ERROR_NO_MORE_ITEMS, "Expectd ERROR_NO_MORE_ITEMS, got %d\n", r);
4370
4371     MsiViewClose(view);
4372     MsiCloseHandle(view);
4373
4374     r = MsiDatabaseCommit(hdb);
4375     ok(r == ERROR_SUCCESS, "MsiDatabaseCommit failed\n");
4376     r = MsiCloseHandle(hdb);
4377     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4378
4379     DeleteFile(msifile);
4380 }
4381
4382 static void test_special_tables(void)
4383 {
4384     const char *query;
4385     MSIHANDLE hdb = 0;
4386     UINT r;
4387
4388     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
4389     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
4390
4391     query = "CREATE TABLE `_Properties` ( "
4392         "`foo` INT NOT NULL, `bar` INT LOCALIZABLE PRIMARY KEY `foo`)";
4393     r = run_query(hdb, 0, query);
4394     ok(r == ERROR_SUCCESS, "failed to create table\n");
4395
4396     query = "CREATE TABLE `_Storages` ( "
4397         "`foo` INT NOT NULL, `bar` INT LOCALIZABLE PRIMARY KEY `foo`)";
4398     r = run_query(hdb, 0, query);
4399     ok(r == ERROR_BAD_QUERY_SYNTAX, "created _Streams table\n");
4400
4401     query = "CREATE TABLE `_Streams` ( "
4402         "`foo` INT NOT NULL, `bar` INT LOCALIZABLE PRIMARY KEY `foo`)";
4403     r = run_query(hdb, 0, query);
4404     ok(r == ERROR_BAD_QUERY_SYNTAX, "created _Streams table\n");
4405
4406     query = "CREATE TABLE `_Tables` ( "
4407         "`foo` INT NOT NULL, `bar` INT LOCALIZABLE PRIMARY KEY `foo`)";
4408     r = run_query(hdb, 0, query);
4409     ok(r == ERROR_BAD_QUERY_SYNTAX, "created _Tables table\n");
4410
4411     query = "CREATE TABLE `_Columns` ( "
4412         "`foo` INT NOT NULL, `bar` INT LOCALIZABLE PRIMARY KEY `foo`)";
4413     r = run_query(hdb, 0, query);
4414     ok(r == ERROR_BAD_QUERY_SYNTAX, "created _Columns table\n");
4415
4416     r = MsiCloseHandle(hdb);
4417     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4418 }
4419
4420 static void test_tables_order(void)
4421 {
4422     const char *query;
4423     MSIHANDLE hdb = 0, hview = 0, hrec = 0;
4424     UINT r;
4425     char buffer[100];
4426     DWORD sz;
4427
4428     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
4429     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
4430
4431     query = "CREATE TABLE `foo` ( "
4432         "`baz` INT NOT NULL PRIMARY KEY `baz`)";
4433     r = run_query(hdb, 0, query);
4434     ok(r == ERROR_SUCCESS, "failed to create table\n");
4435
4436     query = "CREATE TABLE `bar` ( "
4437         "`foo` INT NOT NULL PRIMARY KEY `foo`)";
4438     r = run_query(hdb, 0, query);
4439     ok(r == ERROR_SUCCESS, "failed to create table\n");
4440
4441     query = "CREATE TABLE `baz` ( "
4442         "`bar` INT NOT NULL, "
4443         "`baz` INT NOT NULL, "
4444         "`foo` INT NOT NULL PRIMARY KEY `bar`)";
4445     r = run_query(hdb, 0, query);
4446     ok(r == ERROR_SUCCESS, "failed to create table\n");
4447
4448     /* The names of the tables in the _Tables table must
4449        be in the same order as these names are created in
4450        the strings table. */
4451     query = "SELECT * FROM `_Tables`";
4452     r = MsiDatabaseOpenView(hdb, query, &hview);
4453     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
4454     r = MsiViewExecute(hview, 0);
4455     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
4456
4457     r = MsiViewFetch(hview, &hrec);
4458     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4459     sz = sizeof(buffer);
4460     r = MsiRecordGetString(hrec, 1, buffer, &sz);
4461     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4462     ok(!lstrcmp(buffer, "foo"), "Expected foo, got %s\n", buffer);
4463     r = MsiCloseHandle(hrec);
4464     ok(r == ERROR_SUCCESS, "failed to close record\n");
4465
4466     r = MsiViewFetch(hview, &hrec);
4467     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4468     sz = sizeof(buffer);
4469     r = MsiRecordGetString(hrec, 1, buffer, &sz);
4470     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4471     ok(!lstrcmp(buffer, "baz"), "Expected baz, got %s\n", buffer);
4472     r = MsiCloseHandle(hrec);
4473     ok(r == ERROR_SUCCESS, "failed to close record\n");
4474
4475     r = MsiViewFetch(hview, &hrec);
4476     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4477     sz = sizeof(buffer);
4478     r = MsiRecordGetString(hrec, 1, buffer, &sz);
4479     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4480     ok(!lstrcmp(buffer, "bar"), "Expected bar, got %s\n", buffer);
4481     r = MsiCloseHandle(hrec);
4482     ok(r == ERROR_SUCCESS, "failed to close record\n");
4483
4484     r = MsiViewClose(hview);
4485     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4486     r = MsiCloseHandle(hview);
4487     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4488
4489     /* The names of the tables in the _Columns table must
4490        be in the same order as these names are created in
4491        the strings table. */
4492     query = "SELECT * FROM `_Columns`";
4493     r = MsiDatabaseOpenView(hdb, query, &hview);
4494     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
4495     r = MsiViewExecute(hview, 0);
4496     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
4497
4498     r = MsiViewFetch(hview, &hrec);
4499     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4500     sz = sizeof(buffer);
4501     r = MsiRecordGetString(hrec, 1, buffer, &sz);
4502     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4503     ok(!lstrcmp(buffer, "foo"), "Expected foo, got %s\n", buffer);
4504     sz = sizeof(buffer);
4505     r = MsiRecordGetString(hrec, 3, buffer, &sz);
4506     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4507     ok(!lstrcmp(buffer, "baz"), "Expected baz, got %s\n", buffer);
4508     r = MsiCloseHandle(hrec);
4509     ok(r == ERROR_SUCCESS, "failed to close record\n");
4510
4511     r = MsiViewFetch(hview, &hrec);
4512     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4513     sz = sizeof(buffer);
4514     r = MsiRecordGetString(hrec, 1, buffer, &sz);
4515     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4516     ok(!lstrcmp(buffer, "baz"), "Expected baz, got %s\n", buffer);
4517     sz = sizeof(buffer);
4518     r = MsiRecordGetString(hrec, 3, buffer, &sz);
4519     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4520     ok(!lstrcmp(buffer, "bar"), "Expected bar, got %s\n", buffer);
4521     r = MsiCloseHandle(hrec);
4522     ok(r == ERROR_SUCCESS, "failed to close record\n");
4523
4524     r = MsiViewFetch(hview, &hrec);
4525     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4526     sz = sizeof(buffer);
4527     r = MsiRecordGetString(hrec, 1, buffer, &sz);
4528     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4529     ok(!lstrcmp(buffer, "baz"), "Expected baz, got %s\n", buffer);
4530     sz = sizeof(buffer);
4531     r = MsiRecordGetString(hrec, 3, buffer, &sz);
4532     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4533     ok(!lstrcmp(buffer, "baz"), "Expected baz, got %s\n", buffer);
4534     r = MsiCloseHandle(hrec);
4535     ok(r == ERROR_SUCCESS, "failed to close record\n");
4536
4537     r = MsiViewFetch(hview, &hrec);
4538     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4539     sz = sizeof(buffer);
4540     r = MsiRecordGetString(hrec, 1, buffer, &sz);
4541     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4542     ok(!lstrcmp(buffer, "baz"), "Expected baz, got %s\n", buffer);
4543     sz = sizeof(buffer);
4544     r = MsiRecordGetString(hrec, 3, buffer, &sz);
4545     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4546     ok(!lstrcmp(buffer, "foo"), "Expected foo, got %s\n", buffer);
4547     r = MsiCloseHandle(hrec);
4548     ok(r == ERROR_SUCCESS, "failed to close record\n");
4549
4550     r = MsiViewFetch(hview, &hrec);
4551     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4552     sz = sizeof(buffer);
4553     r = MsiRecordGetString(hrec, 1, buffer, &sz);
4554     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4555     ok(!lstrcmp(buffer, "bar"), "Expected bar, got %s\n", buffer);
4556     sz = sizeof(buffer);
4557     r = MsiRecordGetString(hrec, 3, buffer, &sz);
4558     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4559     ok(!lstrcmp(buffer, "foo"), "Expected foo, got %s\n", buffer);
4560     r = MsiCloseHandle(hrec);
4561     ok(r == ERROR_SUCCESS, "failed to close record\n");
4562
4563     r = MsiViewClose(hview);
4564     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4565     r = MsiCloseHandle(hview);
4566     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4567
4568     r = MsiCloseHandle(hdb);
4569     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4570
4571     DeleteFile(msifile);
4572 }
4573
4574 static void test_rows_order(void)
4575 {
4576     const char *query;
4577     MSIHANDLE hdb = 0, hview = 0, hrec = 0;
4578     UINT r;
4579     char buffer[100];
4580     DWORD sz;
4581
4582     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
4583     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
4584
4585     query = "CREATE TABLE `foo` ( "
4586         "`bar` LONGCHAR NOT NULL PRIMARY KEY `bar`)";
4587     r = run_query(hdb, 0, query);
4588     ok(r == ERROR_SUCCESS, "failed to create table\n");
4589
4590     r = run_query(hdb, 0, "INSERT INTO `foo` "
4591             "( `bar` ) VALUES ( 'A' )");
4592     ok(r == ERROR_SUCCESS, "cannot add value to table\n");
4593
4594     r = run_query(hdb, 0, "INSERT INTO `foo` "
4595             "( `bar` ) VALUES ( 'B' )");
4596     ok(r == ERROR_SUCCESS, "cannot add value to table\n");
4597
4598     r = run_query(hdb, 0, "INSERT INTO `foo` "
4599             "( `bar` ) VALUES ( 'C' )");
4600     ok(r == ERROR_SUCCESS, "cannot add value to table\n");
4601
4602     r = run_query(hdb, 0, "INSERT INTO `foo` "
4603             "( `bar` ) VALUES ( 'D' )");
4604     ok(r == ERROR_SUCCESS, "cannot add value to table\n");
4605
4606     r = run_query(hdb, 0, "INSERT INTO `foo` "
4607             "( `bar` ) VALUES ( 'E' )");
4608     ok(r == ERROR_SUCCESS, "cannot add value to table\n");
4609
4610     r = run_query(hdb, 0, "INSERT INTO `foo` "
4611             "( `bar` ) VALUES ( 'F' )");
4612     ok(r == ERROR_SUCCESS, "cannot add value to table\n");
4613
4614     query = "CREATE TABLE `bar` ( "
4615         "`foo` LONGCHAR NOT NULL, "
4616         "`baz` LONGCHAR NOT NULL "
4617         "PRIMARY KEY `foo` )";
4618     r = run_query(hdb, 0, query);
4619     ok(r == ERROR_SUCCESS, "failed to create table\n");
4620
4621     r = run_query(hdb, 0, "INSERT INTO `bar` "
4622             "( `foo`, `baz` ) VALUES ( 'C', 'E' )");
4623     ok(r == ERROR_SUCCESS, "cannot add value to table\n");
4624
4625     r = run_query(hdb, 0, "INSERT INTO `bar` "
4626             "( `foo`, `baz` ) VALUES ( 'F', 'A' )");
4627     ok(r == ERROR_SUCCESS, "cannot add value to table\n");
4628
4629     r = run_query(hdb, 0, "INSERT INTO `bar` "
4630             "( `foo`, `baz` ) VALUES ( 'A', 'B' )");
4631     ok(r == ERROR_SUCCESS, "cannot add value to table\n");
4632
4633     r = run_query(hdb, 0, "INSERT INTO `bar` "
4634             "( `foo`, `baz` ) VALUES ( 'D', 'E' )");
4635     ok(r == ERROR_SUCCESS, "cannot add value to table\n");
4636
4637     /* The rows of the table must be ordered by the column values of
4638        each row. For strings, the column value is the string id
4639        in the string table.  */
4640
4641     query = "SELECT * FROM `bar`";
4642     r = MsiDatabaseOpenView(hdb, query, &hview);
4643     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
4644     r = MsiViewExecute(hview, 0);
4645     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
4646
4647     r = MsiViewFetch(hview, &hrec);
4648     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4649     sz = sizeof(buffer);
4650     r = MsiRecordGetString(hrec, 1, buffer, &sz);
4651     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4652     ok(!lstrcmp(buffer, "A"), "Expected A, got %s\n", buffer);
4653     sz = sizeof(buffer);
4654     r = MsiRecordGetString(hrec, 2, buffer, &sz);
4655     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4656     ok(!lstrcmp(buffer, "B"), "Expected B, got %s\n", buffer);
4657     r = MsiCloseHandle(hrec);
4658     ok(r == ERROR_SUCCESS, "failed to close record\n");
4659
4660     r = MsiViewFetch(hview, &hrec);
4661     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4662     sz = sizeof(buffer);
4663     r = MsiRecordGetString(hrec, 1, buffer, &sz);
4664     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4665     ok(!lstrcmp(buffer, "C"), "Expected E, got %s\n", buffer);
4666     sz = sizeof(buffer);
4667     r = MsiRecordGetString(hrec, 2, buffer, &sz);
4668     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4669     ok(!lstrcmp(buffer, "E"), "Expected E, got %s\n", buffer);
4670     r = MsiCloseHandle(hrec);
4671     ok(r == ERROR_SUCCESS, "failed to close record\n");
4672
4673     r = MsiViewFetch(hview, &hrec);
4674     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4675     sz = sizeof(buffer);
4676     r = MsiRecordGetString(hrec, 1, buffer, &sz);
4677     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4678     ok(!lstrcmp(buffer, "D"), "Expected D, got %s\n", buffer);
4679     sz = sizeof(buffer);
4680     r = MsiRecordGetString(hrec, 2, buffer, &sz);
4681     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4682     ok(!lstrcmp(buffer, "E"), "Expected E, got %s\n", buffer);
4683     r = MsiCloseHandle(hrec);
4684     ok(r == ERROR_SUCCESS, "failed to close record\n");
4685
4686     r = MsiViewFetch(hview, &hrec);
4687     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4688     sz = sizeof(buffer);
4689     r = MsiRecordGetString(hrec, 1, buffer, &sz);
4690     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4691     ok(!lstrcmp(buffer, "F"), "Expected F, got %s\n", buffer);
4692     sz = sizeof(buffer);
4693     r = MsiRecordGetString(hrec, 2, buffer, &sz);
4694     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4695     ok(!lstrcmp(buffer, "A"), "Expected A, got %s\n", buffer);
4696     r = MsiCloseHandle(hrec);
4697     ok(r == ERROR_SUCCESS, "failed to close record\n");
4698
4699     r = MsiViewClose(hview);
4700     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4701     r = MsiCloseHandle(hview);
4702     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4703
4704     r = MsiCloseHandle(hdb);
4705     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4706
4707     DeleteFile(msifile);
4708 }
4709
4710 static void test_select_markers(void)
4711 {
4712     MSIHANDLE hdb = 0, rec, view, res;
4713     LPCSTR query;
4714     UINT r;
4715     DWORD size;
4716     CHAR buf[MAX_PATH];
4717
4718     hdb = create_db();
4719     ok( hdb, "failed to create db\n");
4720
4721     r = run_query(hdb, 0,
4722             "CREATE TABLE `Table` (`One` CHAR(72), `Two` CHAR(72), `Three` SHORT PRIMARY KEY `One`, `Two`, `Three`)");
4723     ok(r == S_OK, "cannot create table: %d\n", r);
4724
4725     r = run_query(hdb, 0, "INSERT INTO `Table` "
4726             "( `One`, `Two`, `Three` ) VALUES ( 'apple', 'one', 1 )");
4727     ok(r == S_OK, "cannot add file to the Media table: %d\n", r);
4728
4729     r = run_query(hdb, 0, "INSERT INTO `Table` "
4730             "( `One`, `Two`, `Three` ) VALUES ( 'apple', 'two', 1 )");
4731     ok(r == S_OK, "cannot add file to the Media table: %d\n", r);
4732
4733     r = run_query(hdb, 0, "INSERT INTO `Table` "
4734             "( `One`, `Two`, `Three` ) VALUES ( 'apple', 'two', 2 )");
4735     ok(r == S_OK, "cannot add file to the Media table: %d\n", r);
4736
4737     r = run_query(hdb, 0, "INSERT INTO `Table` "
4738             "( `One`, `Two`, `Three` ) VALUES ( 'banana', 'three', 3 )");
4739     ok(r == S_OK, "cannot add file to the Media table: %d\n", r);
4740
4741     rec = MsiCreateRecord(2);
4742     MsiRecordSetString(rec, 1, "apple");
4743     MsiRecordSetString(rec, 2, "two");
4744
4745     query = "SELECT * FROM `Table` WHERE `One`=? AND `Two`=? ORDER BY `Three`";
4746     r = MsiDatabaseOpenView(hdb, query, &view);
4747     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4748
4749     r = MsiViewExecute(view, rec);
4750     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4751
4752     r = MsiViewFetch(view, &res);
4753     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4754
4755     size = MAX_PATH;
4756     r = MsiRecordGetString(res, 1, buf, &size);
4757     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4758     ok(!lstrcmp(buf, "apple"), "Expected apple, got %s\n", buf);
4759
4760     size = MAX_PATH;
4761     r = MsiRecordGetString(res, 2, buf, &size);
4762     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4763     ok(!lstrcmp(buf, "two"), "Expected two, got %s\n", buf);
4764
4765     r = MsiRecordGetInteger(res, 3);
4766     ok(r == 1, "Expected 1, got %d\n", r);
4767
4768     MsiCloseHandle(res);
4769
4770     r = MsiViewFetch(view, &res);
4771     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4772
4773     size = MAX_PATH;
4774     r = MsiRecordGetString(res, 1, buf, &size);
4775     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4776     ok(!lstrcmp(buf, "apple"), "Expected apple, got %s\n", buf);
4777
4778     size = MAX_PATH;
4779     r = MsiRecordGetString(res, 2, buf, &size);
4780     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4781     ok(!lstrcmp(buf, "two"), "Expected two, got %s\n", buf);
4782
4783     r = MsiRecordGetInteger(res, 3);
4784     ok(r == 2, "Expected 2, got %d\n", r);
4785
4786     MsiCloseHandle(res);
4787
4788     r = MsiViewFetch(view, &res);
4789     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
4790
4791     MsiCloseHandle(rec);
4792     MsiViewClose(view);
4793     MsiCloseHandle(view);
4794
4795     rec = MsiCreateRecord(2);
4796     MsiRecordSetString(rec, 1, "one");
4797     MsiRecordSetInteger(rec, 2, 1);
4798
4799     query = "SELECT * FROM `Table` WHERE `Two`<>? AND `Three`>? ORDER BY `Three`";
4800     r = MsiDatabaseOpenView(hdb, query, &view);
4801     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4802     r = MsiViewExecute(view, rec);
4803     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4804
4805     r = MsiViewFetch(view, &res);
4806     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4807
4808     size = MAX_PATH;
4809     r = MsiRecordGetString(res, 1, buf, &size);
4810     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4811     ok(!lstrcmp(buf, "apple"), "Expected apple, got %s\n", buf);
4812
4813     size = MAX_PATH;
4814     r = MsiRecordGetString(res, 2, buf, &size);
4815     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4816     ok(!lstrcmp(buf, "two"), "Expected two, got %s\n", buf);
4817
4818     r = MsiRecordGetInteger(res, 3);
4819     ok(r == 2, "Expected 2, got %d\n", r);
4820
4821     MsiCloseHandle(res);
4822
4823     r = MsiViewFetch(view, &res);
4824     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4825
4826     size = MAX_PATH;
4827     r = MsiRecordGetString(res, 1, buf, &size);
4828     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4829     ok(!lstrcmp(buf, "banana"), "Expected banana, got %s\n", buf);
4830
4831     size = MAX_PATH;
4832     r = MsiRecordGetString(res, 2, buf, &size);
4833     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4834     ok(!lstrcmp(buf, "three"), "Expected three, got %s\n", buf);
4835
4836     r = MsiRecordGetInteger(res, 3);
4837     ok(r == 3, "Expected 3, got %d\n", r);
4838
4839     MsiCloseHandle(res);
4840
4841     r = MsiViewFetch(view, &res);
4842     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
4843
4844     MsiCloseHandle(rec);
4845     MsiViewClose(view);
4846     MsiCloseHandle(view);
4847     MsiCloseHandle(hdb);
4848     DeleteFile(msifile);
4849 }
4850
4851 static void test_viewmodify_update(void)
4852 {
4853     MSIHANDLE hdb = 0, hview = 0, hrec = 0;
4854     const char *query;
4855     UINT r;
4856
4857     DeleteFile(msifile);
4858
4859     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
4860     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
4861
4862     query = "CREATE TABLE `table` (`A` INT, `B` INT PRIMARY KEY `A`)";
4863     r = run_query( hdb, 0, query );
4864     ok(r == ERROR_SUCCESS, "query failed\n");
4865
4866     query = "INSERT INTO `table` (`A`, `B`) VALUES (1, 2)";
4867     r = run_query( hdb, 0, query );
4868     ok(r == ERROR_SUCCESS, "query failed\n");
4869
4870     query = "INSERT INTO `table` (`A`, `B`) VALUES (3, 4)";
4871     r = run_query( hdb, 0, query );
4872     ok(r == ERROR_SUCCESS, "query failed\n");
4873
4874     query = "INSERT INTO `table` (`A`, `B`) VALUES (5, 6)";
4875     r = run_query( hdb, 0, query );
4876     ok(r == ERROR_SUCCESS, "query failed\n");
4877
4878     query = "SELECT `B` FROM `table`";
4879     r = MsiDatabaseOpenView(hdb, query, &hview);
4880     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
4881     r = MsiViewExecute(hview, 0);
4882     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
4883     r = MsiViewFetch(hview, &hrec);
4884     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4885
4886     r = MsiRecordSetInteger(hrec, 1, 0);
4887     ok(r == ERROR_SUCCESS, "failed to set integer\n");
4888
4889     r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
4890     ok(r == ERROR_SUCCESS, "MsiViewModify failed: %d\n", r);
4891
4892     r = MsiCloseHandle(hrec);
4893     ok(r == ERROR_SUCCESS, "failed to close record\n");
4894
4895     r = MsiViewClose(hview);
4896     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4897     r = MsiCloseHandle(hview);
4898     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4899
4900     query = "SELECT * FROM `table`";
4901     r = MsiDatabaseOpenView(hdb, query, &hview);
4902     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
4903     r = MsiViewExecute(hview, 0);
4904     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
4905     r = MsiViewFetch(hview, &hrec);
4906     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4907
4908     r = MsiRecordGetInteger(hrec, 1);
4909     ok(r == 1, "Expected 1, got %d\n", r);
4910     r = MsiRecordGetInteger(hrec, 2);
4911     ok(r == 0, "Expected 0, got %d\n", r);
4912
4913     r = MsiCloseHandle(hrec);
4914     ok(r == ERROR_SUCCESS, "failed to close record\n");
4915
4916     r = MsiViewFetch(hview, &hrec);
4917     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4918
4919     r = MsiRecordGetInteger(hrec, 1);
4920     ok(r == 3, "Expected 3, got %d\n", r);
4921     r = MsiRecordGetInteger(hrec, 2);
4922     ok(r == 4, "Expected 4, got %d\n", r);
4923
4924     r = MsiCloseHandle(hrec);
4925     ok(r == ERROR_SUCCESS, "failed to close record\n");
4926
4927     r = MsiViewFetch(hview, &hrec);
4928     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4929
4930     r = MsiRecordGetInteger(hrec, 1);
4931     ok(r == 5, "Expected 5, got %d\n", r);
4932     r = MsiRecordGetInteger(hrec, 2);
4933     ok(r == 6, "Expected 6, got %d\n", r);
4934
4935     r = MsiCloseHandle(hrec);
4936     ok(r == ERROR_SUCCESS, "failed to close record\n");
4937
4938     r = MsiViewFetch(hview, &hrec);
4939     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
4940
4941     r = MsiViewClose(hview);
4942     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4943     r = MsiCloseHandle(hview);
4944     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4945
4946     /* loop through all elements */
4947     query = "SELECT `B` FROM `table`";
4948     r = MsiDatabaseOpenView(hdb, query, &hview);
4949     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
4950     r = MsiViewExecute(hview, 0);
4951     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
4952
4953     while (TRUE)
4954     {
4955         r = MsiViewFetch(hview, &hrec);
4956         if (r != ERROR_SUCCESS)
4957             break;
4958
4959         r = MsiRecordSetInteger(hrec, 1, 0);
4960         ok(r == ERROR_SUCCESS, "failed to set integer\n");
4961
4962         r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
4963         ok(r == ERROR_SUCCESS, "MsiViewModify failed: %d\n", r);
4964
4965         r = MsiCloseHandle(hrec);
4966         ok(r == ERROR_SUCCESS, "failed to close record\n");
4967     }
4968
4969     r = MsiViewClose(hview);
4970     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4971     r = MsiCloseHandle(hview);
4972     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4973
4974     query = "SELECT * FROM `table`";
4975     r = MsiDatabaseOpenView(hdb, query, &hview);
4976     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
4977     r = MsiViewExecute(hview, 0);
4978     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
4979     r = MsiViewFetch(hview, &hrec);
4980     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4981
4982     r = MsiRecordGetInteger(hrec, 1);
4983     ok(r == 1, "Expected 1, got %d\n", r);
4984     r = MsiRecordGetInteger(hrec, 2);
4985     ok(r == 0, "Expected 0, got %d\n", r);
4986
4987     r = MsiCloseHandle(hrec);
4988     ok(r == ERROR_SUCCESS, "failed to close record\n");
4989
4990     r = MsiViewFetch(hview, &hrec);
4991     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4992
4993     r = MsiRecordGetInteger(hrec, 1);
4994     ok(r == 3, "Expected 3, got %d\n", r);
4995     r = MsiRecordGetInteger(hrec, 2);
4996     ok(r == 0, "Expected 0, got %d\n", r);
4997
4998     r = MsiCloseHandle(hrec);
4999     ok(r == ERROR_SUCCESS, "failed to close record\n");
5000
5001     r = MsiViewFetch(hview, &hrec);
5002     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
5003
5004     r = MsiRecordGetInteger(hrec, 1);
5005     ok(r == 5, "Expected 5, got %d\n", r);
5006     r = MsiRecordGetInteger(hrec, 2);
5007     ok(r == 0, "Expected 0, got %d\n", r);
5008
5009     r = MsiCloseHandle(hrec);
5010     ok(r == ERROR_SUCCESS, "failed to close record\n");
5011
5012     r = MsiViewFetch(hview, &hrec);
5013     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5014
5015     r = MsiViewClose(hview);
5016     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
5017     r = MsiCloseHandle(hview);
5018     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
5019
5020     r = MsiCloseHandle( hdb );
5021     ok(r == ERROR_SUCCESS, "MsiOpenDatabase close failed\n");
5022 }
5023
5024 static void test_viewmodify_assign(void)
5025 {
5026     MSIHANDLE hdb = 0, hview = 0, hrec = 0;
5027     const char *query;
5028     UINT r;
5029
5030     /* setup database */
5031     DeleteFile(msifile);
5032
5033     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
5034     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
5035
5036     query = "CREATE TABLE `table` (`A` INT, `B` INT PRIMARY KEY `A`)";
5037     r = run_query( hdb, 0, query );
5038     ok(r == ERROR_SUCCESS, "query failed\n");
5039
5040     /* assign to view, new primary key */
5041     query = "SELECT * FROM `table`";
5042     r = MsiDatabaseOpenView(hdb, query, &hview);
5043     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
5044     r = MsiViewExecute(hview, 0);
5045     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
5046
5047     hrec = MsiCreateRecord(2);
5048     ok(hrec != 0, "MsiCreateRecord failed\n");
5049
5050     r = MsiRecordSetInteger(hrec, 1, 1);
5051     ok(r == ERROR_SUCCESS, "failed to set integer\n");
5052     r = MsiRecordSetInteger(hrec, 2, 2);
5053     ok(r == ERROR_SUCCESS, "failed to set integer\n");
5054
5055     r = MsiViewModify(hview, MSIMODIFY_ASSIGN, hrec);
5056     ok(r == ERROR_SUCCESS, "MsiViewModify failed: %d\n", r);
5057
5058     r = MsiCloseHandle(hrec);
5059     ok(r == ERROR_SUCCESS, "failed to close record\n");
5060
5061     r = MsiViewClose(hview);
5062     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
5063     r = MsiCloseHandle(hview);
5064     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
5065
5066     query = "SELECT * FROM `table`";
5067     r = MsiDatabaseOpenView(hdb, query, &hview);
5068     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
5069     r = MsiViewExecute(hview, 0);
5070     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
5071     r = MsiViewFetch(hview, &hrec);
5072     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
5073
5074     r = MsiRecordGetInteger(hrec, 1);
5075     ok(r == 1, "Expected 1, got %d\n", r);
5076     r = MsiRecordGetInteger(hrec, 2);
5077     ok(r == 2, "Expected 2, got %d\n", r);
5078
5079     r = MsiCloseHandle(hrec);
5080     ok(r == ERROR_SUCCESS, "failed to close record\n");
5081
5082     r = MsiViewFetch(hview, &hrec);
5083     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5084
5085     r = MsiViewClose(hview);
5086     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
5087     r = MsiCloseHandle(hview);
5088     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
5089
5090     /* assign to view, primary key matches */
5091     query = "SELECT * FROM `table`";
5092     r = MsiDatabaseOpenView(hdb, query, &hview);
5093     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
5094     r = MsiViewExecute(hview, 0);
5095     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
5096
5097     hrec = MsiCreateRecord(2);
5098     ok(hrec != 0, "MsiCreateRecord failed\n");
5099
5100     r = MsiRecordSetInteger(hrec, 1, 1);
5101     ok(r == ERROR_SUCCESS, "failed to set integer\n");
5102     r = MsiRecordSetInteger(hrec, 2, 4);
5103     ok(r == ERROR_SUCCESS, "failed to set integer\n");
5104
5105     r = MsiViewModify(hview, MSIMODIFY_ASSIGN, hrec);
5106     ok(r == ERROR_SUCCESS, "MsiViewModify failed: %d\n", r);
5107
5108     r = MsiCloseHandle(hrec);
5109     ok(r == ERROR_SUCCESS, "failed to close record\n");
5110
5111     r = MsiViewClose(hview);
5112     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
5113     r = MsiCloseHandle(hview);
5114     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
5115
5116     query = "SELECT * FROM `table`";
5117     r = MsiDatabaseOpenView(hdb, query, &hview);
5118     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
5119     r = MsiViewExecute(hview, 0);
5120     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
5121     r = MsiViewFetch(hview, &hrec);
5122     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
5123
5124     r = MsiRecordGetInteger(hrec, 1);
5125     ok(r == 1, "Expected 1, got %d\n", r);
5126     r = MsiRecordGetInteger(hrec, 2);
5127     ok(r == 4, "Expected 4, got %d\n", r);
5128
5129     r = MsiCloseHandle(hrec);
5130     ok(r == ERROR_SUCCESS, "failed to close record\n");
5131
5132     r = MsiViewFetch(hview, &hrec);
5133     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5134
5135     r = MsiViewClose(hview);
5136     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
5137     r = MsiCloseHandle(hview);
5138     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
5139
5140     /* close database */
5141     r = MsiCloseHandle( hdb );
5142     ok(r == ERROR_SUCCESS, "MsiOpenDatabase close failed\n");
5143 }
5144
5145 static const WCHAR data10[] = { /* MOO */
5146     0x8001, 0x000b,
5147 };
5148 static const WCHAR data11[] = { /* AAR */
5149     0x8002, 0x8005,
5150     0x000c, 0x000f,
5151 };
5152 static const char data12[] = /* _StringData */
5153     "MOOABAARCDonetwofourfive";
5154 static const WCHAR data13[] = { /* _StringPool */
5155 /*  len, refs */
5156     0,   0,    /* string 0 ''     */
5157     0,   0,    /* string 1 ''     */
5158     0,   0,    /* string 2 ''     */
5159     0,   0,    /* string 3 ''     */
5160     0,   0,    /* string 4 ''     */
5161     3,   3,    /* string 5 'MOO'  */
5162     1,   1,    /* string 6 'A'    */
5163     1,   1,    /* string 7 'B'    */
5164     3,   3,    /* string 8 'AAR'  */
5165     1,   1,    /* string 9 'C'    */
5166     1,   1,    /* string a 'D'    */
5167     3,   1,    /* string b 'one'  */
5168     3,   1,    /* string c 'two'  */
5169     0,   0,    /* string d ''     */
5170     4,   1,    /* string e 'four' */
5171     4,   1,    /* string f 'five' */
5172 };
5173
5174 static void test_stringtable(void)
5175 {
5176     MSIHANDLE hdb = 0, hview = 0, hrec = 0;
5177     IStorage *stg = NULL;
5178     IStream *stm;
5179     WCHAR name[0x20];
5180     HRESULT hr;
5181     const char *query;
5182     char buffer[MAX_PATH];
5183     WCHAR data[MAX_PATH];
5184     DWORD sz, read;
5185     UINT r;
5186
5187     static const DWORD mode = STGM_DIRECT | STGM_READ | STGM_SHARE_DENY_WRITE;
5188     static const WCHAR stringdata[] = {0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0}; /* _StringData */
5189     static const WCHAR stringpool[] = {0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0}; /* _StringPool */
5190     static const WCHAR moo[] = {0x4840, 0x3e16, 0x4818, 0}; /* MOO */
5191     static const WCHAR aar[] = {0x4840, 0x3a8a, 0x481b, 0}; /* AAR */
5192
5193     DeleteFile(msifile);
5194
5195     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
5196     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5197
5198     query = "CREATE TABLE `MOO` (`A` INT, `B` CHAR(72) PRIMARY KEY `A`)";
5199     r = run_query(hdb, 0, query);
5200     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5201
5202     query = "CREATE TABLE `AAR` (`C` INT, `D` CHAR(72) PRIMARY KEY `C`)";
5203     r = run_query(hdb, 0, query);
5204     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5205
5206     /* insert persistent row */
5207     query = "INSERT INTO `MOO` (`A`, `B`) VALUES (1, 'one')";
5208     r = run_query(hdb, 0, query);
5209     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5210
5211     /* insert persistent row */
5212     query = "INSERT INTO `AAR` (`C`, `D`) VALUES (2, 'two')";
5213     r = run_query(hdb, 0, query);
5214     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5215
5216     /* open a view */
5217     query = "SELECT * FROM `MOO`";
5218     r = MsiDatabaseOpenView(hdb, query, &hview);
5219     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5220     r = MsiViewExecute(hview, 0);
5221     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5222
5223     hrec = MsiCreateRecord(2);
5224
5225     r = MsiRecordSetInteger(hrec, 1, 3);
5226     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5227     r = MsiRecordSetString(hrec, 2, "three");
5228     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5229
5230     /* insert a nonpersistent row */
5231     r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec);
5232     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5233
5234     r = MsiCloseHandle(hrec);
5235     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5236     r = MsiViewClose(hview);
5237     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5238     r = MsiCloseHandle(hview);
5239     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5240
5241     /* insert persistent row */
5242     query = "INSERT INTO `MOO` (`A`, `B`) VALUES (4, 'four')";
5243     r = run_query(hdb, 0, query);
5244     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5245
5246     /* insert persistent row */
5247     query = "INSERT INTO `AAR` (`C`, `D`) VALUES (5, 'five')";
5248     r = run_query(hdb, 0, query);
5249     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5250
5251     r = MsiDatabaseCommit(hdb);
5252     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5253
5254     r = MsiCloseHandle(hdb);
5255     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5256
5257     r = MsiOpenDatabase(msifile, MSIDBOPEN_READONLY, &hdb);
5258     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5259
5260     query = "SELECT * FROM `MOO`";
5261     r = MsiDatabaseOpenView(hdb, query, &hview);
5262     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5263
5264     r = MsiViewExecute(hview, 0);
5265     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5266
5267     r = MsiViewFetch(hview, &hrec);
5268     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5269
5270     r = MsiRecordGetFieldCount(hrec);
5271     ok(r == 2, "Expected 2, got %d\n", r);
5272
5273     r = MsiRecordGetInteger(hrec, 1);
5274     ok(r == 1, "Expected 1, got %d\n", r);
5275
5276     sz = sizeof(buffer);
5277     r = MsiRecordGetString(hrec, 2, buffer, &sz);
5278     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5279     ok(!lstrcmp(buffer, "one"), "Expected one, got %s\n", buffer);
5280
5281     r = MsiCloseHandle(hrec);
5282     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5283
5284     r = MsiViewFetch(hview, &hrec);
5285     todo_wine
5286     {
5287         ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5288     }
5289
5290     r = MsiViewClose(hview);
5291     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5292     r = MsiCloseHandle(hview);
5293     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5294     r = MsiCloseHandle(hrec);
5295     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5296
5297     query = "SELECT * FROM `AAR`";
5298     r = MsiDatabaseOpenView(hdb, query, &hview);
5299     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5300
5301     r = MsiViewExecute(hview, 0);
5302     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5303
5304     r = MsiViewFetch(hview, &hrec);
5305     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5306
5307     r = MsiRecordGetFieldCount(hrec);
5308     ok(r == 2, "Expected 2, got %d\n", r);
5309
5310     r = MsiRecordGetInteger(hrec, 1);
5311     ok(r == 2, "Expected 2, got %d\n", r);
5312
5313     sz = sizeof(buffer);
5314     r = MsiRecordGetString(hrec, 2, buffer, &sz);
5315     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5316     ok(!lstrcmp(buffer, "two"), "Expected two, got %s\n", buffer);
5317
5318     r = MsiCloseHandle(hrec);
5319     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5320
5321     r = MsiViewFetch(hview, &hrec);
5322     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5323
5324     r = MsiRecordGetFieldCount(hrec);
5325     ok(r == 2, "Expected 2, got %d\n", r);
5326
5327     r = MsiRecordGetInteger(hrec, 1);
5328     ok(r == 5, "Expected 5, got %d\n", r);
5329
5330     sz = sizeof(buffer);
5331     r = MsiRecordGetString(hrec, 2, buffer, &sz);
5332     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5333     ok(!lstrcmp(buffer, "five"), "Expected five, got %s\n", buffer);
5334
5335     r = MsiCloseHandle(hrec);
5336     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5337
5338     r = MsiViewFetch(hview, &hrec);
5339     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5340
5341     r = MsiViewClose(hview);
5342     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5343     r = MsiCloseHandle(hview);
5344     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5345     r = MsiCloseHandle(hrec);
5346     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5347     r = MsiCloseHandle(hdb);
5348     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5349
5350     MultiByteToWideChar(CP_ACP, 0, msifile, -1, name, 0x20);
5351     hr = StgOpenStorage(name, NULL, mode, NULL, 0, &stg);
5352     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5353     ok(stg != NULL, "Expected non-NULL storage\n");
5354
5355     hr = IStorage_OpenStream(stg, moo, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm);
5356     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5357     ok(stm != NULL, "Expected non-NULL stream\n");
5358
5359     hr = IStream_Read(stm, data, MAX_PATH, &read);
5360     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5361     todo_wine
5362     {
5363         ok(read == 4, "Expected 4, got %d\n", read);
5364         ok(!memcmp(data, data10, read), "Unexpected data\n");
5365     }
5366
5367     hr = IStream_Release(stm);
5368     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5369
5370     hr = IStorage_OpenStream(stg, aar, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm);
5371     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5372     ok(stm != NULL, "Expected non-NULL stream\n");
5373
5374     hr = IStream_Read(stm, data, MAX_PATH, &read);
5375     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5376     ok(read == 8, "Expected 8, got %d\n", read);
5377     todo_wine
5378     {
5379         ok(!memcmp(data, data11, read), "Unexpected data\n");
5380     }
5381
5382     hr = IStream_Release(stm);
5383     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5384
5385     hr = IStorage_OpenStream(stg, stringdata, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm);
5386     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5387     ok(stm != NULL, "Expected non-NULL stream\n");
5388
5389     hr = IStream_Read(stm, buffer, MAX_PATH, &read);
5390     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5391     ok(read == 24, "Expected 24, got %d\n", read);
5392     ok(!memcmp(buffer, data12, read), "Unexpected data\n");
5393
5394     hr = IStream_Release(stm);
5395     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5396
5397     hr = IStorage_OpenStream(stg, stringpool, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm);
5398     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5399     ok(stm != NULL, "Expected non-NULL stream\n");
5400
5401     hr = IStream_Read(stm, data, MAX_PATH, &read);
5402     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5403     todo_wine
5404     {
5405         ok(read == 64, "Expected 64, got %d\n", read);
5406         ok(!memcmp(data, data13, read), "Unexpected data\n");
5407     }
5408
5409     hr = IStream_Release(stm);
5410     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5411
5412     hr = IStorage_Release(stg);
5413     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
5414
5415     DeleteFileA(msifile);
5416 }
5417
5418 static void test_viewmodify_delete(void)
5419 {
5420     MSIHANDLE hdb = 0, hview = 0, hrec = 0;
5421     UINT r;
5422     const char *query;
5423     char buffer[0x100];
5424     DWORD sz;
5425
5426     DeleteFile(msifile);
5427
5428     /* just MsiOpenDatabase should not create a file */
5429     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
5430     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5431
5432     query = "CREATE TABLE `phone` ( "
5433             "`id` INT, `name` CHAR(32), `number` CHAR(32) "
5434             "PRIMARY KEY `id`)";
5435     r = run_query(hdb, 0, query);
5436     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5437
5438     query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
5439         "VALUES('1', 'Alan', '5030581')";
5440     r = run_query(hdb, 0, query);
5441     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5442
5443     query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
5444         "VALUES('2', 'Barry', '928440')";
5445     r = run_query(hdb, 0, query);
5446     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5447
5448     query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
5449         "VALUES('3', 'Cindy', '2937550')";
5450     r = run_query(hdb, 0, query);
5451     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5452
5453     query = "SELECT * FROM `phone` WHERE `id` <= 2";
5454     r = MsiDatabaseOpenView(hdb, query, &hview);
5455     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5456     r = MsiViewExecute(hview, 0);
5457     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5458     r = MsiViewFetch(hview, &hrec);
5459     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5460
5461     /* delete 1 */
5462     r = MsiViewModify(hview, MSIMODIFY_DELETE, hrec);
5463     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5464
5465     r = MsiCloseHandle(hrec);
5466     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5467     r = MsiViewFetch(hview, &hrec);
5468     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5469
5470     /* delete 2 */
5471     r = MsiViewModify(hview, MSIMODIFY_DELETE, hrec);
5472     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5473
5474     r = MsiCloseHandle(hrec);
5475     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5476     r = MsiViewClose(hview);
5477     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5478     r = MsiCloseHandle(hview);
5479     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5480
5481     query = "SELECT * FROM `phone`";
5482     r = MsiDatabaseOpenView(hdb, query, &hview);
5483     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5484     r = MsiViewExecute(hview, 0);
5485     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5486     r = MsiViewFetch(hview, &hrec);
5487     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5488
5489     r = MsiRecordGetInteger(hrec, 1);
5490     ok(r == 3, "Expected 3, got %d\n", r);
5491
5492     sz = sizeof(buffer);
5493     r = MsiRecordGetString(hrec, 2, buffer, &sz);
5494     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5495     ok(!lstrcmp(buffer, "Cindy"), "Expected Cindy, got %s\n", buffer);
5496
5497     sz = sizeof(buffer);
5498     r = MsiRecordGetString(hrec, 3, buffer, &sz);
5499     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5500     ok(!lstrcmp(buffer, "2937550"), "Expected 2937550, got %s\n", buffer);
5501
5502     r = MsiCloseHandle(hrec);
5503     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5504
5505     r = MsiViewFetch(hview, &hrec);
5506     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5507
5508     r = MsiViewClose(hview);
5509     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5510     r = MsiCloseHandle(hview);
5511     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5512     r = MsiCloseHandle(hdb);
5513     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5514 }
5515
5516 static const WCHAR _Tables[] = {0x4840, 0x3f7f, 0x4164, 0x422f, 0x4836, 0};
5517 static const WCHAR _StringData[] = {0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0};
5518 static const WCHAR _StringPool[] = {0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0};
5519
5520 static const WCHAR data14[] = { /* _StringPool */
5521 /*  len, refs */
5522     0,   0,    /* string 0 ''    */
5523 };
5524
5525 static const struct {
5526     LPCWSTR name;
5527     const void *data;
5528     DWORD size;
5529 } database_table_data[] =
5530 {
5531     {_Tables, NULL, 0},
5532     {_StringData, NULL, 0},
5533     {_StringPool, data14, sizeof data14},
5534 };
5535
5536 static void enum_stream_names(IStorage *stg)
5537 {
5538     IEnumSTATSTG *stgenum = NULL;
5539     IStream *stm;
5540     HRESULT hr;
5541     STATSTG stat;
5542     ULONG n, count;
5543     BYTE data[MAX_PATH];
5544     BYTE check[MAX_PATH];
5545     DWORD sz;
5546
5547     memset(check, 'a', MAX_PATH);
5548
5549     hr = IStorage_EnumElements(stg, 0, NULL, 0, &stgenum);
5550     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
5551
5552     n = 0;
5553     while(TRUE)
5554     {
5555         count = 0;
5556         hr = IEnumSTATSTG_Next(stgenum, 1, &stat, &count);
5557         if(FAILED(hr) || !count)
5558             break;
5559
5560         ok(!lstrcmpW(stat.pwcsName, database_table_data[n].name),
5561            "Expected table %d name to match\n", n);
5562
5563         stm = NULL;
5564         hr = IStorage_OpenStream(stg, stat.pwcsName, NULL,
5565                                  STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm);
5566         ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
5567         ok(stm != NULL, "Expected non-NULL stream\n");
5568
5569         CoTaskMemFree(stat.pwcsName);
5570
5571         sz = MAX_PATH;
5572         memset(data, 'a', MAX_PATH);
5573         hr = IStream_Read(stm, data, sz, &count);
5574         ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
5575
5576         ok(count == database_table_data[n].size,
5577            "Expected %d, got %d\n", database_table_data[n].size, count);
5578
5579         if (!database_table_data[n].size)
5580             ok(!memcmp(data, check, MAX_PATH), "data should not be changed\n");
5581         else
5582             ok(!memcmp(data, database_table_data[n].data, database_table_data[n].size),
5583                "Expected table %d data to match\n", n);
5584
5585         IStream_Release(stm);
5586         n++;
5587     }
5588
5589     ok(n == 3, "Expected 3, got %d\n", n);
5590
5591     IEnumSTATSTG_Release(stgenum);
5592 }
5593
5594 static void test_defaultdatabase(void)
5595 {
5596     UINT r;
5597     HRESULT hr;
5598     MSIHANDLE hdb;
5599     IStorage *stg = NULL;
5600
5601     DeleteFile(msifile);
5602
5603     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
5604     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5605
5606     r = MsiDatabaseCommit(hdb);
5607     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5608
5609     MsiCloseHandle(hdb);
5610
5611     hr = StgOpenStorage(msifileW, NULL, STGM_READ | STGM_SHARE_DENY_WRITE, NULL, 0, &stg);
5612     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
5613     ok(stg != NULL, "Expected non-NULL stg\n");
5614
5615     enum_stream_names(stg);
5616
5617     IStorage_Release(stg);
5618     DeleteFileA(msifile);
5619 }
5620
5621 static void test_order(void)
5622 {
5623     MSIHANDLE hdb, hview, hrec;
5624     CHAR buffer[MAX_PATH];
5625     LPCSTR query;
5626     UINT r, sz;
5627     int val;
5628
5629     hdb = create_db();
5630     ok(hdb, "failed to create db\n");
5631
5632     query = "CREATE TABLE `Empty` ( `A` SHORT NOT NULL PRIMARY KEY `A`)";
5633     r = run_query(hdb, 0, query);
5634     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5635
5636     query = "CREATE TABLE `Mesa` ( `A` SHORT NOT NULL, `B` SHORT, `C` SHORT PRIMARY KEY `A`)";
5637     r = run_query(hdb, 0, query);
5638     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5639
5640     query = "INSERT INTO `Mesa` ( `A`, `B`, `C` ) VALUES ( 1, 2, 9 )";
5641     r = run_query(hdb, 0, query);
5642     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5643
5644     query = "INSERT INTO `Mesa` ( `A`, `B`, `C` ) VALUES ( 3, 4, 7 )";
5645     r = run_query(hdb, 0, query);
5646     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5647
5648     query = "INSERT INTO `Mesa` ( `A`, `B`, `C` ) VALUES ( 5, 6, 8 )";
5649     r = run_query(hdb, 0, query);
5650     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5651
5652     query = "CREATE TABLE `Sideboard` ( `D` SHORT NOT NULL, `E` SHORT, `F` SHORT PRIMARY KEY `D`)";
5653     r = run_query(hdb, 0, query);
5654     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5655
5656     query = "INSERT INTO `Sideboard` ( `D`, `E`, `F` ) VALUES ( 10, 11, 18 )";
5657     r = run_query(hdb, 0, query);
5658     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5659
5660     query = "INSERT INTO `Sideboard` ( `D`, `E`, `F` ) VALUES ( 12, 13, 16 )";
5661     r = run_query(hdb, 0, query);
5662     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5663
5664     query = "INSERT INTO `Sideboard` ( `D`, `E`, `F` ) VALUES ( 14, 15, 17 )";
5665     r = run_query(hdb, 0, query);
5666     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5667
5668     query = "SELECT `A`, `B` FROM `Mesa` ORDER BY `C`";
5669     r = MsiDatabaseOpenView(hdb, query, &hview);
5670     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5671     r = MsiViewExecute(hview, 0);
5672     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5673
5674     r = MsiViewFetch(hview, &hrec);
5675     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5676
5677     val = MsiRecordGetInteger(hrec, 1);
5678     ok(val == 3, "Expected 3, got %d\n", val);
5679
5680     val = MsiRecordGetInteger(hrec, 2);
5681     ok(val == 4, "Expected 3, got %d\n", val);
5682
5683     MsiCloseHandle(hrec);
5684
5685     r = MsiViewFetch(hview, &hrec);
5686     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5687
5688     val = MsiRecordGetInteger(hrec, 1);
5689     ok(val == 5, "Expected 5, got %d\n", val);
5690
5691     val = MsiRecordGetInteger(hrec, 2);
5692     ok(val == 6, "Expected 6, got %d\n", val);
5693
5694     MsiCloseHandle(hrec);
5695
5696     r = MsiViewFetch(hview, &hrec);
5697     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5698
5699     val = MsiRecordGetInteger(hrec, 1);
5700     ok(val == 1, "Expected 1, got %d\n", val);
5701
5702     val = MsiRecordGetInteger(hrec, 2);
5703     ok(val == 2, "Expected 2, got %d\n", val);
5704
5705     MsiCloseHandle(hrec);
5706
5707     r = MsiViewFetch(hview, &hrec);
5708     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5709
5710     MsiViewClose(hview);
5711     MsiCloseHandle(hview);
5712
5713     query = "SELECT `A`, `D` FROM `Mesa`, `Sideboard` ORDER BY `F`";
5714     r = MsiDatabaseOpenView(hdb, query, &hview);
5715     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5716     r = MsiViewExecute(hview, 0);
5717     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5718
5719     r = MsiViewFetch(hview, &hrec);
5720     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5721
5722     val = MsiRecordGetInteger(hrec, 1);
5723     ok(val == 1, "Expected 1, got %d\n", val);
5724
5725     val = MsiRecordGetInteger(hrec, 2);
5726     ok(val == 12, "Expected 12, got %d\n", val);
5727
5728     MsiCloseHandle(hrec);
5729
5730     r = MsiViewFetch(hview, &hrec);
5731     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5732
5733     val = MsiRecordGetInteger(hrec, 1);
5734     ok(val == 3, "Expected 3, got %d\n", val);
5735
5736     val = MsiRecordGetInteger(hrec, 2);
5737     ok(val == 12, "Expected 12, got %d\n", val);
5738
5739     MsiCloseHandle(hrec);
5740
5741     r = MsiViewFetch(hview, &hrec);
5742     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5743
5744     val = MsiRecordGetInteger(hrec, 1);
5745     ok(val == 5, "Expected 5, got %d\n", val);
5746
5747     val = MsiRecordGetInteger(hrec, 2);
5748     ok(val == 12, "Expected 12, got %d\n", val);
5749
5750     MsiCloseHandle(hrec);
5751
5752     r = MsiViewFetch(hview, &hrec);
5753     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5754
5755     val = MsiRecordGetInteger(hrec, 1);
5756     ok(val == 1, "Expected 1, got %d\n", val);
5757
5758     val = MsiRecordGetInteger(hrec, 2);
5759     ok(val == 14, "Expected 14, got %d\n", val);
5760
5761     MsiCloseHandle(hrec);
5762
5763     r = MsiViewFetch(hview, &hrec);
5764     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5765
5766     val = MsiRecordGetInteger(hrec, 1);
5767     ok(val == 3, "Expected 3, got %d\n", val);
5768
5769     val = MsiRecordGetInteger(hrec, 2);
5770     ok(val == 14, "Expected 14, got %d\n", val);
5771
5772     MsiCloseHandle(hrec);
5773
5774     r = MsiViewFetch(hview, &hrec);
5775     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5776
5777     val = MsiRecordGetInteger(hrec, 1);
5778     ok(val == 5, "Expected 5, got %d\n", val);
5779
5780     val = MsiRecordGetInteger(hrec, 2);
5781     ok(val == 14, "Expected 14, got %d\n", val);
5782
5783     MsiCloseHandle(hrec);
5784
5785     r = MsiViewFetch(hview, &hrec);
5786     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5787
5788     val = MsiRecordGetInteger(hrec, 1);
5789     ok(val == 1, "Expected 1, got %d\n", val);
5790
5791     val = MsiRecordGetInteger(hrec, 2);
5792     ok(val == 10, "Expected 10, got %d\n", val);
5793
5794     MsiCloseHandle(hrec);
5795
5796     r = MsiViewFetch(hview, &hrec);
5797     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5798
5799     val = MsiRecordGetInteger(hrec, 1);
5800     ok(val == 3, "Expected 3, got %d\n", val);
5801
5802     val = MsiRecordGetInteger(hrec, 2);
5803     ok(val == 10, "Expected 10, got %d\n", val);
5804
5805     MsiCloseHandle(hrec);
5806
5807     r = MsiViewFetch(hview, &hrec);
5808     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5809
5810     val = MsiRecordGetInteger(hrec, 1);
5811     ok(val == 5, "Expected 5, got %d\n", val);
5812
5813     val = MsiRecordGetInteger(hrec, 2);
5814     ok(val == 10, "Expected 10, got %d\n", val);
5815
5816     MsiCloseHandle(hrec);
5817
5818     r = MsiViewFetch(hview, &hrec);
5819     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5820
5821     MsiViewClose(hview);
5822     MsiCloseHandle(hview);
5823
5824     query = "SELECT * FROM `Empty` ORDER BY `A`";
5825     r = MsiDatabaseOpenView(hdb, query, &hview);
5826     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5827     r = MsiViewExecute(hview, 0);
5828     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5829
5830     r = MsiViewFetch(hview, &hrec);
5831     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5832
5833     MsiViewClose(hview);
5834     MsiCloseHandle(hview);
5835
5836     query = "CREATE TABLE `Buffet` ( `One` CHAR(72), `Two` SHORT PRIMARY KEY `One`)";
5837     r = run_query(hdb, 0, query);
5838     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5839
5840     query = "INSERT INTO `Buffet` ( `One`, `Two` ) VALUES ( 'uno',  2)";
5841     r = run_query(hdb, 0, query);
5842     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5843
5844     query = "INSERT INTO `Buffet` ( `One`, `Two` ) VALUES ( 'dos',  3)";
5845     r = run_query(hdb, 0, query);
5846     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5847
5848     query = "INSERT INTO `Buffet` ( `One`, `Two` ) VALUES ( 'tres',  1)";
5849     r = run_query(hdb, 0, query);
5850     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5851
5852     query = "SELECT * FROM `Buffet` WHERE `One` = 'dos' ORDER BY `Two`";
5853     r = MsiDatabaseOpenView(hdb, query, &hview);
5854     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5855     r = MsiViewExecute(hview, 0);
5856     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5857
5858     r = MsiViewFetch(hview, &hrec);
5859     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5860
5861     sz = sizeof(buffer);
5862     r = MsiRecordGetString(hrec, 1, buffer, &sz);
5863     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5864     ok(!lstrcmp(buffer, "dos"), "Expected \"dos\", got \"%s\"\n", buffer);
5865
5866     r = MsiRecordGetInteger(hrec, 2);
5867     ok(r == 3, "Expected 3, got %d\n", r);
5868
5869     MsiCloseHandle(hrec);
5870
5871     r = MsiViewFetch(hview, &hrec);
5872     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5873
5874     MsiViewClose(hview);
5875     MsiCloseHandle(hview);
5876     MsiCloseHandle(hdb);
5877 }
5878
5879 static void test_viewmodify_delete_temporary(void)
5880 {
5881     MSIHANDLE hdb, hview, hrec;
5882     const char *query;
5883     UINT r;
5884
5885     DeleteFile(msifile);
5886
5887     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
5888     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5889
5890     query = "CREATE TABLE `Table` ( `A` SHORT PRIMARY KEY `A` )";
5891     r = run_query(hdb, 0, query);
5892     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5893
5894     query = "SELECT * FROM `Table`";
5895     r = MsiDatabaseOpenView(hdb, query, &hview);
5896     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5897     r = MsiViewExecute(hview, 0);
5898     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5899
5900     hrec = MsiCreateRecord(1);
5901     MsiRecordSetInteger(hrec, 1, 1);
5902
5903     r = MsiViewModify(hview, MSIMODIFY_INSERT, hrec);
5904     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5905
5906     MsiCloseHandle(hrec);
5907
5908     hrec = MsiCreateRecord(1);
5909     MsiRecordSetInteger(hrec, 1, 2);
5910
5911     r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec);
5912     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5913
5914     MsiCloseHandle(hrec);
5915
5916     hrec = MsiCreateRecord(1);
5917     MsiRecordSetInteger(hrec, 1, 3);
5918
5919     r = MsiViewModify(hview, MSIMODIFY_INSERT, hrec);
5920     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5921
5922     MsiCloseHandle(hrec);
5923
5924     hrec = MsiCreateRecord(1);
5925     MsiRecordSetInteger(hrec, 1, 4);
5926
5927     r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec);
5928     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5929
5930     MsiCloseHandle(hrec);
5931     MsiViewClose(hview);
5932     MsiCloseHandle(hview);
5933
5934     query = "SELECT * FROM `Table` WHERE  `A` = 2";
5935     r = MsiDatabaseOpenView(hdb, query, &hview);
5936     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5937     r = MsiViewExecute(hview, 0);
5938     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5939     r = MsiViewFetch(hview, &hrec);
5940     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5941
5942     r = MsiViewModify(hview, MSIMODIFY_DELETE, hrec);
5943     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5944
5945     MsiCloseHandle(hrec);
5946     MsiViewClose(hview);
5947     MsiCloseHandle(hview);
5948
5949     query = "SELECT * FROM `Table` WHERE  `A` = 3";
5950     r = MsiDatabaseOpenView(hdb, query, &hview);
5951     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5952     r = MsiViewExecute(hview, 0);
5953     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5954     r = MsiViewFetch(hview, &hrec);
5955     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5956
5957     r = MsiViewModify(hview, MSIMODIFY_DELETE, hrec);
5958     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5959
5960     MsiCloseHandle(hrec);
5961     MsiViewClose(hview);
5962     MsiCloseHandle(hview);
5963
5964     query = "SELECT * FROM `Table` ORDER BY `A`";
5965     r = MsiDatabaseOpenView(hdb, query, &hview);
5966     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5967     r = MsiViewExecute(hview, 0);
5968     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5969
5970     r = MsiViewFetch(hview, &hrec);
5971     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5972
5973     r = MsiRecordGetInteger(hrec, 1);
5974     ok(r == 1, "Expected 1, got %d\n", r);
5975
5976     MsiCloseHandle(hrec);
5977
5978     r = MsiViewFetch(hview, &hrec);
5979     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5980
5981     r = MsiRecordGetInteger(hrec, 1);
5982     ok(r == 4, "Expected 4, got %d\n", r);
5983
5984     MsiCloseHandle(hrec);
5985
5986     r = MsiViewFetch(hview, &hrec);
5987     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5988
5989     MsiViewClose(hview);
5990     MsiCloseHandle(hview);
5991     MsiCloseHandle(hdb);
5992     DeleteFileA(msifile);
5993 }
5994
5995 static void test_deleterow(void)
5996 {
5997     MSIHANDLE hdb, hview, hrec;
5998     const char *query;
5999     char buf[MAX_PATH];
6000     UINT r;
6001     DWORD size;
6002
6003     DeleteFile(msifile);
6004
6005     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
6006     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6007
6008     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6009     r = run_query(hdb, 0, query);
6010     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6011
6012     query = "INSERT INTO `Table` (`A`) VALUES ('one')";
6013     r = run_query(hdb, 0, query);
6014     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6015
6016     query = "INSERT INTO `Table` (`A`) VALUES ('two')";
6017     r = run_query(hdb, 0, query);
6018     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6019
6020     query = "DELETE FROM `Table` WHERE `A` = 'one'";
6021     r = run_query(hdb, 0, query);
6022     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6023
6024     r = MsiDatabaseCommit(hdb);
6025     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6026
6027     MsiCloseHandle(hdb);
6028
6029     r = MsiOpenDatabase(msifile, MSIDBOPEN_READONLY, &hdb);
6030     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6031
6032     query = "SELECT * FROM `Table`";
6033     r = MsiDatabaseOpenView(hdb, query, &hview);
6034     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6035     r = MsiViewExecute(hview, 0);
6036     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6037
6038     r = MsiViewFetch(hview, &hrec);
6039     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6040
6041     size = MAX_PATH;
6042     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6043     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6044     ok(!lstrcmpA(buf, "two"), "Expected two, got %s\n", buf);
6045
6046     MsiCloseHandle(hrec);
6047
6048     r = MsiViewFetch(hview, &hrec);
6049     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6050
6051     MsiViewClose(hview);
6052     MsiCloseHandle(hview);
6053     MsiCloseHandle(hdb);
6054     DeleteFileA(msifile);
6055 }
6056
6057 static const CHAR import_dat[] = "A\n"
6058                                  "s72\n"
6059                                  "Table\tA\n"
6060                                  "This is a new 'string' ok\n";
6061
6062 static void test_quotes(void)
6063 {
6064     MSIHANDLE hdb, hview, hrec;
6065     const char *query;
6066     char buf[MAX_PATH];
6067     UINT r;
6068     DWORD size;
6069
6070     DeleteFile(msifile);
6071
6072     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
6073     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6074
6075     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6076     r = run_query(hdb, 0, query);
6077     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6078
6079     query = "INSERT INTO `Table` ( `A` ) VALUES ( 'This is a 'string' ok' )";
6080     r = run_query(hdb, 0, query);
6081     ok(r == ERROR_BAD_QUERY_SYNTAX,
6082        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6083
6084     query = "INSERT INTO `Table` ( `A` ) VALUES ( \"This is a 'string' ok\" )";
6085     r = run_query(hdb, 0, query);
6086     ok(r == ERROR_BAD_QUERY_SYNTAX,
6087        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6088
6089     query = "INSERT INTO `Table` ( `A` ) VALUES ( \"test\" )";
6090     r = run_query(hdb, 0, query);
6091     ok(r == ERROR_BAD_QUERY_SYNTAX,
6092        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6093
6094     query = "INSERT INTO `Table` ( `A` ) VALUES ( 'This is a ''string'' ok' )";
6095     r = run_query(hdb, 0, query);
6096     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6097
6098     query = "INSERT INTO `Table` ( `A` ) VALUES ( 'This is a '''string''' ok' )";
6099     r = run_query(hdb, 0, query);
6100     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6101
6102     query = "INSERT INTO `Table` ( `A` ) VALUES ( 'This is a \'string\' ok' )";
6103     r = run_query(hdb, 0, query);
6104     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6105
6106     query = "INSERT INTO `Table` ( `A` ) VALUES ( 'This is a \"string\" ok' )";
6107     r = run_query(hdb, 0, query);
6108     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6109
6110     query = "SELECT * FROM `Table`";
6111     r = MsiDatabaseOpenView(hdb, query, &hview);
6112     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6113
6114     r = MsiViewExecute(hview, 0);
6115     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6116
6117     r = MsiViewFetch(hview, &hrec);
6118     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6119
6120     size = MAX_PATH;
6121     r = MsiRecordGetString(hrec, 1, buf, &size);
6122     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6123     ok(!lstrcmp(buf, "This is a \"string\" ok"),
6124        "Expected \"This is a \"string\" ok\", got %s\n", buf);
6125
6126     MsiCloseHandle(hrec);
6127
6128     r = MsiViewFetch(hview, &hrec);
6129     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6130
6131     MsiViewClose(hview);
6132     MsiCloseHandle(hview);
6133
6134     write_file("import.idt", import_dat, (sizeof(import_dat) - 1) * sizeof(char));
6135
6136     r = MsiDatabaseImportA(hdb, CURR_DIR, "import.idt");
6137     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6138
6139     DeleteFileA("import.idt");
6140
6141     query = "SELECT * FROM `Table`";
6142     r = MsiDatabaseOpenView(hdb, query, &hview);
6143     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6144
6145     r = MsiViewExecute(hview, 0);
6146     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6147
6148     r = MsiViewFetch(hview, &hrec);
6149     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6150
6151     size = MAX_PATH;
6152     r = MsiRecordGetString(hrec, 1, buf, &size);
6153     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6154     ok(!lstrcmp(buf, "This is a new 'string' ok"),
6155        "Expected \"This is a new 'string' ok\", got %s\n", buf);
6156
6157     MsiCloseHandle(hrec);
6158
6159     r = MsiViewFetch(hview, &hrec);
6160     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6161
6162     MsiViewClose(hview);
6163     MsiCloseHandle(hview);
6164     MsiCloseHandle(hdb);
6165     DeleteFileA(msifile);
6166 }
6167
6168 static void test_carriagereturn(void)
6169 {
6170     MSIHANDLE hdb, hview, hrec;
6171     const char *query;
6172     char buf[MAX_PATH];
6173     UINT r;
6174     DWORD size;
6175
6176     DeleteFile(msifile);
6177
6178     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
6179     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6180
6181     query = "CREATE TABLE `Table`\r ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6182     r = run_query(hdb, 0, query);
6183     ok(r == ERROR_BAD_QUERY_SYNTAX,
6184        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6185
6186     query = "CREATE TABLE `Table` \r( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6187     r = run_query(hdb, 0, query);
6188     ok(r == ERROR_BAD_QUERY_SYNTAX,
6189        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6190
6191     query = "CREATE\r TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6192     r = run_query(hdb, 0, query);
6193     ok(r == ERROR_BAD_QUERY_SYNTAX,
6194        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6195
6196     query = "CREATE TABLE\r `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6197     r = run_query(hdb, 0, query);
6198     ok(r == ERROR_BAD_QUERY_SYNTAX,
6199        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6200
6201     query = "CREATE TABLE `Table` (\r `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6202     r = run_query(hdb, 0, query);
6203     ok(r == ERROR_BAD_QUERY_SYNTAX,
6204        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6205
6206     query = "CREATE TABLE `Table` ( `A`\r CHAR(72) NOT NULL PRIMARY KEY `A` )";
6207     r = run_query(hdb, 0, query);
6208     ok(r == ERROR_BAD_QUERY_SYNTAX,
6209        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6210
6211     query = "CREATE TABLE `Table` ( `A` CHAR(72)\r NOT NULL PRIMARY KEY `A` )";
6212     r = run_query(hdb, 0, query);
6213     ok(r == ERROR_BAD_QUERY_SYNTAX,
6214        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6215
6216     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT\r NULL PRIMARY KEY `A` )";
6217     r = run_query(hdb, 0, query);
6218     ok(r == ERROR_BAD_QUERY_SYNTAX,
6219        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6220
6221     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT \rNULL PRIMARY KEY `A` )";
6222     r = run_query(hdb, 0, query);
6223     ok(r == ERROR_BAD_QUERY_SYNTAX,
6224        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6225
6226     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL\r PRIMARY KEY `A` )";
6227     r = run_query(hdb, 0, query);
6228     ok(r == ERROR_BAD_QUERY_SYNTAX,
6229        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6230
6231     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL \rPRIMARY KEY `A` )";
6232     r = run_query(hdb, 0, query);
6233     ok(r == ERROR_BAD_QUERY_SYNTAX,
6234        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6235
6236     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY\r KEY `A` )";
6237     r = run_query(hdb, 0, query);
6238     ok(r == ERROR_BAD_QUERY_SYNTAX,
6239        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6240
6241     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY \rKEY `A` )";
6242     r = run_query(hdb, 0, query);
6243     ok(r == ERROR_BAD_QUERY_SYNTAX,
6244        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6245
6246     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY\r `A` )";
6247     r = run_query(hdb, 0, query);
6248     ok(r == ERROR_BAD_QUERY_SYNTAX,
6249        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6250
6251     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A`\r )";
6252     r = run_query(hdb, 0, query);
6253     ok(r == ERROR_BAD_QUERY_SYNTAX,
6254        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6255
6256     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )\r";
6257     r = run_query(hdb, 0, query);
6258     ok(r == ERROR_BAD_QUERY_SYNTAX,
6259        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6260
6261     query = "CREATE TABLE `\rOne` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6262     r = run_query(hdb, 0, query);
6263     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6264
6265     query = "CREATE TABLE `Tw\ro` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6266     r = run_query(hdb, 0, query);
6267     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6268
6269     query = "CREATE TABLE `Three\r` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6270     r = run_query(hdb, 0, query);
6271     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6272
6273     query = "CREATE TABLE `Four` ( `A\r` CHAR(72) NOT 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 `Four` ( `\rA` CHAR(72) NOT NULL 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 `Four` ( `A` CHAR(72\r) NOT NULL 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 `Four` ( `A` CHAR(\r72) NOT NULL PRIMARY 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 `Four` ( `A` CHAR(72) NOT NULL PRIMARY KEY `\rA` )";
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 `Four` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A\r` )";
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 `Four` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A\r` )";
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 = "SELECT * FROM `_Tables`";
6309     r = MsiDatabaseOpenView(hdb, query, &hview);
6310     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6311     r = MsiViewExecute(hview, 0);
6312     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6313
6314     r = MsiViewFetch(hview, &hrec);
6315     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6316
6317     size = MAX_PATH;
6318     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6319     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6320     ok(!lstrcmpA(buf, "\rOne"), "Expected \"\\rOne\", got \"%s\"\n", buf);
6321
6322     MsiCloseHandle(hrec);
6323
6324     r = MsiViewFetch(hview, &hrec);
6325     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6326
6327     size = MAX_PATH;
6328     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6329     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6330     ok(!lstrcmpA(buf, "Tw\ro"), "Expected \"Tw\\ro\", got \"%s\"\n", buf);
6331
6332     MsiCloseHandle(hrec);
6333
6334     r = MsiViewFetch(hview, &hrec);
6335     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6336
6337     size = MAX_PATH;
6338     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6339     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6340     ok(!lstrcmpA(buf, "Three\r"), "Expected \"Three\r\", got \"%s\"\n", buf);
6341
6342     MsiCloseHandle(hrec);
6343
6344     r = MsiViewFetch(hview, &hrec);
6345     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6346
6347     MsiViewClose(hview);
6348     MsiCloseHandle(hview);
6349
6350     MsiCloseHandle(hdb);
6351     DeleteFileA(msifile);
6352 }
6353
6354 static void test_noquotes(void)
6355 {
6356     MSIHANDLE hdb, hview, hrec;
6357     const char *query;
6358     char buf[MAX_PATH];
6359     UINT r;
6360     DWORD size;
6361
6362     DeleteFile(msifile);
6363
6364     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
6365     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6366
6367     query = "CREATE TABLE Table ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6368     r = run_query(hdb, 0, query);
6369     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6370
6371     query = "CREATE TABLE `Table` ( A CHAR(72) NOT NULL PRIMARY KEY `A` )";
6372     r = run_query(hdb, 0, query);
6373     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6374
6375     query = "CREATE TABLE `Table2` ( `A` CHAR(72) NOT NULL PRIMARY KEY A )";
6376     r = run_query(hdb, 0, query);
6377     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6378
6379     query = "CREATE TABLE `Table3` ( A CHAR(72) NOT NULL PRIMARY KEY A )";
6380     r = run_query(hdb, 0, query);
6381     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6382
6383     query = "SELECT * FROM `_Tables`";
6384     r = MsiDatabaseOpenView(hdb, query, &hview);
6385     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6386     r = MsiViewExecute(hview, 0);
6387     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6388
6389     r = MsiViewFetch(hview, &hrec);
6390     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6391
6392     size = MAX_PATH;
6393     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6394     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6395     ok(!lstrcmpA(buf, "Table"), "Expected \"Table\", got \"%s\"\n", buf);
6396
6397     MsiCloseHandle(hrec);
6398
6399     r = MsiViewFetch(hview, &hrec);
6400     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6401
6402     size = MAX_PATH;
6403     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6404     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6405     ok(!lstrcmpA(buf, "Table2"), "Expected \"Table2\", got \"%s\"\n", buf);
6406
6407     MsiCloseHandle(hrec);
6408
6409     r = MsiViewFetch(hview, &hrec);
6410     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6411
6412     size = MAX_PATH;
6413     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6414     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6415     ok(!lstrcmpA(buf, "Table3"), "Expected \"Table3\", got \"%s\"\n", buf);
6416
6417     MsiCloseHandle(hrec);
6418
6419     r = MsiViewFetch(hview, &hrec);
6420     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6421
6422     MsiViewClose(hview);
6423     MsiCloseHandle(hview);
6424
6425     query = "SELECT * FROM `_Columns`";
6426     r = MsiDatabaseOpenView(hdb, query, &hview);
6427     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6428     r = MsiViewExecute(hview, 0);
6429     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6430
6431     r = MsiViewFetch(hview, &hrec);
6432     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6433
6434     size = MAX_PATH;
6435     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6436     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6437     ok(!lstrcmpA(buf, "Table"), "Expected \"Table\", got \"%s\"\n", buf);
6438
6439     r = MsiRecordGetInteger(hrec, 2);
6440     ok(r == 1, "Expected 1, got %d\n", r);
6441
6442     size = MAX_PATH;
6443     r = MsiRecordGetStringA(hrec, 3, buf, &size);
6444     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6445     ok(!lstrcmpA(buf, "A"), "Expected \"A\", got \"%s\"\n", buf);
6446
6447     MsiCloseHandle(hrec);
6448
6449     r = MsiViewFetch(hview, &hrec);
6450     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6451
6452     size = MAX_PATH;
6453     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6454     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6455     ok(!lstrcmpA(buf, "Table2"), "Expected \"Table2\", got \"%s\"\n", buf);
6456
6457     r = MsiRecordGetInteger(hrec, 2);
6458     ok(r == 1, "Expected 1, got %d\n", r);
6459
6460     size = MAX_PATH;
6461     r = MsiRecordGetStringA(hrec, 3, buf, &size);
6462     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6463     ok(!lstrcmpA(buf, "A"), "Expected \"A\", got \"%s\"\n", buf);
6464
6465     MsiCloseHandle(hrec);
6466
6467     r = MsiViewFetch(hview, &hrec);
6468     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6469
6470     size = MAX_PATH;
6471     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6472     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6473     ok(!lstrcmpA(buf, "Table3"), "Expected \"Table3\", got \"%s\"\n", buf);
6474
6475     r = MsiRecordGetInteger(hrec, 2);
6476     ok(r == 1, "Expected 1, got %d\n", r);
6477
6478     size = MAX_PATH;
6479     r = MsiRecordGetStringA(hrec, 3, buf, &size);
6480     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6481     ok(!lstrcmpA(buf, "A"), "Expected \"A\", got \"%s\"\n", buf);
6482
6483     MsiCloseHandle(hrec);
6484
6485     r = MsiViewFetch(hview, &hrec);
6486     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6487
6488     MsiViewClose(hview);
6489     MsiCloseHandle(hview);
6490
6491     query = "INSERT INTO Table ( `A` ) VALUES ( 'hi' )";
6492     r = run_query(hdb, 0, query);
6493     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6494
6495     query = "INSERT INTO `Table` ( A ) VALUES ( 'hi' )";
6496     r = run_query(hdb, 0, query);
6497     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6498
6499     query = "INSERT INTO `Table` ( `A` ) VALUES ( hi )";
6500     r = run_query(hdb, 0, query);
6501     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6502
6503     query = "SELECT * FROM Table WHERE `A` = 'hi'";
6504     r = run_query(hdb, 0, query);
6505     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6506
6507     query = "SELECT * FROM `Table` WHERE `A` = hi";
6508     r = run_query(hdb, 0, query);
6509     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6510
6511     query = "SELECT * FROM Table";
6512     r = run_query(hdb, 0, query);
6513     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6514
6515     query = "SELECT * FROM Table2";
6516     r = MsiDatabaseOpenView(hdb, query, &hview);
6517     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6518     r = MsiViewExecute(hview, 0);
6519     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6520
6521     r = MsiViewFetch(hview, &hrec);
6522     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6523
6524     MsiViewClose(hview);
6525     MsiCloseHandle(hview);
6526
6527     query = "SELECT * FROM `Table` WHERE A = 'hi'";
6528     r = MsiDatabaseOpenView(hdb, query, &hview);
6529     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6530     r = MsiViewExecute(hview, 0);
6531     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6532
6533     r = MsiViewFetch(hview, &hrec);
6534     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6535
6536     size = MAX_PATH;
6537     r = MsiRecordGetStringA(hrec, 1, buf, &size);
6538     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6539     ok(!lstrcmpA(buf, "hi"), "Expected \"hi\", got \"%s\"\n", buf);
6540
6541     MsiCloseHandle(hrec);
6542
6543     r = MsiViewFetch(hview, &hrec);
6544     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6545
6546     MsiViewClose(hview);
6547     MsiCloseHandle(hview);
6548     MsiCloseHandle(hdb);
6549     DeleteFileA(msifile);
6550 }
6551
6552 static void read_file_data(LPCSTR filename, LPSTR buffer)
6553 {
6554     HANDLE file;
6555     DWORD read;
6556
6557     file = CreateFileA( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
6558     ZeroMemory(buffer, MAX_PATH);
6559     ReadFile(file, buffer, MAX_PATH, &read, NULL);
6560     CloseHandle(file);
6561 }
6562
6563 static void test_forcecodepage(void)
6564 {
6565     MSIHANDLE hdb;
6566     const char *query;
6567     char buffer[MAX_PATH];
6568     UINT r;
6569
6570     DeleteFile(msifile);
6571
6572     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
6573     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6574
6575     query = "SELECT * FROM `_ForceCodepage`";
6576     r = run_query(hdb, 0, query);
6577     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6578
6579     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6580     r = run_query(hdb, 0, query);
6581     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6582
6583     query = "SELECT * FROM `_ForceCodepage`";
6584     r = run_query(hdb, 0, query);
6585     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6586
6587     r = MsiDatabaseCommit(hdb);
6588     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6589
6590     query = "SELECT * FROM `_ForceCodepage`";
6591     r = run_query(hdb, 0, query);
6592     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6593
6594     MsiCloseHandle(hdb);
6595
6596     r = MsiOpenDatabase(msifile, MSIDBOPEN_DIRECT, &hdb);
6597     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6598
6599     query = "SELECT * FROM `_ForceCodepage`";
6600     r = run_query(hdb, 0, query);
6601     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6602
6603     r = MsiDatabaseExport(hdb, "_ForceCodepage", CURR_DIR, "forcecodepage.idt");
6604     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6605
6606     read_file_data("forcecodepage.idt", buffer);
6607     ok(!lstrcmpA(buffer, "\r\n\r\n0\t_ForceCodepage\r\n"),
6608        "Expected \"\r\n\r\n0\t_ForceCodepage\r\n\", got \"%s\"", buffer);
6609
6610     MsiCloseHandle(hdb);
6611     DeleteFileA(msifile);
6612     DeleteFileA("forcecodepage.idt");
6613 }
6614
6615 static void test_viewmodify_refresh(void)
6616 {
6617     MSIHANDLE hdb, hview, hrec;
6618     const char *query;
6619     char buffer[MAX_PATH];
6620     UINT r;
6621     DWORD size;
6622
6623     DeleteFile(msifile);
6624
6625     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
6626     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6627
6628     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL, `B` INT PRIMARY KEY `A` )";
6629     r = run_query(hdb, 0, query);
6630     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6631
6632     query = "INSERT INTO `Table` ( `A`, `B` ) VALUES ( 'hi', 1 )";
6633     r = run_query(hdb, 0, query);
6634     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6635
6636     query = "SELECT * FROM `Table`";
6637     r = MsiDatabaseOpenView(hdb, query, &hview);
6638     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6639     r = MsiViewExecute(hview, 0);
6640     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6641
6642     r = MsiViewFetch(hview, &hrec);
6643     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6644
6645     query = "UPDATE `Table` SET `B` = 2 WHERE `A` = 'hi'";
6646     r = run_query(hdb, 0, query);
6647     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6648
6649     r = MsiViewModify(hview, MSIMODIFY_REFRESH, hrec);
6650     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6651
6652     size = MAX_PATH;
6653     r = MsiRecordGetStringA(hrec, 1, buffer, &size);
6654     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6655     ok(!lstrcmpA(buffer, "hi"), "Expected \"hi\", got \"%s\"\n", buffer);
6656     ok(size == 2, "Expected 2, got %d\n", size);
6657
6658     r = MsiRecordGetInteger(hrec, 2);
6659     ok(r == 2, "Expected 2, got %d\n", r);
6660
6661     MsiCloseHandle(hrec);
6662     MsiViewClose(hview);
6663     MsiCloseHandle(hview);
6664
6665     query = "INSERT INTO `Table` ( `A`, `B` ) VALUES ( 'hello', 3 )";
6666     r = run_query(hdb, 0, query);
6667     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6668
6669     query = "SELECT * FROM `Table` WHERE `B` = 3";
6670     r = MsiDatabaseOpenView(hdb, query, &hview);
6671     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6672     r = MsiViewExecute(hview, 0);
6673     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6674
6675     r = MsiViewFetch(hview, &hrec);
6676     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6677
6678     query = "UPDATE `Table` SET `B` = 2 WHERE `A` = 'hello'";
6679     r = run_query(hdb, 0, query);
6680     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6681
6682     query = "INSERT INTO `Table` ( `A`, `B` ) VALUES ( 'hithere', 3 )";
6683     r = run_query(hdb, 0, query);
6684     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6685
6686     r = MsiViewModify(hview, MSIMODIFY_REFRESH, hrec);
6687     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6688
6689     size = MAX_PATH;
6690     r = MsiRecordGetStringA(hrec, 1, buffer, &size);
6691     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6692     ok(!lstrcmpA(buffer, "hello"), "Expected \"hello\", got \"%s\"\n", buffer);
6693     ok(size == 5, "Expected 5, got %d\n", size);
6694
6695     r = MsiRecordGetInteger(hrec, 2);
6696     ok(r == 2, "Expected 2, got %d\n", r);
6697
6698     MsiCloseHandle(hrec);
6699     MsiViewClose(hview);
6700     MsiCloseHandle(hview);
6701     MsiCloseHandle(hdb);
6702     DeleteFileA(msifile);
6703 }
6704
6705 static void test_where_viewmodify(void)
6706 {
6707     MSIHANDLE hdb, hview, hrec;
6708     const char *query;
6709     UINT r;
6710
6711     DeleteFile(msifile);
6712
6713     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
6714     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6715
6716     query = "CREATE TABLE `Table` ( `A` INT, `B` INT PRIMARY KEY `A` )";
6717     r = run_query(hdb, 0, query);
6718     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6719
6720     query = "INSERT INTO `Table` ( `A`, `B` ) VALUES ( 1, 2 )";
6721     r = run_query(hdb, 0, query);
6722     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6723
6724     query = "INSERT INTO `Table` ( `A`, `B` ) VALUES ( 3, 4 )";
6725     r = run_query(hdb, 0, query);
6726     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6727
6728     query = "INSERT INTO `Table` ( `A`, `B` ) VALUES ( 5, 6 )";
6729     r = run_query(hdb, 0, query);
6730     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6731
6732     /* `B` = 3 doesn't match, but the view shouldn't be executed */
6733     query = "SELECT * FROM `Table` WHERE `B` = 3";
6734     r = MsiDatabaseOpenView(hdb, query, &hview);
6735     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6736
6737     hrec = MsiCreateRecord(2);
6738     MsiRecordSetInteger(hrec, 1, 7);
6739     MsiRecordSetInteger(hrec, 2, 8);
6740
6741     r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec);
6742     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6743
6744     MsiCloseHandle(hrec);
6745     MsiViewClose(hview);
6746     MsiCloseHandle(hview);
6747
6748     query = "SELECT * FROM `Table` WHERE `A` = 7";
6749     r = MsiDatabaseOpenView(hdb, query, &hview);
6750     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6751     r = MsiViewExecute(hview, 0);
6752     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6753
6754     r = MsiViewFetch(hview, &hrec);
6755     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6756
6757     r = MsiRecordGetInteger(hrec, 1);
6758     ok(r == 7, "Expected 7, got %d\n", r);
6759
6760     r = MsiRecordGetInteger(hrec, 2);
6761     ok(r == 8, "Expected 8, got %d\n", r);
6762
6763     MsiRecordSetInteger(hrec, 2, 9);
6764
6765     r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
6766     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6767
6768     MsiCloseHandle(hrec);
6769     MsiViewClose(hview);
6770     MsiCloseHandle(hview);
6771
6772     query = "SELECT * FROM `Table` WHERE `A` = 7";
6773     r = MsiDatabaseOpenView(hdb, query, &hview);
6774     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6775     r = MsiViewExecute(hview, 0);
6776     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6777
6778     r = MsiViewFetch(hview, &hrec);
6779     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6780
6781     r = MsiRecordGetInteger(hrec, 1);
6782     ok(r == 7, "Expected 7, got %d\n", r);
6783
6784     r = MsiRecordGetInteger(hrec, 2);
6785     ok(r == 9, "Expected 9, got %d\n", r);
6786
6787     query = "UPDATE `Table` SET `B` = 10 WHERE `A` = 7";
6788     r = run_query(hdb, 0, query);
6789     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6790
6791     r = MsiViewModify(hview, MSIMODIFY_REFRESH, hrec);
6792     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6793
6794     r = MsiRecordGetInteger(hrec, 1);
6795     ok(r == 7, "Expected 7, got %d\n", r);
6796
6797     r = MsiRecordGetInteger(hrec, 2);
6798     ok(r == 10, "Expected 10, got %d\n", r);
6799
6800     MsiCloseHandle(hrec);
6801     MsiViewClose(hview);
6802     MsiCloseHandle(hview);
6803     MsiCloseHandle(hdb);
6804 }
6805
6806 static BOOL create_storage(LPCSTR name)
6807 {
6808     WCHAR nameW[MAX_PATH];
6809     IStorage *stg;
6810     IStream *stm;
6811     HRESULT hr;
6812     DWORD count;
6813     BOOL res = FALSE;
6814
6815     MultiByteToWideChar(CP_ACP, 0, name, -1, nameW, MAX_PATH);
6816     hr = StgCreateDocfile(nameW, STGM_CREATE | STGM_READWRITE |
6817                           STGM_DIRECT | STGM_SHARE_EXCLUSIVE, 0, &stg);
6818     if (FAILED(hr))
6819         return FALSE;
6820
6821     hr = IStorage_CreateStream(stg, nameW, STGM_WRITE | STGM_SHARE_EXCLUSIVE,
6822                                0, 0, &stm);
6823     if (FAILED(hr))
6824         goto done;
6825
6826     hr = IStream_Write(stm, "stgdata", 8, &count);
6827     if (SUCCEEDED(hr))
6828         res = TRUE;
6829
6830 done:
6831     IStream_Release(stm);
6832     IStorage_Release(stg);
6833
6834     return res;
6835 }
6836
6837 static void test_storages_table(void)
6838 {
6839     MSIHANDLE hdb, hview, hrec;
6840     IStorage *stg, *inner;
6841     IStream *stm;
6842     char file[MAX_PATH];
6843     char buf[MAX_PATH];
6844     WCHAR name[MAX_PATH];
6845     LPCSTR query;
6846     HRESULT hr;
6847     DWORD size;
6848     UINT r;
6849
6850     hdb = create_db();
6851     ok(hdb, "failed to create db\n");
6852
6853     r = MsiDatabaseCommit(hdb);
6854     ok(r == ERROR_SUCCESS , "Failed to commit database\n");
6855
6856     MsiCloseHandle(hdb);
6857
6858     r = MsiOpenDatabase(msifile, MSIDBOPEN_TRANSACT, &hdb);
6859     ok(r == ERROR_SUCCESS , "Failed to open database\n");
6860
6861     /* check the column types */
6862     hrec = get_column_info(hdb, "SELECT * FROM `_Storages`", MSICOLINFO_TYPES);
6863     ok(hrec, "failed to get column info hrecord\n");
6864     ok(check_record(hrec, 1, "s62"), "wrong hrecord type\n");
6865     ok(check_record(hrec, 2, "V0"), "wrong hrecord type\n");
6866
6867     MsiCloseHandle(hrec);
6868
6869     /* now try the names */
6870     hrec = get_column_info(hdb, "SELECT * FROM `_Storages`", MSICOLINFO_NAMES);
6871     ok(hrec, "failed to get column info hrecord\n");
6872     ok(check_record(hrec, 1, "Name"), "wrong hrecord type\n");
6873     ok(check_record(hrec, 2, "Data"), "wrong hrecord type\n");
6874
6875     MsiCloseHandle(hrec);
6876
6877     create_storage("storage.bin");
6878
6879     hrec = MsiCreateRecord(2);
6880     MsiRecordSetString(hrec, 1, "stgname");
6881
6882     r = MsiRecordSetStream(hrec, 2, "storage.bin");
6883     ok(r == ERROR_SUCCESS, "Failed to add stream data to the hrecord: %d\n", r);
6884
6885     DeleteFileA("storage.bin");
6886
6887     query = "INSERT INTO `_Storages` (`Name`, `Data`) VALUES (?, ?)";
6888     r = MsiDatabaseOpenView(hdb, query, &hview);
6889     ok(r == ERROR_SUCCESS, "Failed to open database hview: %d\n", r);
6890
6891     r = MsiViewExecute(hview, hrec);
6892     ok(r == ERROR_SUCCESS, "Failed to execute hview: %d\n", r);
6893
6894     MsiCloseHandle(hrec);
6895     MsiViewClose(hview);
6896     MsiCloseHandle(hview);
6897
6898     query = "SELECT `Name`, `Data` FROM `_Storages`";
6899     r = MsiDatabaseOpenView(hdb, query, &hview);
6900     ok(r == ERROR_SUCCESS, "Failed to open database hview: %d\n", r);
6901
6902     r = MsiViewExecute(hview, 0);
6903     ok(r == ERROR_SUCCESS, "Failed to execute hview: %d\n", r);
6904
6905     r = MsiViewFetch(hview, &hrec);
6906     ok(r == ERROR_SUCCESS, "Failed to fetch hrecord: %d\n", r);
6907
6908     size = MAX_PATH;
6909     r = MsiRecordGetString(hrec, 1, file, &size);
6910     ok(r == ERROR_SUCCESS, "Failed to get string: %d\n", r);
6911     ok(!lstrcmp(file, "stgname"), "Expected \"stgname\", got \"%s\"\n", file);
6912
6913     size = MAX_PATH;
6914     lstrcpyA(buf, "apple");
6915     r = MsiRecordReadStream(hrec, 2, buf, &size);
6916     ok(r == ERROR_INVALID_DATA, "Expected ERROR_INVALID_DATA, got %d\n", r);
6917     ok(!lstrcmp(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf);
6918     ok(size == 0, "Expected 0, got %d\n", size);
6919
6920     MsiCloseHandle(hrec);
6921
6922     r = MsiViewFetch(hview, &hrec);
6923     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6924
6925     MsiViewClose(hview);
6926     MsiCloseHandle(hview);
6927
6928     MsiDatabaseCommit(hdb);
6929     MsiCloseHandle(hdb);
6930
6931     MultiByteToWideChar(CP_ACP, 0, msifile, -1, name, MAX_PATH);
6932     hr = StgOpenStorage(name, NULL, STGM_DIRECT | STGM_READ |
6933                         STGM_SHARE_DENY_WRITE, NULL, 0, &stg);
6934     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
6935     ok(stg != NULL, "Expected non-NULL storage\n");
6936
6937     MultiByteToWideChar(CP_ACP, 0, "stgname", -1, name, MAX_PATH);
6938     hr = IStorage_OpenStorage(stg, name, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE,
6939                               NULL, 0, &inner);
6940     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
6941     ok(inner != NULL, "Expected non-NULL storage\n");
6942
6943     MultiByteToWideChar(CP_ACP, 0, "storage.bin", -1, name, MAX_PATH);
6944     hr = IStorage_OpenStream(inner, name, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm);
6945     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
6946     ok(stm != NULL, "Expected non-NULL stream\n");
6947
6948     hr = IStream_Read(stm, buf, MAX_PATH, &size);
6949     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
6950     ok(size == 8, "Expected 8, got %d\n", size);
6951     ok(!lstrcmpA(buf, "stgdata"), "Expected \"stgdata\", got \"%s\"\n", buf);
6952
6953     IStream_Release(stm);
6954     IStorage_Release(inner);
6955
6956     IStorage_Release(stg);
6957     DeleteFileA(msifile);
6958 }
6959
6960 static void test_dbtopackage(void)
6961 {
6962     MSIHANDLE hdb, hpkg;
6963     CHAR package[10];
6964     CHAR buf[MAX_PATH];
6965     DWORD size;
6966     UINT r;
6967
6968     /* create an empty database, transact mode */
6969     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
6970     ok(r == ERROR_SUCCESS, "Failed to create database\n");
6971
6972     set_summary_info(hdb);
6973
6974     r = create_directory_table(hdb);
6975     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6976
6977     r = create_custom_action_table(hdb);
6978     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6979
6980     r = add_custom_action_entry(hdb, "'SetProp', 51, 'MYPROP', 'grape'");
6981     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6982
6983     sprintf(package, "#%i", hdb);
6984     r = MsiOpenPackage(package, &hpkg);
6985     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6986
6987     /* property is not set yet */
6988     size = MAX_PATH;
6989     lstrcpyA(buf, "kiwi");
6990     r = MsiGetProperty(hpkg, "MYPROP", buf, &size);
6991     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6992     ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf);
6993     ok(size == 0, "Expected 0, got %d\n", size);
6994
6995     /* run the custom action to set the property */
6996     r = MsiDoAction(hpkg, "SetProp");
6997     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6998
6999     /* property is now set */
7000     size = MAX_PATH;
7001     lstrcpyA(buf, "kiwi");
7002     r = MsiGetProperty(hpkg, "MYPROP", buf, &size);
7003     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7004     ok(!lstrcmpA(buf, "grape"), "Expected \"grape\", got \"%s\"\n", buf);
7005     ok(size == 5, "Expected 5, got %d\n", size);
7006
7007     MsiCloseHandle(hpkg);
7008
7009     /* reset the package */
7010     r = MsiOpenPackage(package, &hpkg);
7011     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7012
7013     /* property is not set anymore */
7014     size = MAX_PATH;
7015     lstrcpyA(buf, "kiwi");
7016     r = MsiGetProperty(hpkg, "MYPROP", buf, &size);
7017     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7018     todo_wine
7019     {
7020         ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf);
7021         ok(size == 0, "Expected 0, got %d\n", size);
7022     }
7023
7024     MsiCloseHandle(hdb);
7025     MsiCloseHandle(hpkg);
7026
7027     /* create an empty database, direct mode */
7028     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATEDIRECT, &hdb);
7029     ok(r == ERROR_SUCCESS, "Failed to create database\n");
7030
7031     set_summary_info(hdb);
7032
7033     r = create_directory_table(hdb);
7034     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7035
7036     r = create_custom_action_table(hdb);
7037     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7038
7039     r = add_custom_action_entry(hdb, "'SetProp', 51, 'MYPROP', 'grape'");
7040     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7041
7042     sprintf(package, "#%i", hdb);
7043     r = MsiOpenPackage(package, &hpkg);
7044     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7045
7046     /* property is not set yet */
7047     size = MAX_PATH;
7048     lstrcpyA(buf, "kiwi");
7049     r = MsiGetProperty(hpkg, "MYPROP", buf, &size);
7050     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7051     ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf);
7052     ok(size == 0, "Expected 0, got %d\n", size);
7053
7054     /* run the custom action to set the property */
7055     r = MsiDoAction(hpkg, "SetProp");
7056     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7057
7058     /* property is now set */
7059     size = MAX_PATH;
7060     lstrcpyA(buf, "kiwi");
7061     r = MsiGetProperty(hpkg, "MYPROP", buf, &size);
7062     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7063     ok(!lstrcmpA(buf, "grape"), "Expected \"grape\", got \"%s\"\n", buf);
7064     ok(size == 5, "Expected 5, got %d\n", size);
7065
7066     MsiCloseHandle(hpkg);
7067
7068     /* reset the package */
7069     r = MsiOpenPackage(package, &hpkg);
7070     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7071
7072     /* property is not set anymore */
7073     size = MAX_PATH;
7074     lstrcpyA(buf, "kiwi");
7075     r = MsiGetProperty(hpkg, "MYPROP", buf, &size);
7076     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7077     todo_wine
7078     {
7079         ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf);
7080         ok(size == 0, "Expected 0, got %d\n", size);
7081     }
7082
7083     MsiCloseHandle(hdb);
7084     MsiCloseHandle(hpkg);
7085     DeleteFileA(msifile);
7086 }
7087
7088 static void test_droptable(void)
7089 {
7090     MSIHANDLE hdb, hview, hrec;
7091     CHAR buf[MAX_PATH];
7092     LPCSTR query;
7093     DWORD size;
7094     UINT r;
7095
7096     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
7097     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7098
7099     query = "CREATE TABLE `One` ( `A` INT PRIMARY KEY `A` )";
7100     r = run_query(hdb, 0, query);
7101     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7102
7103     query = "SELECT * FROM `One`";
7104     r = do_query(hdb, query, &hrec);
7105     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7106
7107     query = "SELECT * FROM `_Tables` WHERE `Name` = 'One'";
7108     r = MsiDatabaseOpenViewA(hdb, query, &hview);
7109     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7110     r = MsiViewExecute(hview, 0);
7111     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7112
7113     r = MsiViewFetch(hview, &hrec);
7114     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7115
7116     size = MAX_PATH;
7117     r = MsiRecordGetStringA(hrec, 1, buf, &size);
7118     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7119     ok(!lstrcmpA(buf, "One"), "Expected \"One\", got \"%s\"\n", buf);
7120
7121     MsiCloseHandle(hrec);
7122     MsiViewClose(hview);
7123     MsiCloseHandle(hview);
7124
7125     query = "SELECT * FROM `_Columns` WHERE `Table` = 'One'";
7126     r = MsiDatabaseOpenViewA(hdb, query, &hview);
7127     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7128     r = MsiViewExecute(hview, 0);
7129     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7130
7131     r = MsiViewFetch(hview, &hrec);
7132     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7133
7134     size = MAX_PATH;
7135     r = MsiRecordGetStringA(hrec, 1, buf, &size);
7136     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7137     ok(!lstrcmpA(buf, "One"), "Expected \"One\", got \"%s\"\n", buf);
7138
7139     r = MsiRecordGetInteger(hrec, 2);
7140     ok(r == 1, "Expected 1, got %d\n", r);
7141
7142     size = MAX_PATH;
7143     r = MsiRecordGetStringA(hrec, 3, buf, &size);
7144     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7145     ok(!lstrcmpA(buf, "A"), "Expected \"A\", got \"%s\"\n", buf);
7146
7147     MsiCloseHandle(hrec);
7148
7149     r = MsiViewFetch(hview, &hrec);
7150     ok(r == ERROR_NO_MORE_ITEMS,
7151        "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7152
7153     MsiViewClose(hview);
7154     MsiCloseHandle(hview);
7155
7156     query = "DROP `One`";
7157     r = run_query(hdb, 0, query);
7158     ok(r == ERROR_BAD_QUERY_SYNTAX,
7159        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7160
7161     query = "DROP TABLE";
7162     r = run_query(hdb, 0, query);
7163     ok(r == ERROR_BAD_QUERY_SYNTAX,
7164        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7165
7166     query = "DROP TABLE `One`";
7167     hview = 0;
7168     r = MsiDatabaseOpenViewA(hdb, query, &hview);
7169     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7170     r = MsiViewExecute(hview, 0);
7171     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7172
7173     r = MsiViewFetch(hview, &hrec);
7174     ok(r == ERROR_FUNCTION_FAILED,
7175        "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
7176
7177     MsiViewClose(hview);
7178     MsiCloseHandle(hview);
7179
7180     query = "SELECT * FROM `IDontExist`";
7181     r = do_query(hdb, query, &hrec);
7182     ok(r == ERROR_BAD_QUERY_SYNTAX,
7183        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7184
7185     query = "SELECT * FROM `One`";
7186     r = do_query(hdb, query, &hrec);
7187     ok(r == ERROR_BAD_QUERY_SYNTAX,
7188        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7189
7190     query = "CREATE TABLE `One` ( `A` INT PRIMARY KEY `A` )";
7191     r = run_query(hdb, 0, query);
7192     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7193
7194     query = "DROP TABLE One";
7195     r = run_query(hdb, 0, query);
7196     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7197
7198     query = "SELECT * FROM `One`";
7199     r = do_query(hdb, query, &hrec);
7200     ok(r == ERROR_BAD_QUERY_SYNTAX,
7201        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7202
7203     query = "SELECT * FROM `_Tables` WHERE `Name` = 'One'";
7204     r = do_query(hdb, query, &hrec);
7205     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7206
7207     query = "SELECT * FROM `_Columns` WHERE `Table` = 'One'";
7208     r = do_query(hdb, query, &hrec);
7209     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7210
7211     query = "CREATE TABLE `One` ( `B` INT, `C` INT PRIMARY KEY `B` )";
7212     r = run_query(hdb, 0, query);
7213     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7214
7215     query = "SELECT * FROM `One`";
7216     r = do_query(hdb, query, &hrec);
7217     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7218
7219     query = "SELECT * FROM `_Tables` WHERE `Name` = 'One'";
7220     r = MsiDatabaseOpenViewA(hdb, query, &hview);
7221     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7222     r = MsiViewExecute(hview, 0);
7223     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7224
7225     r = MsiViewFetch(hview, &hrec);
7226     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7227
7228     size = MAX_PATH;
7229     r = MsiRecordGetStringA(hrec, 1, buf, &size);
7230     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7231     ok(!lstrcmpA(buf, "One"), "Expected \"One\", got \"%s\"\n", buf);
7232
7233     MsiCloseHandle(hrec);
7234     MsiViewClose(hview);
7235     MsiCloseHandle(hview);
7236
7237     query = "SELECT * FROM `_Columns` WHERE `Table` = 'One'";
7238     r = MsiDatabaseOpenViewA(hdb, query, &hview);
7239     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7240     r = MsiViewExecute(hview, 0);
7241     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7242
7243     r = MsiViewFetch(hview, &hrec);
7244     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7245
7246     size = MAX_PATH;
7247     r = MsiRecordGetStringA(hrec, 1, buf, &size);
7248     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7249     ok(!lstrcmpA(buf, "One"), "Expected \"One\", got \"%s\"\n", buf);
7250
7251     r = MsiRecordGetInteger(hrec, 2);
7252     ok(r == 1, "Expected 1, got %d\n", r);
7253
7254     size = MAX_PATH;
7255     r = MsiRecordGetStringA(hrec, 3, buf, &size);
7256     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7257     ok(!lstrcmpA(buf, "B"), "Expected \"B\", got \"%s\"\n", buf);
7258
7259     MsiCloseHandle(hrec);
7260
7261     r = MsiViewFetch(hview, &hrec);
7262     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7263
7264     size = MAX_PATH;
7265     r = MsiRecordGetStringA(hrec, 1, buf, &size);
7266     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7267     ok(!lstrcmpA(buf, "One"), "Expected \"One\", got \"%s\"\n", buf);
7268
7269     r = MsiRecordGetInteger(hrec, 2);
7270     ok(r == 2, "Expected 2, got %d\n", r);
7271
7272     size = MAX_PATH;
7273     r = MsiRecordGetStringA(hrec, 3, buf, &size);
7274     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7275     ok(!lstrcmpA(buf, "C"), "Expected \"C\", got \"%s\"\n", buf);
7276
7277     MsiCloseHandle(hrec);
7278
7279     r = MsiViewFetch(hview, &hrec);
7280     ok(r == ERROR_NO_MORE_ITEMS,
7281        "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7282
7283     MsiViewClose(hview);
7284     MsiCloseHandle(hview);
7285
7286     query = "DROP TABLE One";
7287     r = run_query(hdb, 0, query);
7288     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7289
7290     query = "SELECT * FROM `One`";
7291     r = do_query(hdb, query, &hrec);
7292     ok(r == ERROR_BAD_QUERY_SYNTAX,
7293        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7294
7295     query = "SELECT * FROM `_Tables` WHERE `Name` = 'One'";
7296     r = do_query(hdb, query, &hrec);
7297     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7298
7299     query = "SELECT * FROM `_Columns` WHERE `Table` = 'One'";
7300     r = do_query(hdb, query, &hrec);
7301     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7302
7303     MsiCloseHandle(hdb);
7304     DeleteFileA(msifile);
7305 }
7306
7307 static void test_dbmerge(void)
7308 {
7309     MSIHANDLE hdb, href, hview, hrec;
7310     CHAR buf[MAX_PATH];
7311     LPCSTR query;
7312     DWORD size;
7313     UINT r;
7314
7315     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
7316     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7317
7318     r = MsiOpenDatabase("refdb.msi", MSIDBOPEN_CREATE, &href);
7319     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7320
7321     /* hDatabase is invalid */
7322     r = MsiDatabaseMergeA(0, href, "MergeErrors");
7323     ok(r == ERROR_INVALID_HANDLE,
7324        "Expected ERROR_INVALID_HANDLE, got %d\n", r);
7325
7326     /* hDatabaseMerge is invalid */
7327     r = MsiDatabaseMergeA(hdb, 0, "MergeErrors");
7328     ok(r == ERROR_INVALID_HANDLE,
7329        "Expected ERROR_INVALID_HANDLE, got %d\n", r);
7330
7331     /* szTableName is NULL */
7332     r = MsiDatabaseMergeA(hdb, href, NULL);
7333     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7334
7335     /* szTableName is empty */
7336     r = MsiDatabaseMergeA(hdb, href, "");
7337     ok(r == ERROR_INVALID_TABLE, "Expected ERROR_INVALID_TABLE, got %d\n", r);
7338
7339     /* both DBs empty, szTableName is valid */
7340     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7341     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7342
7343     query = "CREATE TABLE `One` ( `A` INT PRIMARY KEY `A` )";
7344     r = run_query(hdb, 0, query);
7345     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7346
7347     query = "CREATE TABLE `One` ( `A` CHAR(72) PRIMARY KEY `A` )";
7348     r = run_query(href, 0, query);
7349     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7350
7351     /* column types don't match */
7352     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7353     ok(r == ERROR_DATATYPE_MISMATCH,
7354        "Expected ERROR_DATATYPE_MISMATCH, got %d\n", r);
7355
7356     /* nothing in MergeErrors */
7357     query = "SELECT * FROM `MergeErrors`";
7358     r = do_query(hdb, query, &hrec);
7359     ok(r == ERROR_BAD_QUERY_SYNTAX,
7360        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7361
7362     query = "DROP TABLE `One`";
7363     r = run_query(hdb, 0, query);
7364     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7365
7366     query = "DROP TABLE `One`";
7367     r = run_query(href, 0, query);
7368     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7369
7370     query = "CREATE TABLE `One` ( "
7371         "`A` CHAR(72), "
7372         "`B` CHAR(56), "
7373         "`C` CHAR(64) LOCALIZABLE, "
7374         "`D` LONGCHAR, "
7375         "`E` CHAR(72) NOT NULL, "
7376         "`F` CHAR(56) NOT NULL, "
7377         "`G` CHAR(64) NOT NULL LOCALIZABLE, "
7378         "`H` LONGCHAR NOT NULL "
7379         "PRIMARY KEY `A` )";
7380     r = run_query(hdb, 0, query);
7381     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7382
7383     query = "CREATE TABLE `One` ( "
7384         "`A` CHAR(64), "
7385         "`B` CHAR(64), "
7386         "`C` CHAR(64), "
7387         "`D` CHAR(64), "
7388         "`E` CHAR(64) NOT NULL, "
7389         "`F` CHAR(64) NOT NULL, "
7390         "`G` CHAR(64) NOT NULL, "
7391         "`H` CHAR(64) NOT NULL "
7392         "PRIMARY KEY `A` )";
7393     r = run_query(href, 0, query);
7394     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7395
7396     /* column sting types don't match exactly */
7397     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7398     ok(r == ERROR_SUCCESS,
7399        "Expected ERROR_SUCCESS, got %d\n", r);
7400
7401     /* nothing in MergeErrors */
7402     query = "SELECT * FROM `MergeErrors`";
7403     r = do_query(hdb, query, &hrec);
7404     ok(r == ERROR_BAD_QUERY_SYNTAX,
7405        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7406
7407     query = "DROP TABLE `One`";
7408     r = run_query(hdb, 0, query);
7409     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7410
7411     query = "DROP TABLE `One`";
7412     r = run_query(href, 0, query);
7413     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7414
7415     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A` )";
7416     r = run_query(hdb, 0, query);
7417     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7418
7419     query = "CREATE TABLE `One` ( `A` INT, `C` INT PRIMARY KEY `A` )";
7420     r = run_query(href, 0, query);
7421     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7422
7423     /* column names don't match */
7424     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7425     ok(r == ERROR_DATATYPE_MISMATCH,
7426        "Expected ERROR_DATATYPE_MISMATCH, got %d\n", r);
7427
7428     /* nothing in MergeErrors */
7429     query = "SELECT * FROM `MergeErrors`";
7430     r = do_query(hdb, query, &hrec);
7431     ok(r == ERROR_BAD_QUERY_SYNTAX,
7432        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7433
7434     query = "DROP TABLE `One`";
7435     r = run_query(hdb, 0, query);
7436     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7437
7438     query = "DROP TABLE `One`";
7439     r = run_query(href, 0, query);
7440     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7441
7442     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A` )";
7443     r = run_query(hdb, 0, query);
7444     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7445
7446     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `B` )";
7447     r = run_query(href, 0, query);
7448     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7449
7450     /* primary keys don't match */
7451     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7452     ok(r == ERROR_DATATYPE_MISMATCH,
7453        "Expected ERROR_DATATYPE_MISMATCH, got %d\n", r);
7454
7455     /* nothing in MergeErrors */
7456     query = "SELECT * FROM `MergeErrors`";
7457     r = do_query(hdb, query, &hrec);
7458     ok(r == ERROR_BAD_QUERY_SYNTAX,
7459        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7460
7461     query = "DROP TABLE `One`";
7462     r = run_query(hdb, 0, query);
7463     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7464
7465     query = "DROP TABLE `One`";
7466     r = run_query(href, 0, query);
7467     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7468
7469     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A` )";
7470     r = run_query(hdb, 0, query);
7471     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7472
7473     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A`, `B` )";
7474     r = run_query(href, 0, query);
7475     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7476
7477     /* number of primary keys doesn't match */
7478     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7479     ok(r == ERROR_DATATYPE_MISMATCH,
7480        "Expected ERROR_DATATYPE_MISMATCH, got %d\n", r);
7481
7482     /* nothing in MergeErrors */
7483     query = "SELECT * FROM `MergeErrors`";
7484     r = do_query(hdb, query, &hrec);
7485     ok(r == ERROR_BAD_QUERY_SYNTAX,
7486        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7487
7488     query = "DROP TABLE `One`";
7489     r = run_query(hdb, 0, query);
7490     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7491
7492     query = "DROP TABLE `One`";
7493     r = run_query(href, 0, query);
7494     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7495
7496     query = "CREATE TABLE `One` ( `A` INT, `B` INT, `C` INT PRIMARY KEY `A` )";
7497     r = run_query(hdb, 0, query);
7498     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7499
7500     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A` )";
7501     r = run_query(href, 0, query);
7502     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7503
7504     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 1, 2 )";
7505     r = run_query(href, 0, query);
7506     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7507
7508     /* number of columns doesn't match */
7509     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7510     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7511
7512     query = "SELECT * FROM `One`";
7513     r = do_query(hdb, query, &hrec);
7514     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7515
7516     r = MsiRecordGetInteger(hrec, 1);
7517     ok(r == 1, "Expected 1, got %d\n", r);
7518
7519     r = MsiRecordGetInteger(hrec, 2);
7520     ok(r == 2, "Expected 2, got %d\n", r);
7521
7522     r = MsiRecordGetInteger(hrec, 3);
7523     ok(r == MSI_NULL_INTEGER, "Expected MSI_NULL_INTEGER, got %d\n", r);
7524
7525     MsiCloseHandle(hrec);
7526
7527     /* nothing in MergeErrors */
7528     query = "SELECT * FROM `MergeErrors`";
7529     r = do_query(hdb, query, &hrec);
7530     ok(r == ERROR_BAD_QUERY_SYNTAX,
7531        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7532
7533     query = "DROP TABLE `One`";
7534     r = run_query(hdb, 0, query);
7535     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7536
7537     query = "DROP TABLE `One`";
7538     r = run_query(href, 0, query);
7539     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7540
7541     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A` )";
7542     r = run_query(hdb, 0, query);
7543     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7544
7545     query = "CREATE TABLE `One` ( `A` INT, `B` INT, `C` INT PRIMARY KEY `A` )";
7546     r = run_query(href, 0, query);
7547     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7548
7549     query = "INSERT INTO `One` ( `A`, `B`, `C` ) VALUES ( 1, 2, 3 )";
7550     r = run_query(href, 0, query);
7551     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7552
7553     /* number of columns doesn't match */
7554     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7555     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7556
7557     query = "SELECT * FROM `One`";
7558     r = do_query(hdb, query, &hrec);
7559     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7560
7561     r = MsiRecordGetInteger(hrec, 1);
7562     ok(r == 1, "Expected 1, got %d\n", r);
7563
7564     r = MsiRecordGetInteger(hrec, 2);
7565     ok(r == 2, "Expected 2, got %d\n", r);
7566
7567     r = MsiRecordGetInteger(hrec, 3);
7568     ok(r == MSI_NULL_INTEGER, "Expected MSI_NULL_INTEGER, got %d\n", r);
7569
7570     MsiCloseHandle(hrec);
7571
7572     /* nothing in MergeErrors */
7573     query = "SELECT * FROM `MergeErrors`";
7574     r = do_query(hdb, query, &hrec);
7575     ok(r == ERROR_BAD_QUERY_SYNTAX,
7576        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7577
7578     query = "DROP TABLE `One`";
7579     r = run_query(hdb, 0, query);
7580     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7581
7582     query = "DROP TABLE `One`";
7583     r = run_query(href, 0, query);
7584     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7585
7586     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A` )";
7587     r = run_query(hdb, 0, query);
7588     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7589
7590     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 1, 1 )";
7591     r = run_query(hdb, 0, query);
7592     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7593
7594     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 2, 2 )";
7595     r = run_query(hdb, 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(href, 0, query);
7600     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7601
7602     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 1, 2 )";
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` ) VALUES ( 2, 3 )";
7607     r = run_query(href, 0, query);
7608     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7609
7610     /* primary keys match, rows do not */
7611     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7612     ok(r == ERROR_FUNCTION_FAILED,
7613        "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
7614
7615     /* nothing in MergeErrors */
7616     query = "SELECT * FROM `MergeErrors`";
7617     r = do_query(hdb, query, &hrec);
7618     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7619
7620     size = MAX_PATH;
7621     r = MsiRecordGetStringA(hrec, 1, buf, &size);
7622     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7623     ok(!lstrcmpA(buf, "One"), "Expected \"One\", got \"%s\"\n", buf);
7624
7625     r = MsiRecordGetInteger(hrec, 2);
7626     ok(r == 2, "Expected 2, got %d\n", r);
7627
7628     MsiCloseHandle(hrec);
7629
7630     r = MsiDatabaseOpenViewA(hdb, "SELECT * FROM `MergeErrors`", &hview);
7631     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7632
7633     r = MsiViewGetColumnInfo(hview, MSICOLINFO_NAMES, &hrec);
7634     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7635
7636     size = MAX_PATH;
7637     r = MsiRecordGetString(hrec, 1, buf, &size);
7638     ok(!lstrcmpA(buf, "Table"), "Expected \"Table\", got \"%s\"\n", buf);
7639
7640     size = MAX_PATH;
7641     r = MsiRecordGetString(hrec, 2, buf, &size);
7642     ok(!lstrcmpA(buf, "NumRowMergeConflicts"),
7643        "Expected \"NumRowMergeConflicts\", got \"%s\"\n", buf);
7644
7645     MsiCloseHandle(hrec);
7646
7647     r = MsiViewGetColumnInfo(hview, MSICOLINFO_TYPES, &hrec);
7648     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7649
7650     size = MAX_PATH;
7651     r = MsiRecordGetString(hrec, 1, buf, &size);
7652     ok(!lstrcmpA(buf, "s255"), "Expected \"s255\", got \"%s\"\n", buf);
7653
7654     size = MAX_PATH;
7655     r = MsiRecordGetString(hrec, 2, buf, &size);
7656     ok(!lstrcmpA(buf, "i2"), "Expected \"i2\", got \"%s\"\n", buf);
7657
7658     MsiCloseHandle(hrec);
7659     MsiViewClose(hview);
7660     MsiCloseHandle(hview);
7661
7662     query = "DROP TABLE `MergeErrors`";
7663     r = run_query(hdb, 0, query);
7664     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7665
7666     query = "DROP TABLE `One`";
7667     r = run_query(hdb, 0, query);
7668     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7669
7670     query = "DROP TABLE `One`";
7671     r = run_query(href, 0, query);
7672     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7673
7674     query = "CREATE TABLE `One` ( `A` INT, `B` CHAR(72) PRIMARY KEY `A` )";
7675     r = run_query(href, 0, query);
7676     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7677
7678     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 1, 'hi' )";
7679     r = run_query(href, 0, query);
7680     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7681
7682     /* table from merged database is not in target database */
7683     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7684     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7685
7686     query = "SELECT * FROM `One`";
7687     r = do_query(hdb, query, &hrec);
7688     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7689
7690     r = MsiRecordGetInteger(hrec, 1);
7691     ok(r == 1, "Expected 1, got %d\n", r);
7692
7693     size = MAX_PATH;
7694     r = MsiRecordGetStringA(hrec, 2, buf, &size);
7695     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7696     ok(!lstrcmpA(buf, "hi"), "Expected \"hi\", got \"%s\"\n", buf);
7697
7698     MsiCloseHandle(hrec);
7699
7700     /* nothing in MergeErrors */
7701     query = "SELECT * FROM `MergeErrors`";
7702     r = do_query(hdb, query, &hrec);
7703     ok(r == ERROR_BAD_QUERY_SYNTAX,
7704        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7705
7706     query = "DROP TABLE `One`";
7707     r = run_query(hdb, 0, query);
7708     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7709
7710     query = "DROP TABLE `One`";
7711     r = run_query(href, 0, query);
7712     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7713
7714     query = "CREATE TABLE `One` ( "
7715             "`A` CHAR(72), `B` INT PRIMARY KEY `A` )";
7716     r = run_query(hdb, 0, query);
7717     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7718
7719     query = "CREATE TABLE `One` ( "
7720             "`A` CHAR(72), `B` INT PRIMARY KEY `A` )";
7721     r = run_query(href, 0, query);
7722     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7723
7724     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 'hi', 1 )";
7725     r = run_query(href, 0, query);
7726     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7727
7728     /* primary key is string */
7729     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7730     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7731
7732     query = "SELECT * FROM `One`";
7733     r = do_query(hdb, query, &hrec);
7734     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7735
7736     size = MAX_PATH;
7737     r = MsiRecordGetStringA(hrec, 1, buf, &size);
7738     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7739     ok(!lstrcmpA(buf, "hi"), "Expected \"hi\", got \"%s\"\n", buf);
7740
7741     r = MsiRecordGetInteger(hrec, 2);
7742     ok(r == 1, "Expected 1, got %d\n", r);
7743
7744     MsiCloseHandle(hrec);
7745
7746     /* nothing in MergeErrors */
7747     query = "SELECT * FROM `MergeErrors`";
7748     r = do_query(hdb, query, &hrec);
7749     ok(r == ERROR_BAD_QUERY_SYNTAX,
7750        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7751
7752     create_file_data("codepage.idt", "\r\n\r\n850\t_ForceCodepage\r\n", 0);
7753
7754     GetCurrentDirectoryA(MAX_PATH, buf);
7755     r = MsiDatabaseImportA(hdb, buf, "codepage.idt");
7756     todo_wine
7757     {
7758         ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7759     }
7760
7761     query = "DROP TABLE `One`";
7762     r = run_query(hdb, 0, query);
7763     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7764
7765     query = "DROP TABLE `One`";
7766     r = run_query(href, 0, query);
7767     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7768
7769     query = "CREATE TABLE `One` ( "
7770             "`A` INT, `B` CHAR(72) LOCALIZABLE PRIMARY KEY `A` )";
7771     r = run_query(hdb, 0, query);
7772     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7773
7774     query = "CREATE TABLE `One` ( "
7775             "`A` INT, `B` CHAR(72) LOCALIZABLE PRIMARY KEY `A` )";
7776     r = run_query(href, 0, query);
7777     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7778
7779     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 1, 'hi' )";
7780     r = run_query(href, 0, query);
7781     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7782
7783     /* code page does not match */
7784     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7785     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7786
7787     query = "SELECT * FROM `One`";
7788     r = do_query(hdb, query, &hrec);
7789     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7790
7791     r = MsiRecordGetInteger(hrec, 1);
7792     ok(r == 1, "Expected 1, got %d\n", r);
7793
7794     size = MAX_PATH;
7795     r = MsiRecordGetStringA(hrec, 2, buf, &size);
7796     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7797     ok(!lstrcmpA(buf, "hi"), "Expected \"hi\", got \"%s\"\n", buf);
7798
7799     MsiCloseHandle(hrec);
7800
7801     /* nothing in MergeErrors */
7802     query = "SELECT * FROM `MergeErrors`";
7803     r = do_query(hdb, query, &hrec);
7804     ok(r == ERROR_BAD_QUERY_SYNTAX,
7805        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7806
7807     query = "DROP TABLE `One`";
7808     r = run_query(hdb, 0, query);
7809     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7810
7811     query = "DROP TABLE `One`";
7812     r = run_query(href, 0, query);
7813     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7814
7815     query = "CREATE TABLE `One` ( `A` INT, `B` OBJECT PRIMARY KEY `A` )";
7816     r = run_query(hdb, 0, query);
7817     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7818
7819     query = "CREATE TABLE `One` ( `A` INT, `B` OBJECT PRIMARY KEY `A` )";
7820     r = run_query(href, 0, query);
7821     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7822
7823     create_file("binary.dat");
7824     hrec = MsiCreateRecord(1);
7825     MsiRecordSetStreamA(hrec, 1, "binary.dat");
7826
7827     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 1, ? )";
7828     r = run_query(href, hrec, query);
7829     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7830
7831     MsiCloseHandle(hrec);
7832
7833     /* binary data to merge */
7834     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7835     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7836
7837     query = "SELECT * FROM `One`";
7838     r = do_query(hdb, query, &hrec);
7839     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7840
7841     r = MsiRecordGetInteger(hrec, 1);
7842     ok(r == 1, "Expected 1, got %d\n", r);
7843
7844     size = MAX_PATH;
7845     ZeroMemory(buf, MAX_PATH);
7846     r = MsiRecordReadStream(hrec, 2, buf, &size);
7847     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7848     ok(!lstrcmpA(buf, "binary.dat\n"),
7849        "Expected \"binary.dat\\n\", got \"%s\"\n", buf);
7850
7851     MsiCloseHandle(hrec);
7852
7853     /* nothing in MergeErrors */
7854     query = "SELECT * FROM `MergeErrors`";
7855     r = do_query(hdb, query, &hrec);
7856     ok(r == ERROR_BAD_QUERY_SYNTAX,
7857        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7858
7859     query = "DROP TABLE `One`";
7860     r = run_query(hdb, 0, query);
7861     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7862
7863     query = "DROP TABLE `One`";
7864     r = run_query(href, 0, query);
7865     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7866
7867     query = "CREATE TABLE `One` ( `A` INT, `B` CHAR(72) PRIMARY KEY `A` )";
7868     r = run_query(hdb, 0, query);
7869     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7870     r = run_query(href, 0, query);
7871     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7872
7873     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 1, 'foo' )";
7874     r = run_query(href, 0, query);
7875     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7876
7877     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 2, 'bar' )";
7878     r = run_query(href, 0, query);
7879     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7880
7881     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7882     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7883
7884     query = "SELECT * FROM `One`";
7885     r = MsiDatabaseOpenViewA(hdb, query, &hview);
7886     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7887     r = MsiViewExecute(hview, 0);
7888     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7889
7890     r = MsiViewFetch(hview, &hrec);
7891     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7892
7893     r = MsiRecordGetInteger(hrec, 1);
7894     ok(r == 1, "Expected 1, got %d\n", r);
7895
7896     size = MAX_PATH;
7897     r = MsiRecordGetStringA(hrec, 2, buf, &size);
7898     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7899     ok(!lstrcmpA(buf, "foo"), "Expected \"foo\", got \"%s\"\n", buf);
7900
7901     MsiCloseHandle(hrec);
7902
7903     r = MsiViewFetch(hview, &hrec);
7904     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7905
7906     r = MsiRecordGetInteger(hrec, 1);
7907     ok(r == 2, "Expected 2, got %d\n", r);
7908
7909     size = MAX_PATH;
7910     r = MsiRecordGetStringA(hrec, 2, buf, &size);
7911     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7912     ok(!lstrcmpA(buf, "bar"), "Expected \"bar\", got \"%s\"\n", buf);
7913
7914     MsiCloseHandle(hrec);
7915
7916     r = MsiViewFetch(hview, &hrec);
7917     ok(r == ERROR_NO_MORE_ITEMS,
7918        "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7919
7920     MsiViewClose(hview);
7921     MsiCloseHandle(hview);
7922
7923     MsiCloseHandle(hdb);
7924     MsiCloseHandle(href);
7925     DeleteFileA(msifile);
7926     DeleteFileA("refdb.msi");
7927     DeleteFileA("codepage.idt");
7928     DeleteFileA("binary.dat");
7929 }
7930
7931 static void test_select_with_tablenames(void)
7932 {
7933     MSIHANDLE hdb, view, rec;
7934     LPCSTR query;
7935     UINT r;
7936     int i;
7937
7938     int vals[4][2] = {
7939         {1,12},
7940         {4,12},
7941         {1,15},
7942         {4,15}};
7943
7944     hdb = create_db();
7945     ok(hdb, "failed to create db\n");
7946
7947     /* Build a pair of tables with the same column names, but unique data */
7948     query = "CREATE TABLE `T1` ( `A` SHORT, `B` SHORT PRIMARY KEY `A`)";
7949     r = run_query(hdb, 0, query);
7950     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7951
7952     query = "INSERT INTO `T1` ( `A`, `B` ) VALUES ( 1, 2 )";
7953     r = run_query(hdb, 0, query);
7954     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7955
7956     query = "INSERT INTO `T1` ( `A`, `B` ) VALUES ( 4, 5 )";
7957     r = run_query(hdb, 0, query);
7958     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7959
7960     query = "CREATE TABLE `T2` ( `A` SHORT, `B` SHORT PRIMARY KEY `A`)";
7961     r = run_query(hdb, 0, query);
7962     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7963
7964     query = "INSERT INTO `T2` ( `A`, `B` ) VALUES ( 11, 12 )";
7965     r = run_query(hdb, 0, query);
7966     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7967
7968     query = "INSERT INTO `T2` ( `A`, `B` ) VALUES ( 14, 15 )";
7969     r = run_query(hdb, 0, query);
7970     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7971
7972
7973     /* Test that selection based on prefixing the column with the table
7974      * actually selects the right data */
7975
7976     query = "SELECT T1.A, T2.B FROM T1,T2";
7977     r = MsiDatabaseOpenView(hdb, query, &view);
7978     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7979     r = MsiViewExecute(view, 0);
7980     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7981
7982     for (i = 0; i < 4; i++)
7983     {
7984         r = MsiViewFetch(view, &rec);
7985         ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7986
7987         r = MsiRecordGetInteger(rec, 1);
7988         ok(r == vals[i][0], "Expected %d, got %d\n", vals[i][0], r);
7989
7990         r = MsiRecordGetInteger(rec, 2);
7991         ok(r == vals[i][1], "Expected %d, got %d\n", vals[i][1], r);
7992
7993         MsiCloseHandle(rec);
7994     }
7995
7996     r = MsiViewFetch(view, &rec);
7997     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7998
7999     MsiViewClose(view);
8000     MsiCloseHandle(view);
8001     MsiCloseHandle(hdb);
8002     DeleteFileA(msifile);
8003 }
8004
8005 UINT ordervals[6][3] =
8006 {
8007     { MSI_NULL_INTEGER, 12, 13 },
8008     { 1, 2, 3 },
8009     { 6, 4, 5 },
8010     { 8, 9, 7 },
8011     { 10, 11, MSI_NULL_INTEGER },
8012     { 14, MSI_NULL_INTEGER, 15 }
8013 };
8014
8015 static void test_insertorder(void)
8016 {
8017     MSIHANDLE hdb, view, rec;
8018     LPCSTR query;
8019     UINT r;
8020     int i;
8021
8022     hdb = create_db();
8023     ok(hdb, "failed to create db\n");
8024
8025     query = "CREATE TABLE `T` ( `A` SHORT, `B` SHORT, `C` SHORT PRIMARY KEY `A`)";
8026     r = run_query(hdb, 0, query);
8027     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8028
8029     query = "INSERT INTO `T` ( `A`, `B`, `C` ) VALUES ( 1, 2, 3 )";
8030     r = run_query(hdb, 0, query);
8031     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8032
8033     query = "INSERT INTO `T` ( `B`, `C`, `A` ) VALUES ( 4, 5, 6 )";
8034     r = run_query(hdb, 0, query);
8035     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8036
8037     query = "INSERT INTO `T` ( `C`, `A`, `B` ) VALUES ( 7, 8, 9 )";
8038     r = run_query(hdb, 0, query);
8039     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8040
8041     query = "INSERT INTO `T` ( `A`, `B` ) VALUES ( 10, 11 )";
8042     r = run_query(hdb, 0, query);
8043     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8044
8045     query = "INSERT INTO `T` ( `B`, `C` ) VALUES ( 12, 13 )";
8046     r = run_query(hdb, 0, query);
8047     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8048
8049     /* fails because the primary key already
8050      * has an MSI_NULL_INTEGER value set above
8051      */
8052     query = "INSERT INTO `T` ( `C` ) VALUES ( 14 )";
8053     r = run_query(hdb, 0, query);
8054     ok(r == ERROR_FUNCTION_FAILED,
8055        "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
8056
8057     /* replicate the error where primary key is set twice */
8058     query = "INSERT INTO `T` ( `A`, `C` ) VALUES ( 1, 14 )";
8059     r = run_query(hdb, 0, query);
8060     ok(r == ERROR_FUNCTION_FAILED,
8061        "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
8062
8063     query = "INSERT INTO `T` ( `A`, `C` ) VALUES ( 14, 15 )";
8064     r = run_query(hdb, 0, query);
8065     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8066
8067     query = "INSERT INTO `T` VALUES ( 16 )";
8068     r = run_query(hdb, 0, query);
8069     ok(r == ERROR_BAD_QUERY_SYNTAX,
8070        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
8071
8072     query = "INSERT INTO `T` VALUES ( 17, 18 )";
8073     r = run_query(hdb, 0, query);
8074     ok(r == ERROR_BAD_QUERY_SYNTAX,
8075        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
8076
8077     query = "INSERT INTO `T` VALUES ( 19, 20, 21 )";
8078     r = run_query(hdb, 0, query);
8079     ok(r == ERROR_BAD_QUERY_SYNTAX,
8080        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
8081
8082     query = "SELECT * FROM `T`";
8083     r = MsiDatabaseOpenView(hdb, query, &view);
8084     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8085     r = MsiViewExecute(view, 0);
8086     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8087
8088     for (i = 0; i < 6; i++)
8089     {
8090         r = MsiViewFetch(view, &rec);
8091         ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8092
8093         r = MsiRecordGetInteger(rec, 1);
8094         ok(r == ordervals[i][0], "Expected %d, got %d\n", ordervals[i][0], r);
8095
8096         r = MsiRecordGetInteger(rec, 2);
8097         ok(r == ordervals[i][1], "Expected %d, got %d\n", ordervals[i][1], r);
8098
8099         r = MsiRecordGetInteger(rec, 3);
8100         ok(r == ordervals[i][2], "Expected %d, got %d\n", ordervals[i][2], r);
8101
8102         MsiCloseHandle(rec);
8103     }
8104
8105     r = MsiViewFetch(view, &rec);
8106     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
8107
8108     MsiViewClose(view);
8109     MsiCloseHandle(view);
8110
8111     query = "DELETE FROM `T` WHERE `A` IS NULL";
8112     r = run_query(hdb, 0, query);
8113     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8114
8115     query = "INSERT INTO `T` ( `B`, `C` ) VALUES ( 12, 13 ) TEMPORARY";
8116     r = run_query(hdb, 0, query);
8117     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8118
8119     query = "SELECT * FROM `T`";
8120     r = MsiDatabaseOpenView(hdb, query, &view);
8121     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8122     r = MsiViewExecute(view, 0);
8123     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8124
8125     for (i = 0; i < 6; i++)
8126     {
8127         r = MsiViewFetch(view, &rec);
8128         ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8129
8130         r = MsiRecordGetInteger(rec, 1);
8131         ok(r == ordervals[i][0], "Expected %d, got %d\n", ordervals[i][0], r);
8132
8133         r = MsiRecordGetInteger(rec, 2);
8134         ok(r == ordervals[i][1], "Expected %d, got %d\n", ordervals[i][1], r);
8135
8136         r = MsiRecordGetInteger(rec, 3);
8137         ok(r == ordervals[i][2], "Expected %d, got %d\n", ordervals[i][2], r);
8138
8139         MsiCloseHandle(rec);
8140     }
8141
8142     r = MsiViewFetch(view, &rec);
8143     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
8144
8145     MsiViewClose(view);
8146     MsiCloseHandle(view);
8147     MsiCloseHandle(hdb);
8148     DeleteFileA(msifile);
8149 }
8150
8151 static void test_columnorder(void)
8152 {
8153     MSIHANDLE hdb, view, rec;
8154     char buf[MAX_PATH];
8155     LPCSTR query;
8156     DWORD sz;
8157     UINT r;
8158
8159     hdb = create_db();
8160     ok(hdb, "failed to create db\n");
8161
8162     /* Each column is a slot:
8163      * ---------------------
8164      * | B | C | A | E | D |
8165      * ---------------------
8166      *
8167      * When a column is selected as a primary key,
8168      * the column occupying the nth primary key slot is swapped
8169      * with the current position of the primary key in question:
8170      *
8171      * set primary key `D`
8172      * ---------------------    ---------------------
8173      * | B | C | A | E | D | -> | D | C | A | E | B |
8174      * ---------------------    ---------------------
8175      *
8176      * set primary key `E`
8177      * ---------------------    ---------------------
8178      * | D | C | A | E | B | -> | D | E | A | C | B |
8179      * ---------------------    ---------------------
8180      */
8181
8182     query = "CREATE TABLE `T` ( `B` SHORT NOT NULL, `C` SHORT NOT NULL, "
8183             "`A` CHAR(255), `E` INT, `D` CHAR(255) NOT NULL "
8184             "PRIMARY KEY `D`, `E`)";
8185     r = run_query(hdb, 0, query);
8186     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8187
8188     query = "SELECT * FROM `T`";
8189     r = MsiDatabaseOpenView(hdb, query, &view);
8190     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8191
8192     r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
8193     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8194
8195     sz = MAX_PATH;
8196     lstrcpyA(buf, "kiwi");
8197     r = MsiRecordGetString(rec, 1, buf, &sz);
8198     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8199     ok(!lstrcmpA("s255", buf), "Expected \"s255\", got \"%s\"\n", buf);
8200
8201     sz = MAX_PATH;
8202     lstrcpyA(buf, "kiwi");
8203     r = MsiRecordGetString(rec, 2, buf, &sz);
8204     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8205     ok(!lstrcmpA("I2", buf), "Expected \"I2\", got \"%s\"\n", buf);
8206
8207     sz = MAX_PATH;
8208     lstrcpyA(buf, "kiwi");
8209     r = MsiRecordGetString(rec, 3, buf, &sz);
8210     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8211     ok(!lstrcmpA("S255", buf), "Expected \"S255\", got \"%s\"\n", buf);
8212
8213     sz = MAX_PATH;
8214     lstrcpyA(buf, "kiwi");
8215     r = MsiRecordGetString(rec, 4, buf, &sz);
8216     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8217     ok(!lstrcmpA("i2", buf), "Expected \"i2\", got \"%s\"\n", buf);
8218
8219     sz = MAX_PATH;
8220     lstrcpyA(buf, "kiwi");
8221     r = MsiRecordGetString(rec, 5, buf, &sz);
8222     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8223     ok(!lstrcmpA("i2", buf), "Expected \"i2\", got \"%s\"\n", buf);
8224
8225     MsiCloseHandle(rec);
8226
8227     r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec);
8228     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8229
8230     sz = MAX_PATH;
8231     lstrcpyA(buf, "kiwi");
8232     r = MsiRecordGetString(rec, 1, buf, &sz);
8233     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8234     ok(!lstrcmpA("D", buf), "Expected \"D\", got \"%s\"\n", buf);
8235
8236     sz = MAX_PATH;
8237     lstrcpyA(buf, "kiwi");
8238     r = MsiRecordGetString(rec, 2, buf, &sz);
8239     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8240     ok(!lstrcmpA("E", buf), "Expected \"E\", got \"%s\"\n", buf);
8241
8242     sz = MAX_PATH;
8243     lstrcpyA(buf, "kiwi");
8244     r = MsiRecordGetString(rec, 3, buf, &sz);
8245     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8246     ok(!lstrcmpA("A", buf), "Expected \"A\", got \"%s\"\n", buf);
8247
8248     sz = MAX_PATH;
8249     lstrcpyA(buf, "kiwi");
8250     r = MsiRecordGetString(rec, 4, buf, &sz);
8251     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8252     ok(!lstrcmpA("C", buf), "Expected \"C\", got \"%s\"\n", buf);
8253
8254     sz = MAX_PATH;
8255     lstrcpyA(buf, "kiwi");
8256     r = MsiRecordGetString(rec, 5, buf, &sz);
8257     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8258     ok(!lstrcmpA("B", buf), "Expected \"B\", got \"%s\"\n", buf);
8259
8260     MsiCloseHandle(rec);
8261     MsiViewClose(view);
8262     MsiCloseHandle(view);
8263
8264     query = "INSERT INTO `T` ( `B`, `C`, `A`, `E`, `D` ) "
8265             "VALUES ( 1, 2, 'a', 3, 'bc' )";
8266     r = run_query(hdb, 0, query);
8267     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8268
8269     query = "SELECT * FROM `T`";
8270     r = do_query(hdb, query, &rec);
8271
8272     sz = MAX_PATH;
8273     lstrcpyA(buf, "kiwi");
8274     r = MsiRecordGetString(rec, 1, buf, &sz);
8275     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8276     ok(!lstrcmpA("bc", buf), "Expected \"bc\", got \"%s\"\n", buf);
8277
8278     r = MsiRecordGetInteger(rec, 2);
8279     ok(r == 3, "Expected 3, got %d\n", r);
8280
8281     sz = MAX_PATH;
8282     lstrcpyA(buf, "kiwi");
8283     r = MsiRecordGetString(rec, 3, buf, &sz);
8284     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8285     ok(!lstrcmpA("a", buf), "Expected \"a\", got \"%s\"\n", buf);
8286
8287     r = MsiRecordGetInteger(rec, 4);
8288     ok(r == 2, "Expected 2, got %d\n", r);
8289
8290     r = MsiRecordGetInteger(rec, 5);
8291     ok(r == 1, "Expected 1, got %d\n", r);
8292
8293     MsiCloseHandle(rec);
8294
8295     query = "SELECT * FROM `_Columns` WHERE `Table` = 'T'";
8296     r = MsiDatabaseOpenView(hdb, query, &view);
8297     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8298     r = MsiViewExecute(view, 0);
8299     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8300
8301     r = MsiViewFetch(view, &rec);
8302     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8303
8304     sz = MAX_PATH;
8305     lstrcpyA(buf, "kiwi");
8306     r = MsiRecordGetString(rec, 1, buf, &sz);
8307     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8308     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
8309
8310     r = MsiRecordGetInteger(rec, 2);
8311     ok(r == 1, "Expected 1, got %d\n", r);
8312
8313     sz = MAX_PATH;
8314     lstrcpyA(buf, "kiwi");
8315     r = MsiRecordGetString(rec, 3, buf, &sz);
8316     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8317     ok(!lstrcmpA("D", buf), "Expected \"D\", got \"%s\"\n", buf);
8318
8319     MsiCloseHandle(rec);
8320
8321     r = MsiViewFetch(view, &rec);
8322     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8323
8324     sz = MAX_PATH;
8325     lstrcpyA(buf, "kiwi");
8326     r = MsiRecordGetString(rec, 1, buf, &sz);
8327     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8328     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
8329
8330     r = MsiRecordGetInteger(rec, 2);
8331     ok(r == 2, "Expected 2, got %d\n", r);
8332
8333     sz = MAX_PATH;
8334     lstrcpyA(buf, "kiwi");
8335     r = MsiRecordGetString(rec, 3, buf, &sz);
8336     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8337     ok(!lstrcmpA("E", buf), "Expected \"E\", got \"%s\"\n", buf);
8338
8339     MsiCloseHandle(rec);
8340
8341     r = MsiViewFetch(view, &rec);
8342     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8343
8344     sz = MAX_PATH;
8345     lstrcpyA(buf, "kiwi");
8346     r = MsiRecordGetString(rec, 1, buf, &sz);
8347     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8348     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
8349
8350     r = MsiRecordGetInteger(rec, 2);
8351     ok(r == 3, "Expected 3, got %d\n", r);
8352
8353     sz = MAX_PATH;
8354     lstrcpyA(buf, "kiwi");
8355     r = MsiRecordGetString(rec, 3, buf, &sz);
8356     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8357     ok(!lstrcmpA("A", buf), "Expected \"A\", got \"%s\"\n", buf);
8358
8359     MsiCloseHandle(rec);
8360
8361     r = MsiViewFetch(view, &rec);
8362     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8363
8364     sz = MAX_PATH;
8365     lstrcpyA(buf, "kiwi");
8366     r = MsiRecordGetString(rec, 1, buf, &sz);
8367     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8368     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
8369
8370     r = MsiRecordGetInteger(rec, 2);
8371     ok(r == 4, "Expected 4, got %d\n", r);
8372
8373     sz = MAX_PATH;
8374     lstrcpyA(buf, "kiwi");
8375     r = MsiRecordGetString(rec, 3, buf, &sz);
8376     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8377     ok(!lstrcmpA("C", buf), "Expected \"C\", got \"%s\"\n", buf);
8378
8379     MsiCloseHandle(rec);
8380
8381     r = MsiViewFetch(view, &rec);
8382     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8383
8384     sz = MAX_PATH;
8385     lstrcpyA(buf, "kiwi");
8386     r = MsiRecordGetString(rec, 1, buf, &sz);
8387     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8388     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
8389
8390     r = MsiRecordGetInteger(rec, 2);
8391     ok(r == 5, "Expected 5, got %d\n", r);
8392
8393     sz = MAX_PATH;
8394     lstrcpyA(buf, "kiwi");
8395     r = MsiRecordGetString(rec, 3, buf, &sz);
8396     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8397     ok(!lstrcmpA("B", buf), "Expected \"B\", got \"%s\"\n", buf);
8398
8399     MsiCloseHandle(rec);
8400
8401     r = MsiViewFetch(view, &rec);
8402     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
8403
8404     MsiViewClose(view);
8405     MsiCloseHandle(view);
8406
8407     query = "CREATE TABLE `Z` ( `B` SHORT NOT NULL, `C` SHORT NOT NULL, "
8408             "`A` CHAR(255), `E` INT, `D` CHAR(255) NOT NULL "
8409             "PRIMARY KEY `C`, `A`, `D`)";
8410     r = run_query(hdb, 0, query);
8411     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8412
8413     query = "SELECT * FROM `Z`";
8414     r = MsiDatabaseOpenView(hdb, query, &view);
8415     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8416
8417     r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
8418     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8419
8420     sz = MAX_PATH;
8421     lstrcpyA(buf, "kiwi");
8422     r = MsiRecordGetString(rec, 1, buf, &sz);
8423     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8424     ok(!lstrcmpA("i2", buf), "Expected \"i2\", got \"%s\"\n", buf);
8425
8426     sz = MAX_PATH;
8427     lstrcpyA(buf, "kiwi");
8428     r = MsiRecordGetString(rec, 2, buf, &sz);
8429     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8430     ok(!lstrcmpA("S255", buf), "Expected \"S255\", got \"%s\"\n", buf);
8431
8432     sz = MAX_PATH;
8433     lstrcpyA(buf, "kiwi");
8434     r = MsiRecordGetString(rec, 3, buf, &sz);
8435     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8436     ok(!lstrcmpA("s255", buf), "Expected \"s255\", got \"%s\"\n", buf);
8437
8438     sz = MAX_PATH;
8439     lstrcpyA(buf, "kiwi");
8440     r = MsiRecordGetString(rec, 4, buf, &sz);
8441     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8442     ok(!lstrcmpA("I2", buf), "Expected \"I2\", got \"%s\"\n", buf);
8443
8444     sz = MAX_PATH;
8445     lstrcpyA(buf, "kiwi");
8446     r = MsiRecordGetString(rec, 5, buf, &sz);
8447     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8448     ok(!lstrcmpA("i2", buf), "Expected \"i2\", got \"%s\"\n", buf);
8449
8450     MsiCloseHandle(rec);
8451
8452     r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec);
8453     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8454
8455     sz = MAX_PATH;
8456     lstrcpyA(buf, "kiwi");
8457     r = MsiRecordGetString(rec, 1, buf, &sz);
8458     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8459     ok(!lstrcmpA("C", buf), "Expected \"C\", got \"%s\"\n", buf);
8460
8461     sz = MAX_PATH;
8462     lstrcpyA(buf, "kiwi");
8463     r = MsiRecordGetString(rec, 2, buf, &sz);
8464     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8465     ok(!lstrcmpA("A", buf), "Expected \"A\", got \"%s\"\n", buf);
8466
8467     sz = MAX_PATH;
8468     lstrcpyA(buf, "kiwi");
8469     r = MsiRecordGetString(rec, 3, buf, &sz);
8470     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8471     ok(!lstrcmpA("D", buf), "Expected \"D\", got \"%s\"\n", buf);
8472
8473     sz = MAX_PATH;
8474     lstrcpyA(buf, "kiwi");
8475     r = MsiRecordGetString(rec, 4, buf, &sz);
8476     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8477     ok(!lstrcmpA("E", buf), "Expected \"E\", got \"%s\"\n", buf);
8478
8479     sz = MAX_PATH;
8480     lstrcpyA(buf, "kiwi");
8481     r = MsiRecordGetString(rec, 5, buf, &sz);
8482     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8483     ok(!lstrcmpA("B", buf), "Expected \"B\", got \"%s\"\n", buf);
8484
8485     MsiCloseHandle(rec);
8486     MsiViewClose(view);
8487     MsiCloseHandle(view);
8488
8489     query = "INSERT INTO `Z` ( `B`, `C`, `A`, `E`, `D` ) "
8490             "VALUES ( 1, 2, 'a', 3, 'bc' )";
8491     r = run_query(hdb, 0, query);
8492     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8493
8494     query = "SELECT * FROM `Z`";
8495     r = do_query(hdb, query, &rec);
8496
8497     r = MsiRecordGetInteger(rec, 1);
8498     ok(r == 2, "Expected 2, got %d\n", r);
8499
8500     sz = MAX_PATH;
8501     lstrcpyA(buf, "kiwi");
8502     r = MsiRecordGetString(rec, 2, buf, &sz);
8503     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8504     ok(!lstrcmpA("a", buf), "Expected \"a\", got \"%s\"\n", buf);
8505
8506     sz = MAX_PATH;
8507     lstrcpyA(buf, "kiwi");
8508     r = MsiRecordGetString(rec, 3, buf, &sz);
8509     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8510     ok(!lstrcmpA("bc", buf), "Expected \"bc\", got \"%s\"\n", buf);
8511
8512     r = MsiRecordGetInteger(rec, 4);
8513     ok(r == 3, "Expected 3, got %d\n", r);
8514
8515     r = MsiRecordGetInteger(rec, 5);
8516     ok(r == 1, "Expected 1, got %d\n", r);
8517
8518     MsiCloseHandle(rec);
8519
8520     query = "SELECT * FROM `_Columns` WHERE `Table` = 'T'";
8521     r = MsiDatabaseOpenView(hdb, query, &view);
8522     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8523     r = MsiViewExecute(view, 0);
8524     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8525
8526     r = MsiViewFetch(view, &rec);
8527     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8528
8529     sz = MAX_PATH;
8530     lstrcpyA(buf, "kiwi");
8531     r = MsiRecordGetString(rec, 1, buf, &sz);
8532     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8533     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
8534
8535     r = MsiRecordGetInteger(rec, 2);
8536     ok(r == 1, "Expected 1, got %d\n", r);
8537
8538     sz = MAX_PATH;
8539     lstrcpyA(buf, "kiwi");
8540     r = MsiRecordGetString(rec, 3, buf, &sz);
8541     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8542     ok(!lstrcmpA("D", buf), "Expected \"D\", got \"%s\"\n", buf);
8543
8544     MsiCloseHandle(rec);
8545
8546     r = MsiViewFetch(view, &rec);
8547     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8548
8549     sz = MAX_PATH;
8550     lstrcpyA(buf, "kiwi");
8551     r = MsiRecordGetString(rec, 1, buf, &sz);
8552     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8553     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
8554
8555     r = MsiRecordGetInteger(rec, 2);
8556     ok(r == 2, "Expected 2, got %d\n", r);
8557
8558     sz = MAX_PATH;
8559     lstrcpyA(buf, "kiwi");
8560     r = MsiRecordGetString(rec, 3, buf, &sz);
8561     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8562     ok(!lstrcmpA("E", buf), "Expected \"E\", got \"%s\"\n", buf);
8563
8564     MsiCloseHandle(rec);
8565
8566     r = MsiViewFetch(view, &rec);
8567     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8568
8569     sz = MAX_PATH;
8570     lstrcpyA(buf, "kiwi");
8571     r = MsiRecordGetString(rec, 1, buf, &sz);
8572     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8573     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
8574
8575     r = MsiRecordGetInteger(rec, 2);
8576     ok(r == 3, "Expected 3, got %d\n", r);
8577
8578     sz = MAX_PATH;
8579     lstrcpyA(buf, "kiwi");
8580     r = MsiRecordGetString(rec, 3, buf, &sz);
8581     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8582     ok(!lstrcmpA("A", buf), "Expected \"A\", got \"%s\"\n", buf);
8583
8584     MsiCloseHandle(rec);
8585
8586     r = MsiViewFetch(view, &rec);
8587     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8588
8589     sz = MAX_PATH;
8590     lstrcpyA(buf, "kiwi");
8591     r = MsiRecordGetString(rec, 1, buf, &sz);
8592     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8593     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
8594
8595     r = MsiRecordGetInteger(rec, 2);
8596     ok(r == 4, "Expected 4, got %d\n", r);
8597
8598     sz = MAX_PATH;
8599     lstrcpyA(buf, "kiwi");
8600     r = MsiRecordGetString(rec, 3, buf, &sz);
8601     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8602     ok(!lstrcmpA("C", buf), "Expected \"C\", got \"%s\"\n", buf);
8603
8604     MsiCloseHandle(rec);
8605
8606     r = MsiViewFetch(view, &rec);
8607     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8608
8609     sz = MAX_PATH;
8610     lstrcpyA(buf, "kiwi");
8611     r = MsiRecordGetString(rec, 1, buf, &sz);
8612     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8613     ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf);
8614
8615     r = MsiRecordGetInteger(rec, 2);
8616     ok(r == 5, "Expected 5, got %d\n", r);
8617
8618     sz = MAX_PATH;
8619     lstrcpyA(buf, "kiwi");
8620     r = MsiRecordGetString(rec, 3, buf, &sz);
8621     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8622     ok(!lstrcmpA("B", buf), "Expected \"B\", got \"%s\"\n", buf);
8623
8624     MsiCloseHandle(rec);
8625
8626     r = MsiViewFetch(view, &rec);
8627     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
8628
8629     MsiViewClose(view);
8630     MsiCloseHandle(view);
8631
8632     MsiCloseHandle(hdb);
8633     DeleteFileA(msifile);
8634 }
8635
8636 START_TEST(db)
8637 {
8638     test_msidatabase();
8639     test_msiinsert();
8640     test_msidecomposedesc();
8641     test_msibadqueries();
8642     test_viewmodify();
8643     test_viewgetcolumninfo();
8644     test_getcolinfo();
8645     test_msiexport();
8646     test_longstrings();
8647     test_streamtable();
8648     test_binary();
8649     test_where_not_in_selected();
8650     test_where();
8651     test_msiimport();
8652     test_binary_import();
8653     test_markers();
8654     test_handle_limit();
8655     test_try_transform();
8656     test_join();
8657     test_temporary_table();
8658     test_alter();
8659     test_integers();
8660     test_update();
8661     test_special_tables();
8662     test_tables_order();
8663     test_rows_order();
8664     test_select_markers();
8665     test_viewmodify_update();
8666     test_viewmodify_assign();
8667     test_stringtable();
8668     test_viewmodify_delete();
8669     test_defaultdatabase();
8670     test_order();
8671     test_viewmodify_delete_temporary();
8672     test_deleterow();
8673     test_quotes();
8674     test_carriagereturn();
8675     test_noquotes();
8676     test_forcecodepage();
8677     test_viewmodify_refresh();
8678     test_where_viewmodify();
8679     test_storages_table();
8680     test_dbtopackage();
8681     test_droptable();
8682     test_dbmerge();
8683     test_select_with_tablenames();
8684     test_insertorder();
8685     test_columnorder();
8686     test_suminfo_import();
8687 }