xref: /reactos/modules/rostests/winetests/msi/db.c (revision d3ec7cdd)
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 <objidl.h>
27 #include <msi.h>
28 #include <msidefs.h>
29 #include <msiquery.h>
30 
31 #include "wine/test.h"
32 #include "utils.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[] = L"winetest-db.msi";
38 static const WCHAR msifile2W[] = L"winetst2-db.msi";
39 
40 static void WINAPIV check_record_(int line, MSIHANDLE rec, UINT count, ...)
41 {
42     va_list args;
43     UINT i;
44 
45     ok_(__FILE__, line)(count == MsiRecordGetFieldCount(rec),
46             "expected %u fields, got %u\n", count, MsiRecordGetFieldCount(rec));
47 
48     va_start(args, count);
49 
50     for (i = 1; i <= count; ++i)
51     {
52         const char *expect = va_arg(args, const char *);
53         char buffer[200] = "x";
54         DWORD sz = sizeof(buffer);
55         UINT r = MsiRecordGetStringA(rec, i, buffer, &sz);
56         ok_(__FILE__, line)(r == ERROR_SUCCESS, "field %u: got unexpected error %u\n", i, r);
57         ok_(__FILE__, line)(!strcmp(buffer, expect),
58                 "field %u: expected \"%s\", got \"%s\"\n", i, expect, buffer);
59     }
60 
61     va_end(args);
62 }
63 #define check_record(rec, ...) check_record_(__LINE__, rec, __VA_ARGS__)
64 
65 static void test_msidatabase(void)
66 {
67     MSIHANDLE hdb = 0, hdb2 = 0;
68     WCHAR path[MAX_PATH];
69     DWORD len;
70     UINT res;
71 
72     DeleteFileW(msifileW);
73 
74     res = MsiOpenDatabaseW( msifileW, msifile2W, &hdb );
75     ok( res == ERROR_OPEN_FAILED, "expected failure\n");
76 
77     res = MsiOpenDatabaseW( msifileW, (LPWSTR)0xff, &hdb );
78     ok( res == ERROR_INVALID_PARAMETER, "expected failure\n");
79 
80     res = MsiCloseHandle( hdb );
81     ok( res == ERROR_SUCCESS , "Failed to close database\n" );
82 
83     /* create an empty database */
84     res = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb );
85     ok( res == ERROR_SUCCESS , "Failed to create database\n" );
86 
87     res = MsiDatabaseCommit( hdb );
88     ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
89 
90     ok( GetFileAttributesA( msifile ) != INVALID_FILE_ATTRIBUTES, "database should exist\n");
91 
92     res = MsiCloseHandle( hdb );
93     ok( res == ERROR_SUCCESS , "Failed to close database\n" );
94     res = MsiOpenDatabaseW( msifileW, msifile2W, &hdb2 );
95     ok( res == ERROR_SUCCESS , "Failed to open database\n" );
96 
97     ok( GetFileAttributesA( msifile2 ) != INVALID_FILE_ATTRIBUTES, "database should exist\n");
98 
99     res = MsiDatabaseCommit( hdb2 );
100     ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
101 
102     res = MsiCloseHandle( hdb2 );
103     ok( res == ERROR_SUCCESS , "Failed to close database\n" );
104 
105     res = MsiOpenDatabaseW( msifileW, msifile2W, &hdb2 );
106     ok( res == ERROR_SUCCESS , "Failed to open database\n" );
107 
108     res = MsiCloseHandle( hdb2 );
109     ok( res == ERROR_SUCCESS , "Failed to close database\n" );
110 
111     ok( GetFileAttributesA( msifile2 ) == INVALID_FILE_ATTRIBUTES, "uncommitted database should not exist\n");
112 
113     res = MsiOpenDatabaseW( msifileW, msifile2W, &hdb2 );
114     ok( res == ERROR_SUCCESS , "Failed to close database\n" );
115 
116     res = MsiDatabaseCommit( hdb2 );
117     ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
118 
119     res = MsiCloseHandle( hdb2 );
120     ok( res == ERROR_SUCCESS , "Failed to close database\n" );
121 
122     ok( GetFileAttributesA( msifile2 ) != INVALID_FILE_ATTRIBUTES, "committed database should exist\n");
123 
124     res = MsiOpenDatabaseW( msifileW, MSIDBOPEN_READONLY, &hdb );
125     ok( res == ERROR_SUCCESS , "Failed to open database\n" );
126 
127     res = MsiDatabaseCommit( hdb );
128     ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
129 
130     res = MsiCloseHandle( hdb );
131     ok( res == ERROR_SUCCESS , "Failed to close database\n" );
132 
133     res = MsiOpenDatabaseW( msifileW, MSIDBOPEN_DIRECT, &hdb );
134     ok( res == ERROR_SUCCESS , "Failed to open database\n" );
135 
136     res = MsiCloseHandle( hdb );
137     ok( res == ERROR_SUCCESS , "Failed to close database\n" );
138 
139     res = MsiOpenDatabaseW( msifileW, MSIDBOPEN_TRANSACT, &hdb );
140     ok( res == ERROR_SUCCESS , "Failed to open database\n" );
141 
142     res = MsiCloseHandle( hdb );
143     ok( res == ERROR_SUCCESS , "Failed to close database\n" );
144     ok( GetFileAttributesA( msifile ) != INVALID_FILE_ATTRIBUTES, "database should exist\n");
145 
146     /* MSIDBOPEN_CREATE deletes the database if MsiCommitDatabase isn't called */
147     res = MsiOpenDatabaseW( msifileW, MSIDBOPEN_CREATE, &hdb );
148     ok( res == ERROR_SUCCESS , "Failed to open database\n" );
149 
150     ok( GetFileAttributesA( msifile ) != INVALID_FILE_ATTRIBUTES, "database should exist\n");
151 
152     res = MsiCloseHandle( hdb );
153     ok( res == ERROR_SUCCESS , "Failed to close database\n" );
154 
155     ok( GetFileAttributesA( msifile ) == INVALID_FILE_ATTRIBUTES, "database should exist\n");
156 
157     res = MsiOpenDatabaseW( msifileW, MSIDBOPEN_CREATE, &hdb );
158     ok( res == ERROR_SUCCESS , "Failed to open database\n" );
159 
160     res = MsiDatabaseCommit( hdb );
161     ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
162 
163     ok( GetFileAttributesA( msifile ) != INVALID_FILE_ATTRIBUTES, "database should exist\n");
164 
165     res = MsiCloseHandle( hdb );
166     ok( res == ERROR_SUCCESS , "Failed to close database\n" );
167 
168     res = GetCurrentDirectoryW(ARRAY_SIZE(path), path);
169     ok ( res, "Got zero res.\n" );
170     lstrcatW( path, L"\\");
171     lstrcatW( path, msifileW);
172     len = lstrlenW(path);
173     path[len - 4] = 0;
174 
175     res = MsiOpenDatabaseW( path, MSIDBOPEN_READONLY, &hdb );
176     ok( res != ERROR_SUCCESS , "Got unexpected res %u.\n", res );
177 
178     lstrcpyW( path, msifileW );
179     path[lstrlenW(path) - 4] = 0;
180 
181     res = MsiOpenDatabaseW( path, MSIDBOPEN_READONLY, &hdb );
182     ok( res != ERROR_SUCCESS , "Got unexpected res %u.\n", res );
183 
184     res = DeleteFileA( msifile2 );
185     ok( res == TRUE, "Failed to delete database\n" );
186 
187     res = DeleteFileA( msifile );
188     ok( res == TRUE, "Failed to delete database\n" );
189 }
190 
191 static UINT do_query(MSIHANDLE hdb, const char *query, MSIHANDLE *phrec)
192 {
193     MSIHANDLE hview = 0;
194     UINT r, ret;
195 
196     if (phrec)
197         *phrec = 0;
198 
199     /* open a select query */
200     r = MsiDatabaseOpenViewA(hdb, query, &hview);
201     if (r != ERROR_SUCCESS)
202         return r;
203     r = MsiViewExecute(hview, 0);
204     if (r != ERROR_SUCCESS)
205         return r;
206     ret = MsiViewFetch(hview, phrec);
207     r = MsiViewClose(hview);
208     if (r != ERROR_SUCCESS)
209         return r;
210     r = MsiCloseHandle(hview);
211     if (r != ERROR_SUCCESS)
212         return r;
213     return ret;
214 }
215 
216 static UINT run_queryW( MSIHANDLE hdb, MSIHANDLE hrec, const WCHAR *query )
217 {
218     MSIHANDLE hview = 0;
219     UINT r;
220 
221     r = MsiDatabaseOpenViewW(hdb, query, &hview);
222     if( r != ERROR_SUCCESS )
223         return r;
224 
225     r = MsiViewExecute(hview, hrec);
226     if( r == ERROR_SUCCESS )
227         r = MsiViewClose(hview);
228     MsiCloseHandle(hview);
229     return r;
230 }
231 
232 static UINT create_component_table( MSIHANDLE hdb )
233 {
234     UINT r = run_query( hdb, 0,
235             "CREATE TABLE `Component` ( "
236             "`Component` CHAR(72) NOT NULL, "
237             "`ComponentId` CHAR(38), "
238             "`Directory_` CHAR(72) NOT NULL, "
239             "`Attributes` SHORT NOT NULL, "
240             "`Condition` CHAR(255), "
241             "`KeyPath` CHAR(72) "
242             "PRIMARY KEY `Component`)" );
243     ok(r == ERROR_SUCCESS, "Failed to create Component table: %u\n", r);
244     return r;
245 }
246 
247 static UINT create_custom_action_table( MSIHANDLE hdb )
248 {
249     UINT r = run_query( hdb, 0,
250             "CREATE TABLE `CustomAction` ( "
251             "`Action` CHAR(72) NOT NULL, "
252             "`Type` SHORT NOT NULL, "
253             "`Source` CHAR(72), "
254             "`Target` CHAR(255) "
255             "PRIMARY KEY `Action`)" );
256     ok(r == ERROR_SUCCESS, "Failed to create CustomAction table: %u\n", r);
257     return r;
258 }
259 
260 static UINT create_directory_table( MSIHANDLE hdb )
261 {
262     UINT r = run_query( hdb, 0,
263             "CREATE TABLE `Directory` ( "
264             "`Directory` CHAR(255) NOT NULL, "
265             "`Directory_Parent` CHAR(255), "
266             "`DefaultDir` CHAR(255) NOT NULL "
267             "PRIMARY KEY `Directory`)" );
268     ok(r == ERROR_SUCCESS, "Failed to create Directory table: %u\n", r);
269     return r;
270 }
271 
272 static UINT create_feature_components_table( MSIHANDLE hdb )
273 {
274     UINT r = run_query( hdb, 0,
275             "CREATE TABLE `FeatureComponents` ( "
276             "`Feature_` CHAR(38) NOT NULL, "
277             "`Component_` CHAR(72) NOT NULL "
278             "PRIMARY KEY `Feature_`, `Component_` )" );
279     ok(r == ERROR_SUCCESS, "Failed to create FeatureComponents table: %u\n", r);
280     return r;
281 }
282 
283 static UINT create_std_dlls_table( MSIHANDLE hdb )
284 {
285     UINT r = run_query( hdb, 0,
286             "CREATE TABLE `StdDlls` ( "
287             "`File` CHAR(255) NOT NULL, "
288             "`Binary_` CHAR(72) NOT NULL "
289             "PRIMARY KEY `File` )" );
290     ok(r == ERROR_SUCCESS, "Failed to create StdDlls table: %u\n", r);
291     return r;
292 }
293 
294 static UINT create_binary_table( MSIHANDLE hdb )
295 {
296     UINT r = run_query( hdb, 0,
297            "CREATE TABLE `Binary` ( "
298             "`Name` CHAR(72) NOT NULL, "
299             "`Data` CHAR(72) NOT NULL "
300             "PRIMARY KEY `Name` )" );
301     ok(r == ERROR_SUCCESS, "Failed to create Binary table: %u\n", r);
302     return r;
303 }
304 
305 static inline UINT add_entry(const char *file, int line, const char *type, MSIHANDLE hdb, const char *values, const char *insert)
306 {
307     char *query;
308     UINT sz, r;
309 
310     sz = strlen(values) + strlen(insert) + 1;
311     query = malloc(sz);
312     sprintf(query, insert, values);
313     r = run_query(hdb, 0, query);
314     free(query);
315     ok_(file, line)(r == ERROR_SUCCESS, "failed to insert into %s table: %u\n", type, r);
316     return r;
317 }
318 
319 #define add_component_entry(hdb, values) add_entry(__FILE__, __LINE__, "Component", hdb, values, \
320                "INSERT INTO `Component`  " \
321                "(`Component`, `ComponentId`, `Directory_`, " \
322                "`Attributes`, `Condition`, `KeyPath`) VALUES( %s )")
323 
324 #define add_custom_action_entry(hdb, values) add_entry(__FILE__, __LINE__, "CustomAction", hdb, values, \
325                "INSERT INTO `CustomAction`  " \
326                "(`Action`, `Type`, `Source`, `Target`) VALUES( %s )")
327 
328 #define add_feature_components_entry(hdb, values) add_entry(__FILE__, __LINE__, "FeatureComponents", hdb, values, \
329                "INSERT INTO `FeatureComponents` " \
330                "(`Feature_`, `Component_`) VALUES( %s )")
331 
332 #define add_std_dlls_entry(hdb, values) add_entry(__FILE__, __LINE__, "StdDlls", hdb, values, \
333                "INSERT INTO `StdDlls` (`File`, `Binary_`) VALUES( %s )")
334 
335 #define add_binary_entry(hdb, values) add_entry(__FILE__, __LINE__, "Binary", hdb, values, \
336                "INSERT INTO `Binary` (`Name`, `Data`) VALUES( %s )")
337 
338 static void test_msiinsert(void)
339 {
340     MSIHANDLE hdb = 0, hview = 0, hview2 = 0, hrec = 0;
341     UINT r;
342     const char *query;
343     char buf[80];
344     DWORD sz;
345 
346     DeleteFileA(msifile);
347 
348     /* just MsiOpenDatabase should not create a file */
349     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
350     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
351 
352     /* create a table */
353     query = "CREATE TABLE `phone` ( "
354             "`id` INT, `name` CHAR(32), `number` CHAR(32) "
355             "PRIMARY KEY `id`)";
356     r = MsiDatabaseOpenViewA(hdb, query, &hview);
357     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
358     r = MsiViewExecute(hview, 0);
359     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
360     r = MsiViewClose(hview);
361     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
362     r = MsiCloseHandle(hview);
363     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
364 
365     query = "SELECT * FROM phone WHERE number = '8675309'";
366     r = MsiDatabaseOpenViewA(hdb, query, &hview2);
367     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
368     r = MsiViewExecute(hview2, 0);
369     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
370     r = MsiViewFetch(hview2, &hrec);
371     ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch produced items\n");
372 
373     /* insert a value into it */
374     query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
375         "VALUES('1', 'Abe', '8675309')";
376     r = MsiDatabaseOpenViewA(hdb, query, &hview);
377     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
378     r = MsiViewExecute(hview, 0);
379     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
380     r = MsiViewClose(hview);
381     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
382     r = MsiCloseHandle(hview);
383     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
384 
385     r = MsiViewFetch(hview2, &hrec);
386     ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch produced items\n");
387     r = MsiViewExecute(hview2, 0);
388     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
389     r = MsiViewFetch(hview2, &hrec);
390     ok(r == ERROR_SUCCESS, "MsiViewFetch failed: %u\n", r);
391 
392     r = MsiCloseHandle(hrec);
393     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
394     r = MsiViewClose(hview2);
395     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
396     r = MsiCloseHandle(hview2);
397     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
398 
399     query = "SELECT * FROM `phone` WHERE `id` = 1";
400     r = do_query(hdb, query, &hrec);
401     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
402 
403     /* check the record contains what we put in it */
404     r = MsiRecordGetFieldCount(hrec);
405     ok(r == 3, "record count wrong\n");
406 
407     r = MsiRecordIsNull(hrec, 0);
408     ok(r == FALSE, "field 0 not null\n");
409 
410     r = MsiRecordGetInteger(hrec, 1);
411     ok(r == 1, "field 1 contents wrong\n");
412     sz = sizeof buf;
413     r = MsiRecordGetStringA(hrec, 2, buf, &sz);
414     ok(r == ERROR_SUCCESS, "field 2 content fetch failed\n");
415     ok(!strcmp(buf,"Abe"), "field 2 content incorrect\n");
416     sz = sizeof buf;
417     r = MsiRecordGetStringA(hrec, 3, buf, &sz);
418     ok(r == ERROR_SUCCESS, "field 3 content fetch failed\n");
419     ok(!strcmp(buf,"8675309"), "field 3 content incorrect\n");
420 
421     r = MsiCloseHandle(hrec);
422     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
423 
424     /* open a select query */
425     hrec = 100;
426     query = "SELECT * FROM `phone` WHERE `id` >= 10";
427     r = do_query(hdb, query, &hrec);
428     ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch failed\n");
429     ok(hrec == 0, "hrec should be null\n");
430 
431     r = MsiCloseHandle(hrec);
432     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
433 
434     query = "SELECT * FROM `phone` WHERE `id` < 0";
435     r = do_query(hdb, query, &hrec);
436     ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch failed\n");
437 
438     query = "SELECT * FROM `phone` WHERE `id` <= 0";
439     r = do_query(hdb, query, &hrec);
440     ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch failed\n");
441 
442     query = "SELECT * FROM `phone` WHERE `id` <> 1";
443     r = do_query(hdb, query, &hrec);
444     ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch failed\n");
445 
446     query = "SELECT * FROM `phone` WHERE `id` > 10";
447     r = do_query(hdb, query, &hrec);
448     ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch failed\n");
449 
450     /* now try a few bad INSERT xqueries */
451     query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
452         "VALUES(?, ?)";
453     r = MsiDatabaseOpenViewA(hdb, query, &hview);
454     ok(r == ERROR_BAD_QUERY_SYNTAX, "MsiDatabaseOpenView failed\n");
455 
456     /* construct a record to insert */
457     hrec = MsiCreateRecord(4);
458     r = MsiRecordSetInteger(hrec, 1, 2);
459     ok(r == ERROR_SUCCESS, "MsiRecordSetInteger failed\n");
460     r = MsiRecordSetStringA(hrec, 2, "Adam");
461     ok(r == ERROR_SUCCESS, "MsiRecordSetString failed\n");
462     r = MsiRecordSetStringA(hrec, 3, "96905305");
463     ok(r == ERROR_SUCCESS, "MsiRecordSetString failed\n");
464 
465     /* insert another value, using a record and wildcards */
466     query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
467         "VALUES(?, ?, ?)";
468     r = MsiDatabaseOpenViewA(hdb, query, &hview);
469     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
470 
471     if (r == ERROR_SUCCESS)
472     {
473         r = MsiViewExecute(hview, hrec);
474         ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
475         r = MsiViewClose(hview);
476         ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
477         r = MsiCloseHandle(hview);
478         ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
479     }
480     r = MsiCloseHandle(hrec);
481     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
482 
483     r = MsiViewFetch(0, NULL);
484     ok(r == ERROR_INVALID_PARAMETER, "MsiViewFetch failed\n");
485 
486     r = MsiDatabaseCommit(hdb);
487     ok(r == ERROR_SUCCESS, "MsiDatabaseCommit failed\n");
488 
489     r = MsiCloseHandle(hdb);
490     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
491 
492     r = DeleteFileA(msifile);
493     ok(r == TRUE, "file didn't exist after commit\n");
494 }
495 
496 static void test_msidecomposedesc(void)
497 {
498     UINT (WINAPI *pMsiDecomposeDescriptorA)(LPCSTR, LPCSTR, LPSTR, LPSTR, DWORD *);
499     char prod[MAX_FEATURE_CHARS+1], comp[MAX_FEATURE_CHARS+1], feature[MAX_FEATURE_CHARS+1];
500     const char *desc;
501     UINT r;
502     DWORD len;
503     HMODULE hmod;
504 
505     hmod = GetModuleHandleA("msi.dll");
506     pMsiDecomposeDescriptorA = (void*)GetProcAddress(hmod, "MsiDecomposeDescriptorA");
507     if (!pMsiDecomposeDescriptorA)
508         return;
509 
510     /* test a valid feature descriptor */
511     desc = "']gAVn-}f(ZXfeAR6.jiFollowTheWhiteRabbit>3w2x^IGfe?CxI5heAvk.";
512     len = 0;
513     prod[0] = feature[0] = comp[0] = 0;
514     r = pMsiDecomposeDescriptorA(desc, prod, feature, comp, &len);
515     ok(r == ERROR_SUCCESS, "returned an error\n");
516     ok(len == strlen(desc), "length was wrong\n");
517     ok(strcmp(prod,"{90110409-6000-11D3-8CFE-0150048383C9}")==0, "product wrong\n");
518     ok(strcmp(feature,"FollowTheWhiteRabbit")==0, "feature wrong\n");
519     ok(strcmp(comp,"{A7CD68DB-EF74-49C8-FBB2-A7C463B2AC24}")==0,"component wrong\n");
520 
521     /* test an invalid feature descriptor with too many characters */
522     desc = "']gAVn-}f(ZXfeAR6.ji"
523            "ThisWillFailIfTheresMoreThanAGuidsChars>"
524            "3w2x^IGfe?CxI5heAvk.";
525     len = 0;
526     r = pMsiDecomposeDescriptorA(desc, prod, feature, comp, &len);
527     ok(r == ERROR_INVALID_PARAMETER, "returned wrong error\n");
528 
529     /* test a feature descriptor with < instead of > */
530     desc = "']gAVn-}f(ZXfeAR6.jiFollowTheWhiteRabbit<3w2x^IGfe?CxI5heAvk.";
531     len = 0;
532     prod[0] = feature[0] = 0;
533     comp[0] = 0x55;
534     r = pMsiDecomposeDescriptorA(desc, prod, feature, comp, &len);
535     ok(r == ERROR_SUCCESS, "returned an error\n");
536     ok(len == 41, "got %lu\n", len);
537     ok(!strcmp(prod,"{90110409-6000-11D3-8CFE-0150048383C9}"), "got '%s'\n", prod);
538     ok(!strcmp(feature,"FollowTheWhiteRabbit"), "got '%s'\n", feature);
539     ok(!comp[0], "got '%s'\n", comp);
540 
541     len = 0;
542     prod[0] = feature[0] = 0;
543     comp[0] = 0x55;
544     r = pMsiDecomposeDescriptorA("yh1BVN)8A$!!!!!MKKSkAlwaysInstalledIntl_1033<", prod, feature, comp, &len);
545     ok(r == ERROR_SUCCESS, "got %u\n", r);
546     ok(len == 45, "got %lu\n", len);
547     ok(!strcmp(prod, "{90150000-006E-0409-0000-0000000FF1CE}"), "got '%s'\n", prod);
548     ok(!strcmp(feature, "AlwaysInstalledIntl_1033"), "got '%s'\n", feature);
549     ok(!comp[0], "got '%s'\n", comp);
550 
551     /*
552      * Test a valid feature descriptor with the
553      * maximum number of characters and some trailing characters.
554      */
555     desc = "']gAVn-}f(ZXfeAR6.ji"
556            "ThisWillWorkIfTheresLTEThanAGuidsChars>"
557            "3w2x^IGfe?CxI5heAvk."
558            "extra";
559     len = 0;
560     r = pMsiDecomposeDescriptorA(desc, prod, feature, comp, &len);
561     ok(r == ERROR_SUCCESS, "returned wrong error\n");
562     ok(len == (strlen(desc) - strlen("extra")), "length wrong\n");
563 
564     len = 0;
565     r = pMsiDecomposeDescriptorA(desc, prod, feature, NULL, &len);
566     ok(r == ERROR_SUCCESS, "returned wrong error\n");
567     ok(len == (strlen(desc) - strlen("extra")), "length wrong\n");
568 
569     len = 0;
570     r = pMsiDecomposeDescriptorA(desc, prod, NULL, NULL, &len);
571     ok(r == ERROR_SUCCESS, "returned wrong error\n");
572     ok(len == (strlen(desc) - strlen("extra")), "length wrong\n");
573 
574     len = 0;
575     r = pMsiDecomposeDescriptorA(desc, NULL, NULL, NULL, &len);
576     ok(r == ERROR_SUCCESS, "returned wrong error\n");
577     ok(len == (strlen(desc) - strlen("extra")), "length wrong\n");
578 
579     len = 0;
580     r = pMsiDecomposeDescriptorA(NULL, NULL, NULL, NULL, &len);
581     ok(r == ERROR_INVALID_PARAMETER, "returned wrong error\n");
582     ok(len == 0, "length wrong\n");
583 
584     r = pMsiDecomposeDescriptorA(desc, NULL, NULL, NULL, NULL);
585     ok(r == ERROR_SUCCESS, "returned wrong error\n");
586 }
587 
588 static UINT try_query_param( MSIHANDLE hdb, LPCSTR szQuery, MSIHANDLE hrec )
589 {
590     MSIHANDLE htab = 0;
591     UINT res;
592 
593     res = MsiDatabaseOpenViewA( hdb, szQuery, &htab );
594     if(res == ERROR_SUCCESS )
595     {
596         UINT r;
597 
598         r = MsiViewExecute( htab, hrec );
599         if(r != ERROR_SUCCESS )
600             res = r;
601 
602         r = MsiViewClose( htab );
603         if(r != ERROR_SUCCESS )
604             res = r;
605 
606         r = MsiCloseHandle( htab );
607         if(r != ERROR_SUCCESS )
608             res = r;
609     }
610     return res;
611 }
612 
613 static UINT try_query( MSIHANDLE hdb, LPCSTR szQuery )
614 {
615     return try_query_param( hdb, szQuery, 0 );
616 }
617 
618 static UINT try_insert_query( MSIHANDLE hdb, LPCSTR szQuery )
619 {
620     MSIHANDLE hrec = 0;
621     UINT r;
622 
623     hrec = MsiCreateRecord( 1 );
624     MsiRecordSetStringA( hrec, 1, "Hello");
625 
626     r = try_query_param( hdb, szQuery, hrec );
627 
628     MsiCloseHandle( hrec );
629     return r;
630 }
631 
632 static void test_msibadqueries(void)
633 {
634     MSIHANDLE hdb = 0;
635     UINT r;
636 
637     DeleteFileA(msifile);
638 
639     /* just MsiOpenDatabase should not create a file */
640     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
641     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
642 
643     r = MsiDatabaseCommit( hdb );
644     ok(r == ERROR_SUCCESS , "Failed to commit database\n");
645 
646     r = MsiCloseHandle( hdb );
647     ok(r == ERROR_SUCCESS , "Failed to close database\n");
648 
649     /* open it readonly */
650     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_READONLY, &hdb );
651     ok(r == ERROR_SUCCESS , "Failed to open database r/o\n");
652 
653     /* add a table to it */
654     r = try_query( hdb, "select * from _Tables");
655     ok(r == ERROR_SUCCESS , "query 1 failed\n");
656 
657     r = MsiCloseHandle( hdb );
658     ok(r == ERROR_SUCCESS , "Failed to close database r/o\n");
659 
660     /* open it read/write */
661     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_TRANSACT, &hdb );
662     ok(r == ERROR_SUCCESS , "Failed to open database r/w\n");
663 
664     /* a bunch of test queries that fail with the native MSI */
665 
666     r = try_query( hdb, "CREATE TABLE");
667     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2a return code\n");
668 
669     r = try_query( hdb, "CREATE TABLE `a`");
670     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2b return code\n");
671 
672     r = try_query( hdb, "CREATE TABLE `a` ()");
673     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2c return code\n");
674 
675     r = try_query( hdb, "CREATE TABLE `a` (`b`)");
676     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2d return code\n");
677 
678     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) )");
679     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2e return code\n");
680 
681     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL)");
682     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2f return code\n");
683 
684     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY)");
685     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2g return code\n");
686 
687     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY)");
688     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2h return code\n");
689 
690     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY)");
691     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2i return code\n");
692 
693     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY 'b')");
694     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2j return code\n");
695 
696     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY `b')");
697     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2k return code\n");
698 
699     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY `b')");
700     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2l return code\n");
701 
702     r = try_query( hdb, "CREATE TABLE `a` (`b` CHA(72) NOT NULL PRIMARY KEY `b`)");
703     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2m return code\n");
704 
705     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(-1) NOT NULL PRIMARY KEY `b`)");
706     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2n return code\n");
707 
708     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(720) NOT NULL PRIMARY KEY `b`)");
709     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2o return code\n");
710 
711     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL KEY `b`)");
712     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2p return code\n");
713 
714     r = try_query( hdb, "CREATE TABLE `a` (`` CHAR(72) NOT NULL PRIMARY KEY `b`)");
715     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2p return code\n");
716 
717     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY `b`)");
718     ok(r == ERROR_SUCCESS , "valid query 2z failed\n");
719 
720     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY `b`)");
721     ok(r == ERROR_BAD_QUERY_SYNTAX , "created same table again\n");
722 
723     r = try_query( hdb, "CREATE TABLE `aa` (`b` CHAR(72) NOT NULL, `c` "
724           "CHAR(72), `d` CHAR(255) NOT NULL LOCALIZABLE PRIMARY KEY `b`)");
725     ok(r == ERROR_SUCCESS , "query 4 failed\n");
726 
727     r = MsiDatabaseCommit( hdb );
728     ok(r == ERROR_SUCCESS , "Failed to commit database after write\n");
729 
730     r = try_query( hdb, "CREATE TABLE `blah` (`foo` CHAR(72) NOT NULL "
731                           "PRIMARY KEY `foo`)");
732     ok(r == ERROR_SUCCESS , "query 4 failed\n");
733 
734     r = try_insert_query( hdb, "insert into a  ( `b` ) VALUES ( ? )");
735     ok(r == ERROR_SUCCESS , "failed to insert record in db\n");
736 
737     r = MsiDatabaseCommit( hdb );
738     ok(r == ERROR_SUCCESS , "Failed to commit database after write\n");
739 
740     r = try_query( hdb, "CREATE TABLE `boo` (`foo` CHAR(72) NOT NULL "
741                           "PRIMARY KEY `ba`)");
742     ok(r != ERROR_SUCCESS , "query 5 succeeded\n");
743 
744     r = try_query( hdb,"CREATE TABLE `bee` (`foo` CHAR(72) NOT NULL )");
745     ok(r != ERROR_SUCCESS , "query 6 succeeded\n");
746 
747     r = try_query( hdb, "CREATE TABLE `temp` (`t` CHAR(72) NOT NULL "
748                           "PRIMARY KEY `t`)");
749     ok(r == ERROR_SUCCESS , "query 7 failed\n");
750 
751     r = try_query( hdb, "CREATE TABLE `c` (`b` CHAR NOT NULL PRIMARY KEY `b`)");
752     ok(r == ERROR_SUCCESS , "query 8 failed\n");
753 
754     r = try_query( hdb, "select * from c");
755     ok(r == ERROR_SUCCESS , "query failed\n");
756 
757     r = try_query( hdb, "select * from c where b = 'x");
758     ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
759 
760     r = try_query( hdb, "select * from c where b = 'x'");
761     ok(r == ERROR_SUCCESS, "query failed\n");
762 
763     r = try_query( hdb, "select * from 'c'");
764     ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
765 
766     r = try_query( hdb, "select * from ''");
767     ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
768 
769     r = try_query( hdb, "select * from c where b = x");
770     ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
771 
772     r = try_query( hdb, "select * from c where b = \"x\"");
773     ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
774 
775     r = try_query( hdb, "select * from c where b = 'x'");
776     ok(r == ERROR_SUCCESS, "query failed\n");
777 
778     r = try_query( hdb, "select * from c where b = '\"x'");
779     ok(r == ERROR_SUCCESS, "query failed\n");
780 
781     if (0)  /* FIXME: this query causes trouble with other tests */
782     {
783         r = try_query( hdb, "select * from c where b = '\\\'x'");
784         ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
785     }
786 
787     r = try_query( hdb, "select * from 'c'");
788     ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
789 
790     r = try_query( hdb, "select `c`.`b` from `c` order by `c`.`order`");
791     ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %u\n", r );
792 
793     r = try_query( hdb, "select `c`.b` from `c`");
794     ok( r == ERROR_SUCCESS, "query failed: %u\n", r );
795 
796     r = try_query( hdb, "select `c`.`b from `c`");
797     ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %u\n", r );
798 
799     r = try_query( hdb, "select `c`.b from `c`");
800     ok( r == ERROR_SUCCESS, "query failed: %u\n", r );
801 
802     r = try_query( hdb, "select `c.`b` from `c`");
803     ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %u\n", r );
804 
805     r = try_query( hdb, "select c`.`b` from `c`");
806     ok( r == ERROR_SUCCESS, "query failed: %u\n", r );
807 
808     r = try_query( hdb, "select c.`b` from `c`");
809     ok( r == ERROR_SUCCESS, "query failed: %u\n", r );
810 
811     r = try_query( hdb, "select `c`.`b` from c`");
812     ok( r == ERROR_SUCCESS, "query failed: %u\n", r );
813 
814     r = try_query( hdb, "select `c`.`b` from `c");
815     ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %u\n", r );
816 
817     r = try_query( hdb, "select `c`.`b` from c");
818     ok( r == ERROR_SUCCESS, "query failed: %u\n", r );
819 
820     r = try_query( hdb, "CREATE TABLE `\5a` (`b` CHAR NOT NULL PRIMARY KEY `b`)" );
821     ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
822 
823     r = try_query( hdb, "SELECT * FROM \5a" );
824     ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
825 
826     r = try_query( hdb, "CREATE TABLE `a\5` (`b` CHAR NOT NULL PRIMARY KEY `b`)" );
827     ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
828 
829     r = try_query( hdb, "SELECT * FROM a\5" );
830     ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
831 
832     r = try_query( hdb, "CREATE TABLE `-a` (`b` CHAR NOT NULL PRIMARY KEY `b`)" );
833     ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
834 
835     r = try_query( hdb, "SELECT * FROM -a" );
836     todo_wine ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
837 
838     r = try_query( hdb, "CREATE TABLE `a-` (`b` CHAR NOT NULL PRIMARY KEY `b`)" );
839     ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
840 
841     r = try_query( hdb, "SELECT * FROM a-" );
842     ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
843 
844     r = MsiCloseHandle( hdb );
845     ok(r == ERROR_SUCCESS , "Failed to close database transact\n");
846 
847     r = DeleteFileA( msifile );
848     ok(r == TRUE, "file didn't exist after commit\n");
849 }
850 
851 static void test_viewmodify(void)
852 {
853     MSIHANDLE hdb = 0, hview = 0, hrec = 0;
854     UINT r;
855     MSIDBERROR err;
856     const char *query;
857     char buffer[0x100];
858     DWORD sz;
859 
860     DeleteFileA(msifile);
861 
862     /* just MsiOpenDatabase should not create a file */
863     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
864     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
865 
866     query = "CREATE TABLE `phone` ( "
867             "`id` INT, `name` CHAR(32), `number` CHAR(32) "
868             "PRIMARY KEY `id`)";
869     r = run_query( hdb, 0, query );
870     ok(r == ERROR_SUCCESS, "query failed\n");
871 
872     query = "CREATE TABLE `_Validation` ( "
873             "`Table` CHAR(32) NOT NULL, `Column` CHAR(32) NOT NULL, "
874             "`Nullable` CHAR(4) NOT NULL, `MinValue` INT, `MaxValue` INT, "
875             "`KeyTable` CHAR(255), `KeyColumn` SHORT, `Category` CHAR(32), "
876             "`Set` CHAR(255), `Description` CHAR(255) PRIMARY KEY `Table`, `Column`)";
877     r = run_query( hdb, 0, query );
878     ok(r == ERROR_SUCCESS, "query failed\n");
879 
880     query = "INSERT INTO `_Validation` ( `Table`, `Column`, `Nullable` ) "
881             "VALUES('phone', 'id', 'N')";
882     r = run_query( hdb, 0, query );
883     ok(r == ERROR_SUCCESS, "query failed\n");
884 
885     query = "SELECT * FROM `phone`";
886     r = MsiDatabaseOpenViewA(hdb, query, &hview);
887     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
888 
889     /* check what the error function reports without doing anything */
890     sz = sizeof(buffer);
891     strcpy(buffer, "x");
892     err = MsiViewGetErrorA( hview, buffer, &sz );
893     ok(err == MSIDBERROR_NOERROR, "got %d\n", err);
894     ok(!buffer[0], "got \"%s\"\n", buffer);
895     ok(sz == 0, "got size %lu\n", sz);
896 
897     r = MsiViewExecute(hview, 0);
898     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
899 
900     /* try some invalid records */
901     r = MsiViewModify(hview, MSIMODIFY_INSERT, 0 );
902     ok(r == ERROR_INVALID_HANDLE, "MsiViewModify failed\n");
903     r = MsiViewModify(hview, -1, 0 );
904     ok(r == ERROR_INVALID_HANDLE, "MsiViewModify failed\n");
905 
906     /* try an small record */
907     hrec = MsiCreateRecord(1);
908     r = MsiViewModify(hview, -1, hrec );
909     ok(r == ERROR_INVALID_DATA, "MsiViewModify failed\n");
910 
911     sz = sizeof(buffer);
912     strcpy(buffer, "x");
913     err = MsiViewGetErrorA( hview, buffer, &sz );
914     ok(err == MSIDBERROR_NOERROR, "got %d\n", err);
915     ok(!buffer[0], "got \"%s\"\n", buffer);
916     ok(sz == 0, "got size %lu\n", sz);
917 
918     r = MsiCloseHandle(hrec);
919     ok(r == ERROR_SUCCESS, "failed to close record\n");
920 
921     /* insert a valid record */
922     hrec = MsiCreateRecord(3);
923 
924     r = MsiRecordSetInteger(hrec, 1, 1);
925     ok(r == ERROR_SUCCESS, "failed to set integer\n");
926     r = MsiRecordSetStringA(hrec, 2, "bob");
927     ok(r == ERROR_SUCCESS, "failed to set string\n");
928     r = MsiRecordSetStringA(hrec, 3, "7654321");
929     ok(r == ERROR_SUCCESS, "failed to set string\n");
930 
931     r = MsiViewExecute(hview, 0);
932     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
933     r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec );
934     ok(r == ERROR_SUCCESS, "MsiViewModify failed\n");
935 
936     /* validate it */
937     r = MsiViewExecute(hview, 0);
938     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
939 
940     r = MsiViewModify(hview, MSIMODIFY_VALIDATE_NEW, hrec );
941     ok(r == ERROR_INVALID_DATA, "MsiViewModify failed %u\n", r);
942 
943     sz = sizeof(buffer);
944     strcpy(buffer, "x");
945     err = MsiViewGetErrorA( hview, buffer, &sz );
946     ok(err == MSIDBERROR_DUPLICATEKEY, "got %d\n", err);
947     ok(!strcmp(buffer, "id"), "got \"%s\"\n", buffer);
948     ok(sz == 2, "got size %lu\n", sz);
949 
950     /* insert the same thing again */
951     r = MsiViewExecute(hview, 0);
952     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
953 
954     /* should fail ... */
955     r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec );
956     ok(r == ERROR_FUNCTION_FAILED, "MsiViewModify failed\n");
957 
958     /* try to merge the same record */
959     r = MsiViewExecute(hview, 0);
960     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
961     r = MsiViewModify(hview, MSIMODIFY_MERGE, hrec );
962     ok(r == ERROR_SUCCESS, "MsiViewModify failed\n");
963 
964     r = MsiCloseHandle(hrec);
965     ok(r == ERROR_SUCCESS, "failed to close record\n");
966 
967     /* try merging a new record */
968     hrec = MsiCreateRecord(3);
969 
970     r = MsiRecordSetInteger(hrec, 1, 10);
971     ok(r == ERROR_SUCCESS, "failed to set integer\n");
972     r = MsiRecordSetStringA(hrec, 2, "pepe");
973     ok(r == ERROR_SUCCESS, "failed to set string\n");
974     r = MsiRecordSetStringA(hrec, 3, "7654321");
975     ok(r == ERROR_SUCCESS, "failed to set string\n");
976 
977     r = MsiViewModify(hview, MSIMODIFY_MERGE, hrec );
978     ok(r == ERROR_SUCCESS, "MsiViewModify failed\n");
979     r = MsiViewExecute(hview, 0);
980     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
981 
982     r = MsiCloseHandle(hrec);
983     ok(r == ERROR_SUCCESS, "failed to close record\n");
984 
985     r = MsiViewClose(hview);
986     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
987     r = MsiCloseHandle(hview);
988     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
989 
990     query = "SELECT * FROM `phone`";
991     r = MsiDatabaseOpenViewA(hdb, query, &hview);
992     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
993 
994     r = MsiViewExecute(hview, 0);
995     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
996 
997     r = MsiViewFetch(hview, &hrec);
998     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
999     check_record(hrec, 3, "1", "bob", "7654321");
1000 
1001     /* update the view, non-primary key */
1002     r = MsiRecordSetStringA(hrec, 3, "3141592");
1003     ok(r == ERROR_SUCCESS, "MsiRecordSetString failed\n");
1004 
1005     r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
1006     ok(r == ERROR_SUCCESS, "MsiViewModify failed\n");
1007 
1008     /* do it again */
1009     r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
1010     ok(r == ERROR_SUCCESS, "MsiViewModify failed: %d\n", r);
1011 
1012     /* update the view, primary key */
1013     r = MsiRecordSetInteger(hrec, 1, 5);
1014     ok(r == ERROR_SUCCESS, "MsiRecordSetInteger failed\n");
1015 
1016     r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
1017     ok(r == ERROR_FUNCTION_FAILED, "MsiViewModify failed\n");
1018 
1019     r = MsiCloseHandle(hrec);
1020     ok(r == ERROR_SUCCESS, "failed to close record\n");
1021 
1022     r = MsiViewClose(hview);
1023     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
1024     r = MsiCloseHandle(hview);
1025     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
1026 
1027     query = "SELECT * FROM `phone`";
1028     r = MsiDatabaseOpenViewA(hdb, query, &hview);
1029     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
1030 
1031     r = MsiViewExecute(hview, 0);
1032     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
1033 
1034     r = MsiViewFetch(hview, &hrec);
1035     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
1036     check_record(hrec, 3, "1", "bob", "3141592");
1037     r = MsiCloseHandle(hrec);
1038     ok(r == ERROR_SUCCESS, "failed to close record\n");
1039 
1040     /* use a record that doesn't come from a view fetch */
1041     hrec = MsiCreateRecord(3);
1042     ok(hrec != 0, "MsiCreateRecord failed\n");
1043 
1044     r = MsiRecordSetInteger(hrec, 1, 3);
1045     ok(r == ERROR_SUCCESS, "failed to set integer\n");
1046     r = MsiRecordSetStringA(hrec, 2, "jane");
1047     ok(r == ERROR_SUCCESS, "failed to set string\n");
1048     r = MsiRecordSetStringA(hrec, 3, "112358");
1049     ok(r == ERROR_SUCCESS, "failed to set string\n");
1050 
1051     r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
1052     ok(r == ERROR_FUNCTION_FAILED, "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
1053 
1054     r = MsiCloseHandle(hrec);
1055     ok(r == ERROR_SUCCESS, "failed to close record\n");
1056 
1057     /* use a record that doesn't come from a view fetch, primary key matches */
1058     hrec = MsiCreateRecord(3);
1059     ok(hrec != 0, "MsiCreateRecord failed\n");
1060 
1061     r = MsiRecordSetInteger(hrec, 1, 1);
1062     ok(r == ERROR_SUCCESS, "failed to set integer\n");
1063     r = MsiRecordSetStringA(hrec, 2, "jane");
1064     ok(r == ERROR_SUCCESS, "failed to set string\n");
1065     r = MsiRecordSetStringA(hrec, 3, "112358");
1066     ok(r == ERROR_SUCCESS, "failed to set string\n");
1067 
1068     r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
1069     ok(r == ERROR_FUNCTION_FAILED, "MsiViewModify failed\n");
1070 
1071     r = MsiCloseHandle(hrec);
1072     ok(r == ERROR_SUCCESS, "failed to close record\n");
1073 
1074     hrec = MsiCreateRecord(3);
1075 
1076     r = MsiRecordSetInteger(hrec, 1, 2);
1077     ok(r == ERROR_SUCCESS, "failed to set integer\n");
1078     r = MsiRecordSetStringA(hrec, 2, "nick");
1079     ok(r == ERROR_SUCCESS, "failed to set string\n");
1080     r = MsiRecordSetStringA(hrec, 3, "141421");
1081     ok(r == ERROR_SUCCESS, "failed to set string\n");
1082 
1083     r = MsiViewExecute(hview, 0);
1084     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
1085     r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec );
1086     ok(r == ERROR_SUCCESS, "MsiViewModify failed\n");
1087 
1088     r = MsiCloseHandle(hrec);
1089     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
1090     r = MsiViewClose(hview);
1091     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
1092     r = MsiCloseHandle(hview);
1093     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
1094 
1095     query = "SELECT * FROM `phone` WHERE `id` = 1";
1096     r = MsiDatabaseOpenViewA(hdb, query, &hview);
1097     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
1098     r = MsiViewExecute(hview, 0);
1099     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
1100     r = MsiViewFetch(hview, &hrec);
1101     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
1102 
1103     /* change the id to match the second row */
1104     r = MsiRecordSetInteger(hrec, 1, 2);
1105     ok(r == ERROR_SUCCESS, "failed to set integer\n");
1106     r = MsiRecordSetStringA(hrec, 2, "jerry");
1107     ok(r == ERROR_SUCCESS, "failed to set string\n");
1108 
1109     r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
1110     ok(r == ERROR_FUNCTION_FAILED, "MsiViewModify failed\n");
1111 
1112     r = MsiCloseHandle(hrec);
1113     ok(r == ERROR_SUCCESS, "failed to close record\n");
1114     r = MsiViewClose(hview);
1115     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
1116     r = MsiCloseHandle(hview);
1117     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
1118 
1119     /* broader search */
1120     query = "SELECT * FROM `phone` ORDER BY `id`";
1121     r = MsiDatabaseOpenViewA(hdb, query, &hview);
1122     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
1123     r = MsiViewExecute(hview, 0);
1124     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
1125     r = MsiViewFetch(hview, &hrec);
1126     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
1127 
1128     /* change the id to match the second row */
1129     r = MsiRecordSetInteger(hrec, 1, 2);
1130     ok(r == ERROR_SUCCESS, "failed to set integer\n");
1131     r = MsiRecordSetStringA(hrec, 2, "jerry");
1132     ok(r == ERROR_SUCCESS, "failed to set string\n");
1133 
1134     r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
1135     ok(r == ERROR_FUNCTION_FAILED, "MsiViewModify failed\n");
1136 
1137     r = MsiCloseHandle(hrec);
1138     ok(r == ERROR_SUCCESS, "failed to close record\n");
1139     r = MsiViewClose(hview);
1140     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
1141     r = MsiCloseHandle(hview);
1142     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
1143 
1144     r = MsiCloseHandle( hdb );
1145     ok(r == ERROR_SUCCESS, "MsiOpenDatabase close failed\n");
1146 }
1147 
1148 static MSIHANDLE create_db(void)
1149 {
1150     MSIHANDLE hdb = 0;
1151     UINT res;
1152 
1153     DeleteFileW(msifileW);
1154 
1155     /* create an empty database */
1156     res = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb );
1157     ok( res == ERROR_SUCCESS , "Failed to create database\n" );
1158     if( res != ERROR_SUCCESS )
1159         return hdb;
1160 
1161     res = MsiDatabaseCommit( hdb );
1162     ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
1163 
1164     return hdb;
1165 }
1166 
1167 static void test_getcolinfo(void)
1168 {
1169     MSIHANDLE hdb, hview = 0, rec = 0;
1170     UINT r;
1171 
1172     /* create an empty db */
1173     hdb = create_db();
1174     ok( hdb, "failed to create db\n");
1175 
1176     /* tables should be present */
1177     r = MsiDatabaseOpenViewA(hdb, "select Name from _Tables", &hview);
1178     ok( r == ERROR_SUCCESS, "failed to open query\n");
1179 
1180     r = MsiViewExecute(hview, 0);
1181     ok( r == ERROR_SUCCESS, "failed to execute query\n");
1182 
1183     /* check that NAMES works */
1184     rec = 0;
1185     r = MsiViewGetColumnInfo( hview, MSICOLINFO_NAMES, &rec );
1186     ok( r == ERROR_SUCCESS, "failed to get names\n");
1187     check_record(rec, 1, "Name");
1188     r = MsiCloseHandle( rec );
1189     ok( r == ERROR_SUCCESS, "failed to close record handle\n");
1190 
1191     /* check that TYPES works */
1192     rec = 0;
1193     r = MsiViewGetColumnInfo( hview, MSICOLINFO_TYPES, &rec );
1194     ok( r == ERROR_SUCCESS, "failed to get names\n");
1195     check_record(rec, 1, "s64");
1196     r = MsiCloseHandle( rec );
1197     ok( r == ERROR_SUCCESS, "failed to close record handle\n");
1198 
1199     /* check that invalid values fail */
1200     rec = 0;
1201     r = MsiViewGetColumnInfo( hview, 100, &rec );
1202     ok( r == ERROR_INVALID_PARAMETER, "wrong error code\n");
1203     ok( rec == 0, "returned a record\n");
1204 
1205     r = MsiViewGetColumnInfo( hview, MSICOLINFO_TYPES, NULL );
1206     ok( r == ERROR_INVALID_PARAMETER, "wrong error code\n");
1207 
1208     r = MsiViewGetColumnInfo( 0, MSICOLINFO_TYPES, &rec );
1209     ok( r == ERROR_INVALID_HANDLE, "wrong error code\n");
1210 
1211     r = MsiViewClose(hview);
1212     ok( r == ERROR_SUCCESS, "failed to close view\n");
1213     r = MsiCloseHandle(hview);
1214     ok( r == ERROR_SUCCESS, "failed to close view handle\n");
1215     r = MsiCloseHandle(hdb);
1216     ok( r == ERROR_SUCCESS, "failed to close database\n");
1217 }
1218 
1219 static MSIHANDLE get_column_info(MSIHANDLE hdb, const char *query, MSICOLINFO type)
1220 {
1221     MSIHANDLE hview = 0, rec = 0;
1222     UINT r;
1223 
1224     r = MsiDatabaseOpenViewA(hdb, query, &hview);
1225     if( r != ERROR_SUCCESS )
1226         return r;
1227 
1228     r = MsiViewExecute(hview, 0);
1229     if( r == ERROR_SUCCESS )
1230     {
1231         MsiViewGetColumnInfo( hview, type, &rec );
1232     }
1233     MsiViewClose(hview);
1234     MsiCloseHandle(hview);
1235     return rec;
1236 }
1237 
1238 static UINT get_columns_table_type(MSIHANDLE hdb, const char *table, UINT field)
1239 {
1240     MSIHANDLE hview = 0, rec = 0;
1241     UINT r, type = 0;
1242     char query[0x100];
1243 
1244     sprintf(query, "select * from `_Columns` where  `Table` = '%s'", table );
1245 
1246     r = MsiDatabaseOpenViewA(hdb, query, &hview);
1247     if( r != ERROR_SUCCESS )
1248         return r;
1249 
1250     r = MsiViewExecute(hview, 0);
1251     if( r == ERROR_SUCCESS )
1252     {
1253         while (1)
1254         {
1255             r = MsiViewFetch( hview, &rec );
1256             if( r != ERROR_SUCCESS)
1257                 break;
1258             r = MsiRecordGetInteger( rec, 2 );
1259             if (r == field)
1260                 type = MsiRecordGetInteger( rec, 4 );
1261             MsiCloseHandle( rec );
1262         }
1263     }
1264     MsiViewClose(hview);
1265     MsiCloseHandle(hview);
1266     return type;
1267 }
1268 
1269 static void test_viewgetcolumninfo(void)
1270 {
1271     MSIHANDLE hdb = 0, rec;
1272     UINT r;
1273 
1274     hdb = create_db();
1275     ok( hdb, "failed to create db\n");
1276 
1277     r = run_query( hdb, 0,
1278             "CREATE TABLE `Properties` "
1279             "( `Property` CHAR(255), "
1280             "  `Value` CHAR(1), "
1281             "  `Intvalue` INT, "
1282             "  `Integervalue` INTEGER, "
1283             "  `Shortvalue` SHORT, "
1284             "  `Longvalue` LONG, "
1285             "  `Longcharvalue` LONGCHAR, "
1286             "  `Charvalue` CHAR, "
1287             "  `Localizablevalue` CHAR LOCALIZABLE "
1288             "  PRIMARY KEY `Property`)" );
1289     ok( r == ERROR_SUCCESS , "Failed to create table\n" );
1290 
1291     /* check the column types */
1292     rec = get_column_info( hdb, "select * from `Properties`", MSICOLINFO_TYPES );
1293     ok( rec, "failed to get column info record\n" );
1294     check_record(rec, 9, "S255", "S1", "I2", "I2", "I2", "I4", "S0", "S0", "L0");
1295     MsiCloseHandle( rec );
1296 
1297     /* check the type in _Columns */
1298     ok( 0x3dff == get_columns_table_type(hdb, "Properties", 1 ), "_columns table wrong\n");
1299     ok( 0x1d01 == get_columns_table_type(hdb, "Properties", 2 ), "_columns table wrong\n");
1300     ok( 0x1502 == get_columns_table_type(hdb, "Properties", 3 ), "_columns table wrong\n");
1301     ok( 0x1502 == get_columns_table_type(hdb, "Properties", 4 ), "_columns table wrong\n");
1302     ok( 0x1502 == get_columns_table_type(hdb, "Properties", 5 ), "_columns table wrong\n");
1303     ok( 0x1104 == get_columns_table_type(hdb, "Properties", 6 ), "_columns table wrong\n");
1304     ok( 0x1d00 == get_columns_table_type(hdb, "Properties", 7 ), "_columns table wrong\n");
1305     ok( 0x1d00 == get_columns_table_type(hdb, "Properties", 8 ), "_columns table wrong\n");
1306     ok( 0x1f00 == get_columns_table_type(hdb, "Properties", 9 ), "_columns table wrong\n");
1307 
1308     /* now try the names */
1309     rec = get_column_info( hdb, "select * from `Properties`", MSICOLINFO_NAMES );
1310     ok( rec, "failed to get column info record\n" );
1311     check_record(rec, 9, "Property", "Value", "Intvalue", "Integervalue", "Shortvalue",
1312             "Longvalue", "Longcharvalue", "Charvalue", "Localizablevalue");
1313     MsiCloseHandle( rec );
1314 
1315     r = run_query( hdb, 0,
1316             "CREATE TABLE `Binary` "
1317             "( `Name` CHAR(255), `Data` OBJECT  PRIMARY KEY `Name`)" );
1318     ok( r == ERROR_SUCCESS , "Failed to create table\n" );
1319 
1320     /* check the column types */
1321     rec = get_column_info( hdb, "select * from `Binary`", MSICOLINFO_TYPES );
1322     ok( rec, "failed to get column info record\n" );
1323     check_record(rec, 2, "S255", "V0");
1324     MsiCloseHandle( rec );
1325 
1326     /* check the type in _Columns */
1327     ok( 0x3dff == get_columns_table_type(hdb, "Binary", 1 ), "_columns table wrong\n");
1328     ok( 0x1900 == get_columns_table_type(hdb, "Binary", 2 ), "_columns table wrong\n");
1329 
1330     /* now try the names */
1331     rec = get_column_info( hdb, "select * from `Binary`", MSICOLINFO_NAMES );
1332     ok( rec, "failed to get column info record\n" );
1333     check_record(rec, 2, "Name", "Data");
1334     MsiCloseHandle( rec );
1335 
1336     r = run_query( hdb, 0,
1337             "CREATE TABLE `UIText` "
1338             "( `Key` CHAR(72) NOT NULL, `Text` CHAR(255) LOCALIZABLE PRIMARY KEY `Key`)" );
1339     ok( r == ERROR_SUCCESS , "Failed to create table\n" );
1340 
1341     ok( 0x2d48 == get_columns_table_type(hdb, "UIText", 1 ), "_columns table wrong\n");
1342     ok( 0x1fff == get_columns_table_type(hdb, "UIText", 2 ), "_columns table wrong\n");
1343 
1344     rec = get_column_info( hdb, "select * from `UIText`", MSICOLINFO_NAMES );
1345     ok( rec, "failed to get column info record\n" );
1346     check_record(rec, 2, "Key", "Text");
1347     MsiCloseHandle( rec );
1348 
1349     rec = get_column_info( hdb, "select * from `UIText`", MSICOLINFO_TYPES );
1350     ok( rec, "failed to get column info record\n" );
1351     check_record(rec, 2, "s72", "L255");
1352     MsiCloseHandle( rec );
1353 
1354     MsiCloseHandle( hdb );
1355 }
1356 
1357 static void test_msiexport(void)
1358 {
1359     MSIHANDLE hdb = 0, hview = 0;
1360     UINT r;
1361     const char *query;
1362     char path[MAX_PATH];
1363     const char file[] = "phone.txt";
1364     HANDLE handle;
1365     char buffer[0x100];
1366     DWORD length;
1367     const char expected[] =
1368         "id\tname\tnumber\r\n"
1369         "I2\tS32\tS32\r\n"
1370         "phone\tid\r\n"
1371         "1\tAbe\t8675309\r\n";
1372 
1373     DeleteFileW(msifileW);
1374 
1375     /* just MsiOpenDatabase should not create a file */
1376     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
1377     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
1378 
1379     /* create a table */
1380     query = "CREATE TABLE `phone` ( "
1381             "`id` INT, `name` CHAR(32), `number` CHAR(32) "
1382             "PRIMARY KEY `id`)";
1383     r = MsiDatabaseOpenViewA(hdb, query, &hview);
1384     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
1385     r = MsiViewExecute(hview, 0);
1386     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
1387     r = MsiViewClose(hview);
1388     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
1389     r = MsiCloseHandle(hview);
1390     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
1391 
1392     /* insert a value into it */
1393     query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
1394         "VALUES('1', 'Abe', '8675309')";
1395     r = MsiDatabaseOpenViewA(hdb, query, &hview);
1396     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
1397     r = MsiViewExecute(hview, 0);
1398     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
1399     r = MsiViewClose(hview);
1400     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
1401     r = MsiCloseHandle(hview);
1402     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
1403 
1404     GetCurrentDirectoryA(MAX_PATH, path);
1405 
1406     r = MsiDatabaseExportA(hdb, "phone", path, file);
1407     ok(r == ERROR_SUCCESS, "MsiDatabaseExport failed\n");
1408 
1409     MsiCloseHandle(hdb);
1410 
1411     lstrcatA(path, "\\");
1412     lstrcatA(path, file);
1413 
1414     /* check the data that was written */
1415     length = 0;
1416     memset(buffer, 0, sizeof buffer);
1417     handle = CreateFileA(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
1418     if (handle != INVALID_HANDLE_VALUE)
1419     {
1420         ReadFile(handle, buffer, sizeof buffer, &length, NULL);
1421         CloseHandle(handle);
1422         DeleteFileA(path);
1423     }
1424     else
1425         ok(0, "failed to open file %s\n", path);
1426 
1427     ok( length == strlen(expected), "length of data wrong\n");
1428     ok( !lstrcmpA(buffer, expected), "data doesn't match\n");
1429     DeleteFileA(msifile);
1430 }
1431 
1432 static void test_longstrings(void)
1433 {
1434     const char insert_query[] =
1435         "INSERT INTO `strings` ( `id`, `val` ) VALUES('1', 'Z')";
1436     char *str;
1437     MSIHANDLE hdb = 0, hview = 0, hrec = 0;
1438     DWORD len;
1439     UINT r;
1440     const DWORD STRING_LENGTH = 0x10005;
1441 
1442     DeleteFileW(msifileW);
1443     /* just MsiOpenDatabase should not create a file */
1444     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
1445     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
1446 
1447     /* create a table */
1448     r = try_query( hdb,
1449         "CREATE TABLE `strings` ( `id` INT, `val` CHAR(0) PRIMARY KEY `id`)");
1450     ok(r == ERROR_SUCCESS, "query failed\n");
1451 
1452     /* try to insert a very long string */
1453     str = malloc(STRING_LENGTH + sizeof insert_query);
1454     len = strchr(insert_query, 'Z') - insert_query;
1455     strcpy(str, insert_query);
1456     memset(str+len, 'Z', STRING_LENGTH);
1457     strcpy(str+len+STRING_LENGTH, insert_query+len+1);
1458     r = try_query( hdb, str );
1459     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
1460     free(str);
1461 
1462     r = MsiDatabaseCommit(hdb);
1463     ok(r == ERROR_SUCCESS, "MsiDatabaseCommit failed\n");
1464     MsiCloseHandle(hdb);
1465 
1466     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_READONLY, &hdb);
1467     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
1468 
1469     r = MsiDatabaseOpenViewA(hdb, "select * from `strings` where `id` = 1", &hview);
1470     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
1471 
1472     r = MsiViewExecute(hview, 0);
1473     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
1474 
1475     r = MsiViewFetch(hview, &hrec);
1476     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
1477 
1478     MsiViewClose(hview);
1479     MsiCloseHandle(hview);
1480 
1481     r = MsiRecordGetStringA(hrec, 2, NULL, &len);
1482     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
1483     ok(len == STRING_LENGTH, "string length wrong\n");
1484 
1485     MsiCloseHandle(hrec);
1486     MsiCloseHandle(hdb);
1487     DeleteFileA(msifile);
1488 }
1489 
1490 static void test_streamtable(void)
1491 {
1492     MSIHANDLE hdb = 0, rec, view, hsi;
1493     char file[MAX_PATH];
1494     char buf[MAX_PATH];
1495     DWORD size;
1496     UINT r;
1497 
1498     hdb = create_db();
1499     ok( hdb, "failed to create db\n");
1500 
1501     r = run_query( hdb, 0,
1502             "CREATE TABLE `Properties` "
1503             "( `Property` CHAR(255), `Value` CHAR(1)  PRIMARY KEY `Property`)" );
1504     ok( r == ERROR_SUCCESS , "Failed to create table\n" );
1505 
1506     r = run_query( hdb, 0,
1507             "INSERT INTO `Properties` "
1508             "( `Value`, `Property` ) VALUES ( 'Prop', 'value' )" );
1509     ok( r == ERROR_SUCCESS, "Failed to add to table\n" );
1510 
1511     r = MsiDatabaseCommit( hdb );
1512     ok( r == ERROR_SUCCESS , "Failed to commit database\n" );
1513 
1514     MsiCloseHandle( hdb );
1515 
1516     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_TRANSACT, &hdb );
1517     ok( r == ERROR_SUCCESS , "Failed to open database\n" );
1518 
1519     /* check the column types */
1520     rec = get_column_info( hdb, "select * from `_Streams`", MSICOLINFO_TYPES );
1521     ok( rec, "failed to get column info record\n" );
1522     check_record(rec, 2, "s62", "V0");
1523     MsiCloseHandle( rec );
1524 
1525     /* now try the names */
1526     rec = get_column_info( hdb, "select * from `_Streams`", MSICOLINFO_NAMES );
1527     ok( rec, "failed to get column info record\n" );
1528     check_record(rec, 2, "Name", "Data");
1529     MsiCloseHandle( rec );
1530 
1531     r = MsiDatabaseOpenViewA( hdb,
1532             "SELECT * FROM `_Streams` WHERE `Name` = '\5SummaryInformation'", &view );
1533     ok( r == ERROR_SUCCESS, "Failed to open database view: %u\n", r );
1534 
1535     r = MsiViewExecute( view, 0 );
1536     ok( r == ERROR_SUCCESS, "Failed to execute view: %u\n", r );
1537 
1538     r = MsiViewFetch( view, &rec );
1539     ok( r == ERROR_NO_MORE_ITEMS, "Unexpected result: %u\n", r );
1540 
1541     MsiCloseHandle( rec );
1542     MsiViewClose( view );
1543     MsiCloseHandle( view );
1544 
1545     /* create a summary information stream */
1546     r = MsiGetSummaryInformationA( hdb, NULL, 1, &hsi );
1547     ok( r == ERROR_SUCCESS, "Failed to get summary information handle: %u\n", r );
1548 
1549     r = MsiSummaryInfoSetPropertyA( hsi, PID_SECURITY, VT_I4, 2, NULL, NULL );
1550     ok( r == ERROR_SUCCESS, "Failed to set property: %u\n", r );
1551 
1552     r = MsiSummaryInfoPersist( hsi );
1553     ok( r == ERROR_SUCCESS, "Failed to save summary information: %u\n", r );
1554 
1555     MsiCloseHandle( hsi );
1556 
1557     r = MsiDatabaseOpenViewA( hdb,
1558             "SELECT * FROM `_Streams` WHERE `Name` = '\5SummaryInformation'", &view );
1559     ok( r == ERROR_SUCCESS, "Failed to open database view: %u\n", r );
1560 
1561     r = MsiViewExecute( view, 0 );
1562     ok( r == ERROR_SUCCESS, "Failed to execute view: %u\n", r );
1563 
1564     r = MsiViewFetch( view, &rec );
1565     ok( r == ERROR_SUCCESS, "Unexpected result: %u\n", r );
1566 
1567     MsiCloseHandle( rec );
1568     MsiViewClose( view );
1569     MsiCloseHandle( view );
1570 
1571     /* insert a file into the _Streams table */
1572     create_file( "test.txt", 0 );
1573 
1574     rec = MsiCreateRecord( 2 );
1575     MsiRecordSetStringA( rec, 1, "data" );
1576 
1577     r = MsiRecordSetStreamA( rec, 2, "test.txt" );
1578     ok( r == ERROR_SUCCESS, "Failed to add stream data to the record: %d\n", r);
1579 
1580     DeleteFileA("test.txt");
1581 
1582     r = MsiDatabaseOpenViewA( hdb,
1583             "INSERT INTO `_Streams` ( `Name`, `Data` ) VALUES ( ?, ? )", &view );
1584     ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r);
1585 
1586     r = MsiViewExecute( view, rec );
1587     ok( r == ERROR_SUCCESS, "Failed to execute view: %d\n", r);
1588 
1589     MsiCloseHandle( rec );
1590     MsiViewClose( view );
1591     MsiCloseHandle( view );
1592 
1593     /* insert another one */
1594     create_file( "test1.txt", 0 );
1595 
1596     rec = MsiCreateRecord( 2 );
1597     MsiRecordSetStringA( rec, 1, "data1" );
1598 
1599     r = MsiRecordSetStreamA( rec, 2, "test1.txt" );
1600     ok( r == ERROR_SUCCESS, "Failed to add stream data to the record: %d\n", r);
1601 
1602     DeleteFileA("test1.txt");
1603 
1604     r = MsiDatabaseOpenViewA( hdb,
1605             "INSERT INTO `_Streams` ( `Name`, `Data` ) VALUES ( ?, ? )", &view );
1606     ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r);
1607 
1608     r = MsiViewExecute( view, rec );
1609     ok( r == ERROR_SUCCESS, "Failed to execute view: %d\n", r);
1610 
1611     MsiCloseHandle( rec );
1612     MsiViewClose( view );
1613     MsiCloseHandle( view );
1614 
1615     /* try again */
1616     create_file( "test1.txt", 0 );
1617 
1618     rec = MsiCreateRecord( 2 );
1619     MsiRecordSetStringA( rec, 1, "data1" );
1620 
1621     r = MsiRecordSetStreamA( rec, 2, "test1.txt" );
1622     ok( r == ERROR_SUCCESS, "Failed to add stream data to the record: %d\n", r );
1623 
1624     DeleteFileA( "test1.txt" );
1625 
1626     r = MsiDatabaseOpenViewA( hdb,
1627             "INSERT INTO `_Streams` ( `Name`, `Data` ) VALUES ( ?, ? )", &view );
1628     ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r );
1629 
1630     r = MsiViewExecute( view, rec );
1631     ok( r == ERROR_FUNCTION_FAILED, "got %u\n", r );
1632 
1633     MsiCloseHandle( rec );
1634     MsiViewClose( view );
1635     MsiCloseHandle( view );
1636 
1637     r = MsiDatabaseOpenViewA( hdb,
1638             "SELECT `Name`, `Data` FROM `_Streams` WHERE `Name` = 'data'", &view );
1639     ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r);
1640 
1641     r = MsiViewExecute( view, 0 );
1642     ok( r == ERROR_SUCCESS, "Failed to execute view: %d\n", r);
1643 
1644     r = MsiViewFetch( view, &rec );
1645     ok( r == ERROR_SUCCESS, "Failed to fetch record: %d\n", r);
1646 
1647     size = MAX_PATH;
1648     r = MsiRecordGetStringA( rec, 1, file, &size );
1649     ok( r == ERROR_SUCCESS, "Failed to get string: %d\n", r);
1650     ok( !lstrcmpA(file, "data"), "Expected 'data', got %s\n", file);
1651 
1652     size = MAX_PATH;
1653     memset(buf, 0, MAX_PATH);
1654     r = MsiRecordReadStream( rec, 2, buf, &size );
1655     ok( r == ERROR_SUCCESS, "Failed to get stream: %d\n", r);
1656     ok( !lstrcmpA(buf, "test.txt"), "Expected 'test.txt', got %s\n", buf);
1657 
1658     MsiCloseHandle( rec );
1659     MsiViewClose( view );
1660     MsiCloseHandle( view );
1661 
1662     r = MsiDatabaseOpenViewA( hdb,
1663             "SELECT `Name`, `Data` FROM `_Streams` WHERE `Name` = 'data1'", &view );
1664     ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r);
1665 
1666     r = MsiViewExecute( view, 0 );
1667     ok( r == ERROR_SUCCESS, "Failed to execute view: %d\n", r);
1668 
1669     r = MsiViewFetch( view, &rec );
1670     ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1671 
1672     size = MAX_PATH;
1673     r = MsiRecordGetStringA( rec, 1, file, &size );
1674     ok( r == ERROR_SUCCESS, "Failed to get string: %d\n", r);
1675     ok( !lstrcmpA(file, "data1"), "Expected 'data1', got %s\n", file);
1676 
1677     size = MAX_PATH;
1678     memset(buf, 0, MAX_PATH);
1679     r = MsiRecordReadStream( rec, 2, buf, &size );
1680     ok( r == ERROR_SUCCESS, "Failed to get stream: %d\n", r);
1681     ok( !lstrcmpA(buf, "test1.txt"), "Expected 'test1.txt', got %s\n", buf);
1682 
1683     MsiCloseHandle( rec );
1684     MsiViewClose( view );
1685     MsiCloseHandle( view );
1686 
1687     /* perform an update */
1688     create_file( "test2.txt", 0 );
1689     rec = MsiCreateRecord( 1 );
1690 
1691     r = MsiRecordSetStreamA( rec, 1, "test2.txt" );
1692     ok( r == ERROR_SUCCESS, "Failed to add stream data to the record: %d\n", r);
1693 
1694     DeleteFileA("test2.txt");
1695 
1696     r = MsiDatabaseOpenViewA( hdb,
1697             "UPDATE `_Streams` SET `Data` = ? WHERE `Name` = 'data1'", &view );
1698     ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r);
1699 
1700     r = MsiViewExecute( view, rec );
1701     ok( r == ERROR_SUCCESS, "Failed to execute view: %d\n", r);
1702 
1703     MsiCloseHandle( rec );
1704     MsiViewClose( view );
1705     MsiCloseHandle( view );
1706 
1707     r = MsiDatabaseOpenViewA( hdb,
1708             "SELECT `Name`, `Data` FROM `_Streams` WHERE `Name` = 'data1'", &view );
1709     ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r);
1710 
1711     r = MsiViewExecute( view, 0 );
1712     ok( r == ERROR_SUCCESS, "Failed to execute view: %d\n", r);
1713 
1714     r = MsiViewFetch( view, &rec );
1715     ok( r == ERROR_SUCCESS, "Failed to fetch record: %d\n", r);
1716 
1717     size = MAX_PATH;
1718     r = MsiRecordGetStringA( rec, 1, file, &size );
1719     ok( r == ERROR_SUCCESS, "Failed to get string: %d\n", r);
1720     ok( !lstrcmpA(file, "data1"), "Expected 'data1', got %s\n", file);
1721 
1722     size = MAX_PATH;
1723     memset(buf, 0, MAX_PATH);
1724     r = MsiRecordReadStream( rec, 2, buf, &size );
1725     ok( r == ERROR_SUCCESS, "Failed to get stream: %d\n", r);
1726     ok( !lstrcmpA(buf, "test2.txt"), "Expected 'test2.txt', got %s\n", buf);
1727 
1728     MsiCloseHandle( rec );
1729     MsiViewClose( view );
1730     MsiCloseHandle( view );
1731     MsiCloseHandle( hdb );
1732     DeleteFileA(msifile);
1733 
1734     /* insert a file into the _Streams table */
1735     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATEDIRECT, &hdb);
1736     ok(r == ERROR_SUCCESS, "Failed to create database\n");
1737     ok( hdb, "failed to create db\n");
1738     create_file( "test.txt", 0 );
1739     rec = MsiCreateRecord( 2 );
1740     MsiRecordSetStringA( rec, 1, "data" );
1741     r = MsiRecordSetStreamA( rec, 2, "test.txt" );
1742     ok( r == ERROR_SUCCESS, "Failed to add stream data to the record: %d\n", r);
1743     DeleteFileA("test.txt");
1744     r = MsiDatabaseOpenViewA( hdb,
1745             "INSERT INTO `_Streams` ( `Name`, `Data` ) VALUES ( ?, ? )", &view );
1746     ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r);
1747     r = MsiViewExecute( view, rec );
1748     ok( r == ERROR_SUCCESS, "Failed to execute view: %d\n", r);
1749     MsiCloseHandle( rec );
1750     MsiViewClose( view );
1751     MsiCloseHandle( view );
1752     r = MsiDatabaseCommit( hdb );
1753     ok( r == ERROR_SUCCESS , "Failed to commit database\n" );
1754 
1755     /* open a handle to the "data" stream */
1756     r = MsiDatabaseOpenViewA( hdb,
1757             "SELECT `Name`, `Data` FROM `_Streams` WHERE `Name` = 'data'", &view );
1758     ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r);
1759     r = MsiViewExecute( view, 0 );
1760     ok( r == ERROR_SUCCESS, "Failed to execute view: %d\n", r);
1761     r = MsiViewFetch( view, &rec );
1762     ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1763     MsiViewClose( view );
1764     MsiCloseHandle( view );
1765     /* read the stream while it still exists (normal case) */
1766     size = MAX_PATH;
1767     r = MsiRecordGetStringA( rec, 1, file, &size );
1768     ok( r == ERROR_SUCCESS, "Failed to get string: %d\n", r);
1769     ok( !lstrcmpA(file, "data"), "Expected 'data', got %s\n", file);
1770     size = MAX_PATH;
1771     memset(buf, 0, MAX_PATH);
1772     r = MsiRecordReadStream( rec, 2, buf, &size );
1773     ok( r == ERROR_SUCCESS, "Failed to get stream: %d\n", r);
1774     ok( !lstrcmpA(buf, "test.txt"), "Expected 'test.txt', got '%s' (%lu)\n", buf, size);
1775     MsiCloseHandle( rec );
1776 
1777     /* open a handle to the "data" stream (and keep it open during removal) */
1778     r = MsiDatabaseOpenViewA( hdb,
1779             "SELECT `Name`, `Data` FROM `_Streams` WHERE `Name` = 'data'", &view );
1780     ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r);
1781     r = MsiViewExecute( view, 0 );
1782     ok( r == ERROR_SUCCESS, "Failed to execute view: %d\n", r);
1783     r = MsiViewFetch( view, &rec );
1784     ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1785     MsiViewClose( view );
1786     MsiCloseHandle( view );
1787 
1788     /* remove the stream */
1789     r = MsiDatabaseOpenViewA( hdb,
1790             "DELETE FROM `_Streams` WHERE `Name` = 'data'", &view );
1791     ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r);
1792     r = MsiViewExecute( view, 0 );
1793     ok( r == ERROR_SUCCESS, "Failed to execute view: %d\n", r);
1794     MsiViewClose( view );
1795     MsiCloseHandle( view );
1796 
1797     /* attempt to read the stream that no longer exists (abnormal case) */
1798     size = MAX_PATH;
1799     r = MsiRecordGetStringA( rec, 1, file, &size );
1800     ok( r == ERROR_SUCCESS, "Failed to get string: %d\n", r);
1801     ok( !lstrcmpA(file, "data"), "Expected 'data', got %s\n", file);
1802     size = MAX_PATH;
1803     memset(buf, 0, MAX_PATH);
1804     r = MsiRecordReadStream( rec, 2, buf, &size );
1805     ok( r == ERROR_SUCCESS, "Failed to get stream: %d\n", r);
1806     todo_wine ok( size == 0, "Expected empty buffer, got %lu bytes\n", size);
1807     MsiCloseHandle( rec );
1808 
1809     MsiCloseHandle( hdb );
1810     DeleteFileA(msifile);
1811 }
1812 
1813 static void test_binary(void)
1814 {
1815     MSIHANDLE hdb = 0, rec;
1816     char file[MAX_PATH];
1817     char buf[MAX_PATH];
1818     DWORD size;
1819     LPCSTR query;
1820     UINT r;
1821 
1822     /* insert a file into the Binary table */
1823     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb );
1824     ok( r == ERROR_SUCCESS , "Failed to open database\n" );
1825 
1826     query = "CREATE TABLE `Binary` ( `Name` CHAR(72) NOT NULL, `ID` INT NOT NULL, `Data` OBJECT  PRIMARY KEY `Name`, `ID`)";
1827     r = run_query( hdb, 0, query );
1828     ok( r == ERROR_SUCCESS, "Cannot create Binary table: %d\n", r );
1829 
1830     create_file( "test.txt", 0 );
1831     rec = MsiCreateRecord( 1 );
1832     r = MsiRecordSetStreamA( rec, 1, "test.txt" );
1833     ok( r == ERROR_SUCCESS, "Failed to add stream data to the record: %d\n", r);
1834     DeleteFileA( "test.txt" );
1835 
1836     /* try a name that exceeds maximum OLE stream name length */
1837     query = "INSERT INTO `Binary` ( `Name`, `ID`, `Data` ) VALUES ( 'encryption.dll.CB4E6205_F99A_4C51_ADD4_184506EFAB87', 10000, ? )";
1838     r = run_query( hdb, rec, query );
1839     ok( r == ERROR_SUCCESS, "Insert into Binary table failed: %d\n", r );
1840 
1841     r = MsiCloseHandle( rec );
1842     ok( r == ERROR_SUCCESS , "Failed to close record handle\n" );
1843 
1844     r = MsiDatabaseCommit( hdb );
1845     ok( r == ERROR_FUNCTION_FAILED , "got %u\n", r );
1846 
1847     r = MsiCloseHandle( hdb );
1848     ok( r == ERROR_SUCCESS , "Failed to close database\n" );
1849 
1850     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb );
1851     ok( r == ERROR_SUCCESS , "Failed to open database\n" );
1852 
1853     query = "CREATE TABLE `Binary` ( `Name` CHAR(72) NOT NULL, `ID` INT NOT NULL, `Data` OBJECT  PRIMARY KEY `Name`, `ID`)";
1854     r = run_query( hdb, 0, query );
1855     ok( r == ERROR_SUCCESS, "Cannot create Binary table: %d\n", r );
1856 
1857     create_file( "test.txt", 0 );
1858     rec = MsiCreateRecord( 1 );
1859     r = MsiRecordSetStreamA( rec, 1, "test.txt" );
1860     ok( r == ERROR_SUCCESS, "Failed to add stream data to the record: %d\n", r );
1861     DeleteFileA( "test.txt" );
1862 
1863     query = "INSERT INTO `Binary` ( `Name`, `ID`, `Data` ) VALUES ( 'filename1', 1, ? )";
1864     r = run_query( hdb, rec, query );
1865     ok( r == ERROR_SUCCESS, "Insert into Binary table failed: %d\n", r );
1866 
1867     query = "INSERT INTO `Binary` ( `Name`, `ID`, `Data` ) VALUES ( 'filename1', 1, ? )";
1868     r = run_query( hdb, rec, query );
1869     ok( r == ERROR_FUNCTION_FAILED, "got %u\n", r );
1870 
1871     r = MsiCloseHandle( rec );
1872     ok( r == ERROR_SUCCESS , "Failed to close record handle\n" );
1873 
1874     r = MsiDatabaseCommit( hdb );
1875     ok( r == ERROR_SUCCESS , "Failed to commit database\n" );
1876 
1877     r = MsiCloseHandle( hdb );
1878     ok( r == ERROR_SUCCESS , "Failed to close database\n" );
1879 
1880     /* read file from the Stream table */
1881     r = MsiOpenDatabaseW( msifileW, MSIDBOPEN_READONLY, &hdb );
1882     ok( r == ERROR_SUCCESS , "Failed to open database\n" );
1883 
1884     query = "SELECT * FROM `_Streams`";
1885     r = do_query( hdb, query, &rec );
1886     ok( r == ERROR_SUCCESS, "SELECT query failed: %d\n", r );
1887 
1888     size = MAX_PATH;
1889     r = MsiRecordGetStringA( rec, 1, file, &size );
1890     ok( r == ERROR_SUCCESS, "Failed to get string: %d\n", r );
1891     ok( !lstrcmpA(file, "Binary.filename1.1"), "Expected 'Binary.filename1.1', got %s\n", file );
1892 
1893     size = MAX_PATH;
1894     memset( buf, 0, MAX_PATH );
1895     r = MsiRecordReadStream( rec, 2, buf, &size );
1896     ok( r == ERROR_SUCCESS, "Failed to get stream: %d\n", r );
1897     ok( !lstrcmpA(buf, "test.txt"), "Expected 'test.txt', got %s\n", buf );
1898 
1899     r = MsiCloseHandle( rec );
1900     ok( r == ERROR_SUCCESS , "Failed to close record handle\n" );
1901 
1902     /* read file from the Binary table */
1903     query = "SELECT * FROM `Binary`";
1904     r = do_query( hdb, query, &rec );
1905     ok( r == ERROR_SUCCESS, "SELECT query failed: %d\n", r );
1906 
1907     size = MAX_PATH;
1908     r = MsiRecordGetStringA( rec, 1, file, &size );
1909     ok( r == ERROR_SUCCESS, "Failed to get string: %d\n", r );
1910     ok( !lstrcmpA(file, "filename1"), "Expected 'filename1', got %s\n", file );
1911 
1912     size = MAX_PATH;
1913     memset( buf, 0, MAX_PATH );
1914     r = MsiRecordReadStream( rec, 3, buf, &size );
1915     ok( r == ERROR_SUCCESS, "Failed to get stream: %d\n", r );
1916     ok( !lstrcmpA(buf, "test.txt"), "Expected 'test.txt', got %s\n", buf );
1917 
1918     r = MsiCloseHandle( rec );
1919     ok( r == ERROR_SUCCESS , "Failed to close record handle\n" );
1920 
1921     r = MsiCloseHandle( hdb );
1922     ok( r == ERROR_SUCCESS , "Failed to close database\n" );
1923 
1924     DeleteFileA( msifile );
1925 }
1926 
1927 static void test_where_not_in_selected(void)
1928 {
1929     MSIHANDLE hdb = 0, rec, view;
1930     LPCSTR query;
1931     UINT r;
1932 
1933     hdb = create_db();
1934     ok( hdb, "failed to create db\n");
1935 
1936     r = run_query(hdb, 0,
1937             "CREATE TABLE `IESTable` ("
1938             "`Action` CHAR(64), "
1939             "`Condition` CHAR(64), "
1940             "`Sequence` LONG PRIMARY KEY `Sequence`)");
1941     ok( r == S_OK, "Cannot create IESTable table: %d\n", r);
1942 
1943     r = run_query(hdb, 0,
1944             "CREATE TABLE `CATable` ("
1945             "`Action` CHAR(64), "
1946             "`Type` LONG PRIMARY KEY `Type`)");
1947     ok( r == S_OK, "Cannot create CATable table: %d\n", r);
1948 
1949     r = run_query(hdb, 0, "INSERT INTO `IESTable` "
1950             "( `Action`, `Condition`, `Sequence`) "
1951             "VALUES ( 'clean', 'cond4', 4)");
1952     ok( r == S_OK, "cannot add entry to IESTable table:%d\n", r );
1953 
1954     r = run_query(hdb, 0, "INSERT INTO `IESTable` "
1955             "( `Action`, `Condition`, `Sequence`) "
1956             "VALUES ( 'depends', 'cond1', 1)");
1957     ok( r == S_OK, "cannot add entry to IESTable table:%d\n", r );
1958 
1959     r = run_query(hdb, 0, "INSERT INTO `IESTable` "
1960             "( `Action`, `Condition`, `Sequence`) "
1961             "VALUES ( 'build', 'cond2', 2)");
1962     ok( r == S_OK, "cannot add entry to IESTable table:%d\n", r );
1963 
1964     r = run_query(hdb, 0, "INSERT INTO `IESTable` "
1965             "( `Action`, `Condition`, `Sequence`) "
1966             "VALUES ( 'build2', 'cond6', 6)");
1967     ok( r == S_OK, "cannot add entry to IESTable table:%d\n", r );
1968 
1969     r = run_query(hdb, 0, "INSERT INTO `IESTable` "
1970             "( `Action`, `Condition`, `Sequence`) "
1971             "VALUES ( 'build', 'cond3', 3)");
1972     ok(r == S_OK, "cannot add entry to IESTable table:%d\n", r );
1973 
1974     r = run_query(hdb, 0, "INSERT INTO `CATable` "
1975             "( `Action`, `Type` ) "
1976             "VALUES ( 'build', 32)");
1977     ok(r == S_OK, "cannot add entry to CATable table:%d\n", r );
1978 
1979     r = run_query(hdb, 0, "INSERT INTO `CATable` "
1980             "( `Action`, `Type` ) "
1981             "VALUES ( 'depends', 64)");
1982     ok(r == S_OK, "cannot add entry to CATable table:%d\n", r );
1983 
1984     r = run_query(hdb, 0, "INSERT INTO `CATable` "
1985             "( `Action`, `Type` ) "
1986             "VALUES ( 'clean', 63)");
1987     ok(r == S_OK, "cannot add entry to CATable table:%d\n", r );
1988 
1989     r = run_query(hdb, 0, "INSERT INTO `CATable` "
1990             "( `Action`, `Type` ) "
1991             "VALUES ( 'build2', 34)");
1992     ok(r == S_OK, "cannot add entry to CATable table:%d\n", r );
1993     query = "Select IESTable.Condition from CATable, IESTable where "
1994             "CATable.Action = IESTable.Action and CATable.Type = 32";
1995     r = MsiDatabaseOpenViewA(hdb, query, &view);
1996     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
1997 
1998     r = MsiViewExecute(view, 0);
1999     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
2000 
2001     r = MsiViewFetch(view, &rec);
2002     ok( r == ERROR_SUCCESS, "failed to fetch view: %d\n", r );
2003     check_record(rec, 1, "cond2");
2004     MsiCloseHandle( rec );
2005 
2006     r = MsiViewFetch(view, &rec);
2007     ok( r == ERROR_SUCCESS, "failed to fetch view: %d\n", r );
2008     check_record(rec, 1, "cond3");
2009     MsiCloseHandle( rec );
2010 
2011     MsiViewClose(view);
2012     MsiCloseHandle(view);
2013 
2014     MsiCloseHandle( hdb );
2015     DeleteFileA(msifile);
2016 }
2017 
2018 
2019 static void test_where(void)
2020 {
2021     MSIHANDLE hdb = 0, rec, view;
2022     LPCSTR query;
2023     UINT r;
2024 
2025     hdb = create_db();
2026     ok( hdb, "failed to create db\n");
2027 
2028     r = run_query( hdb, 0,
2029             "CREATE TABLE `Media` ("
2030             "`DiskId` SHORT NOT NULL, "
2031             "`LastSequence` LONG, "
2032             "`DiskPrompt` CHAR(64) LOCALIZABLE, "
2033             "`Cabinet` CHAR(255), "
2034             "`VolumeLabel` CHAR(32), "
2035             "`Source` CHAR(72) "
2036             "PRIMARY KEY `DiskId`)" );
2037     ok( r == S_OK, "cannot create Media table: %d\n", r );
2038 
2039     r = run_query( hdb, 0, "INSERT INTO `Media` "
2040             "( `DiskId`, `LastSequence`, `DiskPrompt`, `Cabinet`, `VolumeLabel`, `Source` ) "
2041             "VALUES ( 1, 0, '', 'zero.cab', '', '' )" );
2042     ok( r == S_OK, "cannot add file to the Media table: %d\n", r );
2043 
2044     r = run_query( hdb, 0, "INSERT INTO `Media` "
2045             "( `DiskId`, `LastSequence`, `DiskPrompt`, `Cabinet`, `VolumeLabel`, `Source` ) "
2046             "VALUES ( 2, 1, '', 'one.cab', '', '' )" );
2047     ok( r == S_OK, "cannot add file to the Media table: %d\n", r );
2048 
2049     r = run_query( hdb, 0, "INSERT INTO `Media` "
2050             "( `DiskId`, `LastSequence`, `DiskPrompt`, `Cabinet`, `VolumeLabel`, `Source` ) "
2051             "VALUES ( 3, 2, '', 'two.cab', '', '' )" );
2052     ok( r == S_OK, "cannot add file to the Media table: %d\n", r );
2053 
2054     query = "SELECT * FROM `Media`";
2055     r = do_query(hdb, query, &rec);
2056     ok(r == ERROR_SUCCESS, "MsiViewFetch failed: %d\n", r);
2057     check_record(rec, 6, "1", "0", "", "zero.cab", "", "");
2058     MsiCloseHandle( rec );
2059 
2060     query = "SELECT * FROM `Media` WHERE `LastSequence` >= 1";
2061     r = do_query(hdb, query, &rec);
2062     ok(r == ERROR_SUCCESS, "MsiViewFetch failed: %d\n", r);
2063     check_record(rec, 6, "2", "1", "", "one.cab", "", "");
2064     MsiCloseHandle( rec );
2065 
2066     query = "SELECT `DiskId` FROM `Media` WHERE `LastSequence` >= 1 AND DiskId >= 0";
2067     r = MsiDatabaseOpenViewA(hdb, query, &view);
2068     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
2069 
2070     r = MsiViewExecute(view, 0);
2071     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
2072 
2073     r = MsiViewFetch(view, &rec);
2074     ok( r == ERROR_SUCCESS, "failed to fetch view: %d\n", r );
2075     check_record(rec, 1, "2");
2076     MsiCloseHandle( rec );
2077 
2078     r = MsiViewFetch(view, &rec);
2079     ok( r == ERROR_SUCCESS, "failed to fetch view: %d\n", r );
2080     check_record(rec, 1, "3");
2081     MsiCloseHandle( rec );
2082 
2083     r = MsiViewFetch(view, &rec);
2084     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
2085 
2086     MsiViewClose(view);
2087     MsiCloseHandle(view);
2088 
2089     MsiCloseHandle( rec );
2090 
2091     rec = 0;
2092     query = "SELECT * FROM `Media` WHERE `DiskPrompt` IS NULL";
2093     r = do_query(hdb, query, &rec);
2094     ok( r == ERROR_SUCCESS, "query failed: %d\n", r );
2095     MsiCloseHandle( rec );
2096 
2097     rec = 0;
2098     query = "SELECT * FROM `Media` WHERE `DiskPrompt` < 'Cabinet'";
2099     r = do_query(hdb, query, &rec);
2100     ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %d\n", r );
2101     MsiCloseHandle( rec );
2102 
2103     rec = 0;
2104     query = "SELECT * FROM `Media` WHERE `DiskPrompt` > 'Cabinet'";
2105     r = do_query(hdb, query, &rec);
2106     ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %d\n", r );
2107     MsiCloseHandle( rec );
2108 
2109     rec = 0;
2110     query = "SELECT * FROM `Media` WHERE `DiskPrompt` <> 'Cabinet'";
2111     r = do_query(hdb, query, &rec);
2112     ok( r == ERROR_SUCCESS, "query failed: %d\n", r );
2113     MsiCloseHandle( rec );
2114 
2115     rec = 0;
2116     query = "SELECT * FROM `Media` WHERE `DiskPrompt` = 'Cabinet'";
2117     r = do_query(hdb, query, &rec);
2118     ok( r == ERROR_NO_MORE_ITEMS, "query failed: %d\n", r );
2119     MsiCloseHandle( rec );
2120 
2121     rec = MsiCreateRecord(1);
2122     MsiRecordSetStringA(rec, 1, "");
2123 
2124     query = "SELECT * FROM `Media` WHERE `DiskPrompt` = ?";
2125     r = MsiDatabaseOpenViewA(hdb, query, &view);
2126     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2127     r = MsiViewExecute(view, rec);
2128     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2129 
2130     MsiCloseHandle(rec);
2131 
2132     r = MsiViewFetch(view, &rec);
2133     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2134 
2135     MsiCloseHandle(rec);
2136     MsiViewClose(view);
2137     MsiCloseHandle(view);
2138 
2139     MsiCloseHandle( hdb );
2140     DeleteFileA(msifile);
2141 }
2142 
2143 static const CHAR test_data[] = "FirstPrimaryColumn\tSecondPrimaryColumn\tShortInt\tShortIntNullable\tLongInt\tLongIntNullable\tString\tLocalizableString\tLocalizableStringNullable\n"
2144                                 "s255\ti2\ti2\tI2\ti4\tI4\tS255\tS0\ts0\n"
2145                                 "TestTable\tFirstPrimaryColumn\n"
2146                                 "stringage\t5\t2\t\t2147483640\t-2147483640\tanother string\tlocalizable\tduh\n";
2147 
2148 static const CHAR two_primary[] = "PrimaryOne\tPrimaryTwo\n"
2149                                   "s255\ts255\n"
2150                                   "TwoPrimary\tPrimaryOne\tPrimaryTwo\n"
2151                                   "papaya\tleaf\n"
2152                                   "papaya\tflower\n";
2153 
2154 static const CHAR endlines1[] = "A\tB\tC\tD\tE\tF\r\n"
2155                                 "s72\ts72\ts72\ts72\ts72\ts72\n"
2156                                 "Table\tA\r\n"
2157                                 "a\tb\tc\td\te\tf\n"
2158                                 "g\th\ti\t\rj\tk\tl\r\n";
2159 
2160 static const CHAR endlines2[] = "A\tB\tC\tD\tE\tF\r"
2161                                 "s72\ts72\ts72\ts72\ts72\ts72\n"
2162                                 "Table2\tA\r\n"
2163                                 "a\tb\tc\td\te\tf\n"
2164                                 "g\th\ti\tj\tk\tl\r\n";
2165 
2166 static const CHAR suminfo[] = "PropertyId\tValue\n"
2167                               "i2\tl255\n"
2168                               "_SummaryInformation\tPropertyId\n"
2169                               "1\t1252\n"
2170                               "2\tInstaller Database\n"
2171                               "3\tInstaller description\n"
2172                               "4\tWineHQ\n"
2173                               "5\tInstaller\n"
2174                               "6\tInstaller comments\n"
2175                               "7\tIntel;1033,2057\n"
2176                               "9\t{12345678-1234-1234-1234-123456789012}\n"
2177                               "12\t2009/04/12 15:46:11\n"
2178                               "13\t2009/04/12 15:46:11\n"
2179                               "14\t200\n"
2180                               "15\t2\n"
2181                               "18\tVim\n"
2182                               "19\t2\n";
2183 
2184 static void write_file(const CHAR *filename, const char *data, int data_size)
2185 {
2186     DWORD size;
2187 
2188     HANDLE hf = CreateFileA(filename, GENERIC_WRITE, 0, NULL,
2189                             CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2190     WriteFile(hf, data, data_size, &size, NULL);
2191     CloseHandle(hf);
2192 }
2193 
2194 static UINT add_table_to_db(MSIHANDLE hdb, LPCSTR table_data)
2195 {
2196     UINT r;
2197 
2198     write_file("temp_file", table_data, (lstrlenA(table_data) - 1) * sizeof(char));
2199     r = MsiDatabaseImportA(hdb, CURR_DIR, "temp_file");
2200     DeleteFileA("temp_file");
2201 
2202     return r;
2203 }
2204 
2205 static void test_suminfo_import(void)
2206 {
2207     MSIHANDLE hdb, hsi, view = 0;
2208     LPCSTR query;
2209     UINT r, count, type;
2210     DWORD size;
2211     char str_value[50];
2212     INT int_value;
2213     FILETIME ft_value;
2214 
2215     GetCurrentDirectoryA(MAX_PATH, CURR_DIR);
2216 
2217     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
2218     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2219 
2220     r = add_table_to_db(hdb, suminfo);
2221     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2222 
2223     /* _SummaryInformation is not imported as a regular table... */
2224 
2225     query = "SELECT * FROM `_SummaryInformation`";
2226     r = MsiDatabaseOpenViewA(hdb, query, &view);
2227     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %u\n", r);
2228     MsiCloseHandle(view);
2229 
2230     /* ...its data is added to the special summary information stream */
2231 
2232     r = MsiGetSummaryInformationA(hdb, NULL, 0, &hsi);
2233     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2234 
2235     r = MsiSummaryInfoGetPropertyCount(hsi, &count);
2236     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2237     ok(count == 14, "Expected 14, got %u\n", count);
2238 
2239     r = MsiSummaryInfoGetPropertyA(hsi, PID_CODEPAGE, &type, &int_value, NULL, NULL, NULL);
2240     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2241     ok(type ==  VT_I2, "Expected VT_I2, got %u\n", type);
2242     ok(int_value == 1252, "Expected 1252, got %d\n", int_value);
2243 
2244     size = sizeof(str_value);
2245     r = MsiSummaryInfoGetPropertyA(hsi, PID_TITLE, &type, NULL, NULL, str_value, &size);
2246     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2247     ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
2248     ok(size == 18, "Expected 18, got %lu\n", size);
2249     ok(!strcmp(str_value, "Installer Database"),
2250        "Expected \"Installer Database\", got %s\n", str_value);
2251 
2252     size = sizeof(str_value);
2253     r = MsiSummaryInfoGetPropertyA(hsi, PID_SUBJECT, &type, NULL, NULL, str_value, &size);
2254     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2255     ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
2256     ok(!strcmp(str_value, "Installer description"),
2257        "Expected \"Installer description\", got %s\n", str_value);
2258 
2259     size = sizeof(str_value);
2260     r = MsiSummaryInfoGetPropertyA(hsi, PID_AUTHOR, &type, NULL, NULL, str_value, &size);
2261     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2262     ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
2263     ok(!strcmp(str_value, "WineHQ"),
2264        "Expected \"WineHQ\", got %s\n", str_value);
2265 
2266     size = sizeof(str_value);
2267     r = MsiSummaryInfoGetPropertyA(hsi, PID_KEYWORDS, &type, NULL, NULL, str_value, &size);
2268     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2269     ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
2270     ok(!strcmp(str_value, "Installer"),
2271        "Expected \"Installer\", got %s\n", str_value);
2272 
2273     size = sizeof(str_value);
2274     r = MsiSummaryInfoGetPropertyA(hsi, PID_COMMENTS, &type, NULL, NULL, str_value, &size);
2275     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2276     ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
2277     ok(!strcmp(str_value, "Installer comments"),
2278        "Expected \"Installer comments\", got %s\n", str_value);
2279 
2280     size = sizeof(str_value);
2281     r = MsiSummaryInfoGetPropertyA(hsi, PID_TEMPLATE, &type, NULL, NULL, str_value, &size);
2282     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2283     ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
2284     ok(!strcmp(str_value, "Intel;1033,2057"),
2285        "Expected \"Intel;1033,2057\", got %s\n", str_value);
2286 
2287     size = sizeof(str_value);
2288     r = MsiSummaryInfoGetPropertyA(hsi, PID_REVNUMBER, &type, NULL, NULL, str_value, &size);
2289     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2290     ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
2291     ok(!strcmp(str_value, "{12345678-1234-1234-1234-123456789012}"),
2292        "Expected \"{12345678-1234-1234-1234-123456789012}\", got %s\n", str_value);
2293 
2294     r = MsiSummaryInfoGetPropertyA(hsi, PID_CREATE_DTM, &type, NULL, &ft_value, NULL, NULL);
2295     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2296     ok(type == VT_FILETIME, "Expected VT_FILETIME, got %u\n", type);
2297 
2298     r = MsiSummaryInfoGetPropertyA(hsi, PID_LASTSAVE_DTM, &type, NULL, &ft_value, NULL, NULL);
2299     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2300     ok(type == VT_FILETIME, "Expected VT_FILETIME, got %u\n", type);
2301 
2302     r = MsiSummaryInfoGetPropertyA(hsi, PID_PAGECOUNT, &type, &int_value, NULL, NULL, NULL);
2303     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2304     ok(type ==  VT_I4, "Expected VT_I4, got %u\n", type);
2305     ok(int_value == 200, "Expected 200, got %d\n", int_value);
2306 
2307     r = MsiSummaryInfoGetPropertyA(hsi, PID_WORDCOUNT, &type, &int_value, NULL, NULL, NULL);
2308     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2309     ok(type ==  VT_I4, "Expected VT_I4, got %u\n", type);
2310     ok(int_value == 2, "Expected 2, got %d\n", int_value);
2311 
2312     r = MsiSummaryInfoGetPropertyA(hsi, PID_SECURITY, &type, &int_value, NULL, NULL, NULL);
2313     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2314     ok(type ==  VT_I4, "Expected VT_I4, got %u\n", type);
2315     ok(int_value == 2, "Expected 2, got %d\n", int_value);
2316 
2317     size = sizeof(str_value);
2318     r = MsiSummaryInfoGetPropertyA(hsi, PID_APPNAME, &type, NULL, NULL, str_value, &size);
2319     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2320     ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
2321     ok(!strcmp(str_value, "Vim"), "Expected \"Vim\", got %s\n", str_value);
2322 
2323     MsiCloseHandle(hsi);
2324     MsiCloseHandle(hdb);
2325     DeleteFileA(msifile);
2326 }
2327 
2328 static void test_msiimport(void)
2329 {
2330     MSIHANDLE hdb, view, rec;
2331     LPCSTR query;
2332     UINT r;
2333 
2334     GetCurrentDirectoryA(MAX_PATH, CURR_DIR);
2335 
2336     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
2337     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2338 
2339     r = MsiDatabaseImportA(hdb, CURR_DIR, NULL);
2340     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
2341 
2342     r = MsiDatabaseImportA(hdb, CURR_DIR, "nonexistent");
2343     ok(r == ERROR_FUNCTION_FAILED, "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
2344 
2345     r = add_table_to_db(hdb, test_data);
2346     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2347 
2348     r = add_table_to_db(hdb, two_primary);
2349     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2350 
2351     r = add_table_to_db(hdb, endlines1);
2352     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2353 
2354     r = add_table_to_db(hdb, endlines2);
2355     ok(r == ERROR_FUNCTION_FAILED, "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
2356 
2357     query = "SELECT * FROM `TestTable`";
2358     r = MsiDatabaseOpenViewA(hdb, query, &view);
2359     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2360 
2361     r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec);
2362     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2363     check_record(rec, 9, "FirstPrimaryColumn", "SecondPrimaryColumn", "ShortInt",
2364             "ShortIntNullable", "LongInt", "LongIntNullable", "String",
2365             "LocalizableString", "LocalizableStringNullable");
2366     MsiCloseHandle(rec);
2367 
2368     r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
2369     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2370     check_record(rec, 9, "s255", "i2", "i2", "I2", "i4", "I4", "S255", "S0", "s0");
2371     MsiCloseHandle(rec);
2372 
2373     query = "SELECT * FROM `TestTable`";
2374     r = do_query(hdb, query, &rec);
2375     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2376     check_record(rec, 9, "stringage", "5", "2", "", "2147483640", "-2147483640",
2377             "another string", "localizable", "duh");
2378     MsiCloseHandle(rec);
2379 
2380     MsiViewClose(view);
2381     MsiCloseHandle(view);
2382 
2383     query = "SELECT * FROM `TwoPrimary`";
2384     r = MsiDatabaseOpenViewA(hdb, query, &view);
2385     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2386 
2387     r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec);
2388     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2389     check_record(rec, 2, "PrimaryOne", "PrimaryTwo");
2390     MsiCloseHandle(rec);
2391 
2392     r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
2393     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2394     check_record(rec, 2, "s255", "s255");
2395     MsiCloseHandle(rec);
2396 
2397     r = MsiViewExecute(view, 0);
2398     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2399 
2400     r = MsiViewFetch(view, &rec);
2401     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2402     check_record(rec, 2, "papaya", "leaf");
2403     MsiCloseHandle(rec);
2404 
2405     r = MsiViewFetch(view, &rec);
2406     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2407     check_record(rec, 2, "papaya", "flower");
2408     MsiCloseHandle(rec);
2409 
2410     r = MsiViewFetch(view, &rec);
2411     ok(r == ERROR_NO_MORE_ITEMS,
2412        "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
2413 
2414     r = MsiViewClose(view);
2415     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2416 
2417     MsiCloseHandle(view);
2418 
2419     query = "SELECT * FROM `Table`";
2420     r = MsiDatabaseOpenViewA(hdb, query, &view);
2421     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2422 
2423     r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec);
2424     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2425     check_record(rec, 6, "A", "B", "C", "D", "E", "F");
2426     MsiCloseHandle(rec);
2427 
2428     r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
2429     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2430     check_record(rec, 6, "s72", "s72", "s72", "s72", "s72", "s72");
2431     MsiCloseHandle(rec);
2432 
2433     MsiViewClose(view);
2434     MsiCloseHandle(view);
2435 
2436     query = "SELECT * FROM `Table`";
2437     r = MsiDatabaseOpenViewA(hdb, query, &view);
2438     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2439 
2440     r = MsiViewExecute(view, 0);
2441     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2442 
2443     r = MsiViewFetch(view, &rec);
2444     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2445     check_record(rec, 6, "a", "b", "c", "d", "e", "f");
2446     MsiCloseHandle(rec);
2447 
2448     r = MsiViewFetch(view, &rec);
2449     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2450     check_record(rec, 6, "g", "h", "i", "j", "k", "l");
2451     MsiCloseHandle(rec);
2452 
2453     r = MsiViewFetch(view, &rec);
2454     ok(r == ERROR_NO_MORE_ITEMS,
2455        "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
2456 
2457     MsiViewClose(view);
2458     MsiCloseHandle(view);
2459     MsiCloseHandle(hdb);
2460     DeleteFileA(msifile);
2461 }
2462 
2463 static const CHAR bin_import_dat[] = "Name\tData\r\n"
2464                                      "s72\tV0\r\n"
2465                                      "Binary\tName\r\n"
2466                                      "filename1\tfilename1.ibd\r\n";
2467 
2468 static void test_binary_import(void)
2469 {
2470     MSIHANDLE hdb = 0, rec;
2471     char file[MAX_PATH];
2472     char buf[MAX_PATH];
2473     char path[MAX_PATH];
2474     DWORD size;
2475     LPCSTR query;
2476     UINT r;
2477 
2478     /* create files to import */
2479     write_file("bin_import.idt", bin_import_dat,
2480           (sizeof(bin_import_dat) - 1) * sizeof(char));
2481     CreateDirectoryA("bin_import", NULL);
2482     create_file_data("bin_import/filename1.ibd", "just some words", 15);
2483 
2484     /* import files into database */
2485     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
2486     ok( r == ERROR_SUCCESS , "Failed to open database\n");
2487 
2488     GetCurrentDirectoryA(MAX_PATH, path);
2489     r = MsiDatabaseImportA(hdb, path, "bin_import.idt");
2490     ok(r == ERROR_SUCCESS , "Failed to import Binary table\n");
2491 
2492     /* read file from the Binary table */
2493     query = "SELECT * FROM `Binary`";
2494     r = do_query(hdb, query, &rec);
2495     ok(r == ERROR_SUCCESS, "SELECT query failed: %d\n", r);
2496 
2497     size = MAX_PATH;
2498     r = MsiRecordGetStringA(rec, 1, file, &size);
2499     ok(r == ERROR_SUCCESS, "Failed to get string: %d\n", r);
2500     ok(!lstrcmpA(file, "filename1"), "Expected 'filename1', got %s\n", file);
2501 
2502     size = MAX_PATH;
2503     memset(buf, 0, MAX_PATH);
2504     r = MsiRecordReadStream(rec, 2, buf, &size);
2505     ok(r == ERROR_SUCCESS, "Failed to get stream: %d\n", r);
2506     ok(!lstrcmpA(buf, "just some words"), "Expected 'just some words', got %s\n", buf);
2507 
2508     r = MsiCloseHandle(rec);
2509     ok(r == ERROR_SUCCESS , "Failed to close record handle\n");
2510 
2511     r = MsiCloseHandle(hdb);
2512     ok(r == ERROR_SUCCESS , "Failed to close database\n");
2513 
2514     DeleteFileA("bin_import/filename1.ibd");
2515     RemoveDirectoryA("bin_import");
2516     DeleteFileA("bin_import.idt");
2517 }
2518 
2519 static void test_markers(void)
2520 {
2521     MSIHANDLE hdb, rec;
2522     LPCSTR query;
2523     UINT r;
2524 
2525     hdb = create_db();
2526     ok( hdb, "failed to create db\n");
2527 
2528     rec = MsiCreateRecord(3);
2529     MsiRecordSetStringA(rec, 1, "Table");
2530     MsiRecordSetStringA(rec, 2, "Apples");
2531     MsiRecordSetStringA(rec, 3, "Oranges");
2532 
2533     /* try a legit create */
2534     query = "CREATE TABLE `Table` ( `One` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`)";
2535     r = run_query(hdb, 0, query);
2536     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2537     MsiCloseHandle(rec);
2538 
2539     /* try table name as marker */
2540     rec = MsiCreateRecord(1);
2541     MsiRecordSetStringA(rec, 1, "Fable");
2542     query = "CREATE TABLE `?` ( `One` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`)";
2543     r = run_query(hdb, rec, query);
2544     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2545 
2546     /* verify that we just created a table called '?', not 'Fable' */
2547     r = try_query(hdb, "SELECT * from `Fable`");
2548     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2549 
2550     r = try_query(hdb, "SELECT * from `?`");
2551     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2552 
2553     /* try table name as marker without backticks */
2554     MsiRecordSetStringA(rec, 1, "Mable");
2555     query = "CREATE TABLE ? ( `One` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`)";
2556     r = run_query(hdb, rec, query);
2557     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2558 
2559     /* try one column name as marker */
2560     MsiRecordSetStringA(rec, 1, "One");
2561     query = "CREATE TABLE `Mable` ( `?` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`)";
2562     r = run_query(hdb, rec, query);
2563     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2564     MsiCloseHandle(rec);
2565 
2566     /* try column names as markers */
2567     rec = MsiCreateRecord(2);
2568     MsiRecordSetStringA(rec, 1, "One");
2569     MsiRecordSetStringA(rec, 2, "Two");
2570     query = "CREATE TABLE `Mable` ( `?` SHORT NOT NULL, `?` CHAR(255) PRIMARY KEY `One`)";
2571     r = run_query(hdb, rec, query);
2572     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2573     MsiCloseHandle(rec);
2574 
2575     /* try names with backticks */
2576     rec = MsiCreateRecord(3);
2577     MsiRecordSetStringA(rec, 1, "One");
2578     MsiRecordSetStringA(rec, 2, "Two");
2579     MsiRecordSetStringA(rec, 3, "One");
2580     query = "CREATE TABLE `Mable` ( `?` SHORT NOT NULL, `?` CHAR(255) PRIMARY KEY `?`)";
2581     r = run_query(hdb, rec, query);
2582     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2583 
2584     /* try names with backticks, minus definitions */
2585     query = "CREATE TABLE `Mable` ( `?`, `?` PRIMARY KEY `?`)";
2586     r = run_query(hdb, rec, query);
2587     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2588 
2589     /* try names without backticks */
2590     query = "CREATE TABLE `Mable` ( ? SHORT NOT NULL, ? CHAR(255) PRIMARY KEY ?)";
2591     r = run_query(hdb, rec, query);
2592     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2593     MsiCloseHandle(rec);
2594 
2595     /* try one long marker */
2596     rec = MsiCreateRecord(1);
2597     MsiRecordSetStringA(rec, 1, "`One` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`");
2598     query = "CREATE TABLE `Mable` ( ? )";
2599     r = run_query(hdb, rec, query);
2600     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2601     MsiCloseHandle(rec);
2602 
2603     /* try all names as markers */
2604     rec = MsiCreateRecord(4);
2605     MsiRecordSetStringA(rec, 1, "Mable");
2606     MsiRecordSetStringA(rec, 2, "One");
2607     MsiRecordSetStringA(rec, 3, "Two");
2608     MsiRecordSetStringA(rec, 4, "One");
2609     query = "CREATE TABLE `?` ( `?` SHORT NOT NULL, `?` CHAR(255) PRIMARY KEY `?`)";
2610     r = run_query(hdb, rec, query);
2611     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2612     MsiCloseHandle(rec);
2613 
2614     /* try a legit insert */
2615     query = "INSERT INTO `Table` ( `One`, `Two` ) VALUES ( 5, 'hello' )";
2616     r = run_query(hdb, 0, query);
2617     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2618 
2619     r = try_query(hdb, "SELECT * from `Table`");
2620     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2621 
2622     /* try values as markers */
2623     rec = MsiCreateRecord(2);
2624     MsiRecordSetInteger(rec, 1, 4);
2625     MsiRecordSetStringA(rec, 2, "hi");
2626     query = "INSERT INTO `Table` ( `One`, `Two` ) VALUES ( ?, '?' )";
2627     r = run_query(hdb, rec, query);
2628     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2629     MsiCloseHandle(rec);
2630 
2631     /* try column names and values as markers */
2632     rec = MsiCreateRecord(4);
2633     MsiRecordSetStringA(rec, 1, "One");
2634     MsiRecordSetStringA(rec, 2, "Two");
2635     MsiRecordSetInteger(rec, 3, 5);
2636     MsiRecordSetStringA(rec, 4, "hi");
2637     query = "INSERT INTO `Table` ( `?`, `?` ) VALUES ( ?, '?' )";
2638     r = run_query(hdb, rec, query);
2639     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2640     MsiCloseHandle(rec);
2641 
2642     /* try column names as markers */
2643     rec = MsiCreateRecord(2);
2644     MsiRecordSetStringA(rec, 1, "One");
2645     MsiRecordSetStringA(rec, 2, "Two");
2646     query = "INSERT INTO `Table` ( `?`, `?` ) VALUES ( 3, 'yellow' )";
2647     r = run_query(hdb, rec, query);
2648     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2649     MsiCloseHandle(rec);
2650 
2651     /* try table name as a marker */
2652     rec = MsiCreateRecord(1);
2653     MsiRecordSetStringA(rec, 1, "Table");
2654     query = "INSERT INTO `?` ( `One`, `Two` ) VALUES ( 2, 'green' )";
2655     r = run_query(hdb, rec, query);
2656     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2657     MsiCloseHandle(rec);
2658 
2659     /* try table name and values as markers */
2660     rec = MsiCreateRecord(3);
2661     MsiRecordSetStringA(rec, 1, "Table");
2662     MsiRecordSetInteger(rec, 2, 10);
2663     MsiRecordSetStringA(rec, 3, "haha");
2664     query = "INSERT INTO `?` ( `One`, `Two` ) VALUES ( ?, '?' )";
2665     r = run_query(hdb, rec, query);
2666     ok(r == ERROR_FUNCTION_FAILED, "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
2667     MsiCloseHandle(rec);
2668 
2669     /* try all markers */
2670     rec = MsiCreateRecord(5);
2671     MsiRecordSetStringA(rec, 1, "Table");
2672     MsiRecordSetStringA(rec, 1, "One");
2673     MsiRecordSetStringA(rec, 1, "Two");
2674     MsiRecordSetInteger(rec, 2, 10);
2675     MsiRecordSetStringA(rec, 3, "haha");
2676     query = "INSERT INTO `?` ( `?`, `?` ) VALUES ( ?, '?' )";
2677     r = run_query(hdb, rec, query);
2678     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2679     MsiCloseHandle(rec);
2680 
2681     /* insert an integer as a string */
2682     rec = MsiCreateRecord(2);
2683     MsiRecordSetStringA(rec, 1, "11");
2684     MsiRecordSetStringA(rec, 2, "hi");
2685     query = "INSERT INTO `Table` ( `One`, `Two` ) VALUES ( ?, '?' )";
2686     r = run_query(hdb, rec, query);
2687     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2688     MsiCloseHandle(rec);
2689 
2690     /* leave off the '' for the string */
2691     rec = MsiCreateRecord(2);
2692     MsiRecordSetInteger(rec, 1, 12);
2693     MsiRecordSetStringA(rec, 2, "hi");
2694     query = "INSERT INTO `Table` ( `One`, `Two` ) VALUES ( ?, ? )";
2695     r = run_query(hdb, rec, query);
2696     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2697     MsiCloseHandle(rec);
2698 
2699     MsiCloseHandle(hdb);
2700     DeleteFileA(msifile);
2701 }
2702 
2703 #define MY_NVIEWS 4000    /* Largest installer I've seen uses < 2000 */
2704 static void test_handle_limit(void)
2705 {
2706     int i;
2707     MSIHANDLE hdb;
2708     MSIHANDLE hviews[MY_NVIEWS];
2709     UINT r;
2710 
2711     /* create an empty db */
2712     hdb = create_db();
2713     ok( hdb, "failed to create db\n");
2714 
2715     memset(hviews, 0, sizeof(hviews));
2716 
2717     for (i=0; i<MY_NVIEWS; i++) {
2718         static char szQueryBuf[256] = "SELECT * from `_Tables`";
2719         hviews[i] = 0xdeadbeeb;
2720         r = MsiDatabaseOpenViewA(hdb, szQueryBuf, &hviews[i]);
2721         if( r != ERROR_SUCCESS || hviews[i] == 0xdeadbeeb ||
2722             hviews[i] == 0 || (i && (hviews[i] == hviews[i-1])))
2723             break;
2724     }
2725 
2726     ok( i == MY_NVIEWS, "problem opening views\n");
2727 
2728     for (i=0; i<MY_NVIEWS; i++) {
2729         if (hviews[i] != 0 && hviews[i] != 0xdeadbeeb) {
2730             MsiViewClose(hviews[i]);
2731             r = MsiCloseHandle(hviews[i]);
2732             if (r != ERROR_SUCCESS)
2733                 break;
2734         }
2735     }
2736 
2737     ok( i == MY_NVIEWS, "problem closing views\n");
2738 
2739     r = MsiCloseHandle(hdb);
2740     ok( r == ERROR_SUCCESS, "failed to close database\n");
2741 }
2742 
2743 static void generate_transform(void)
2744 {
2745     MSIHANDLE hdb1, hdb2, hrec;
2746     LPCSTR query;
2747     UINT r;
2748 
2749     /* start with two identical databases */
2750     CopyFileA(msifile2, msifile, FALSE);
2751 
2752     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_TRANSACT, &hdb1 );
2753     ok( r == ERROR_SUCCESS , "Failed to create database\n" );
2754 
2755     r = MsiDatabaseCommit( hdb1 );
2756     ok( r == ERROR_SUCCESS , "Failed to commit database\n" );
2757 
2758     r = MsiOpenDatabaseW(msifile2W, MSIDBOPEN_READONLY, &hdb2 );
2759     ok( r == ERROR_SUCCESS , "Failed to create database\n" );
2760 
2761     /* the transform between two identical database should be empty */
2762     r = MsiDatabaseGenerateTransformA(hdb1, hdb2, NULL, 0, 0);
2763     todo_wine {
2764     ok( r == ERROR_NO_DATA, "return code %d, should be ERROR_NO_DATA\n", r );
2765     }
2766 
2767     query = "CREATE TABLE `AAR` ( `BAR` SHORT NOT NULL, `CAR` CHAR(255) PRIMARY KEY `CAR`)";
2768     r = run_query(hdb1, 0, query);
2769     ok(r == ERROR_SUCCESS, "failed to add table\n");
2770 
2771     query = "INSERT INTO `AAR` ( `BAR`, `CAR` ) VALUES ( 1, 'vw' )";
2772     r = run_query(hdb1, 0, query);
2773     ok(r == ERROR_SUCCESS, "failed to add row 1\n");
2774 
2775     query = "INSERT INTO `AAR` ( `BAR`, `CAR` ) VALUES ( 2, 'bmw' )";
2776     r = run_query(hdb1, 0, query);
2777     ok(r == ERROR_SUCCESS, "failed to add row 2\n");
2778 
2779     query = "UPDATE `MOO` SET `OOO` = 'c' WHERE `NOO` = 1";
2780     r = run_query(hdb1, 0, query);
2781     ok(r == ERROR_SUCCESS, "failed to modify row\n");
2782 
2783     query = "DELETE FROM `MOO` WHERE `NOO` = 3";
2784     r = run_query(hdb1, 0, query);
2785     ok(r == ERROR_SUCCESS, "failed to delete row\n");
2786 
2787     hrec = MsiCreateRecord(2);
2788     r = MsiRecordSetInteger(hrec, 1, 1);
2789     ok(r == ERROR_SUCCESS, "failed to set integer\n");
2790 
2791     write_file("testdata.bin", "naengmyon", 9);
2792     r = MsiRecordSetStreamA(hrec, 2, "testdata.bin");
2793     ok(r == ERROR_SUCCESS, "failed to set stream\n");
2794 
2795     query = "INSERT INTO `BINARY` ( `ID`, `BLOB` ) VALUES ( ?, ? )";
2796     r = run_query(hdb1, hrec, query);
2797     ok(r == ERROR_SUCCESS, "failed to add row with blob\n");
2798 
2799     MsiCloseHandle(hrec);
2800 
2801     query = "ALTER TABLE `MOO` ADD `COW` INTEGER";
2802     r = run_query(hdb1, 0, query);
2803     ok(r == ERROR_SUCCESS, "failed to add column\n");
2804 
2805     query = "ALTER TABLE `MOO` ADD `PIG` INTEGER";
2806     r = run_query(hdb1, 0, query);
2807     ok(r == ERROR_SUCCESS, "failed to add column\n");
2808 
2809     query = "UPDATE `MOO` SET `PIG` = 5 WHERE `NOO` = 1";
2810     r = run_query(hdb1, 0, query);
2811     ok(r == ERROR_SUCCESS, "failed to modify row\n");
2812 
2813     query = "CREATE TABLE `Property` ( `Property` CHAR(72) NOT NULL, "
2814             "`Value` CHAR(0) PRIMARY KEY `Property`)";
2815     r = run_query(hdb1, 0, query);
2816     ok(r == ERROR_SUCCESS, "failed to add property table\n");
2817 
2818     query = "INSERT INTO `Property` ( `Property`, `Value` ) VALUES ( 'prop', 'val' )";
2819     r = run_query(hdb1, 0, query);
2820     ok(r == ERROR_SUCCESS, "failed to add property\n");
2821 
2822     /* database needs to be committed */
2823     MsiDatabaseCommit(hdb1);
2824 
2825     r = MsiDatabaseGenerateTransformA(hdb1, hdb2, mstfile, 0, 0);
2826     ok( r == ERROR_SUCCESS, "return code %d, should be ERROR_SUCCESS\n", r );
2827 
2828     MsiCloseHandle( hdb1 );
2829     MsiCloseHandle( hdb2 );
2830 
2831     DeleteFileA("testdata.bin");
2832 }
2833 
2834 /* data for generating a transform */
2835 
2836 /* tables transform names - encoded as they would be in an msi database file */
2837 static const WCHAR name1[] = { 0x4840, 0x3a8a, 0x481b, 0 }; /* AAR */
2838 static const WCHAR name2[] = { 0x4840, 0x3b3f, 0x43f2, 0x4438, 0x45b1, 0 }; /* _Columns */
2839 static const WCHAR name3[] = { 0x4840, 0x3f7f, 0x4164, 0x422f, 0x4836, 0 }; /* _Tables */
2840 static const WCHAR name4[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0 }; /* _StringData */
2841 static const WCHAR name5[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0 }; /* _StringPool */
2842 static const WCHAR name6[] = { 0x4840, 0x3e16, 0x4818, 0}; /* MOO */
2843 static const WCHAR name7[] = { 0x4840, 0x3c8b, 0x3a97, 0x409b, 0 }; /* BINARY */
2844 static const WCHAR name8[] = { 0x3c8b, 0x3a97, 0x409b, 0x387e, 0 }; /* BINARY.1 */
2845 static const WCHAR name9[] = { 0x4840, 0x4559, 0x44f2, 0x4568, 0x4737, 0 }; /* Property */
2846 
2847 /* data in each table */
2848 static const WCHAR data1[] = { /* AAR */
2849     0x0201, 0x0008, 0x8001,  /* 0x0201 = add row (1), two shorts */
2850     0x0201, 0x0009, 0x8002,
2851 };
2852 static const WCHAR data2[] = { /* _Columns */
2853     0x0401, 0x0001, 0x8003, 0x0002, 0x9502,
2854     0x0401, 0x0001, 0x8004, 0x0003, 0x9502,
2855     0x0401, 0x0005, 0x0000, 0x0006, 0xbdff,  /* 0x0401 = add row (1), 4 shorts */
2856     0x0401, 0x0005, 0x0000, 0x0007, 0x8502,
2857     0x0401, 0x000a, 0x0000, 0x000a, 0xad48,
2858     0x0401, 0x000a, 0x0000, 0x000b, 0x9d00,
2859 };
2860 static const WCHAR data3[] = { /* _Tables */
2861     0x0101, 0x0005, /* 0x0101 = add row (1), 1 short */
2862     0x0101, 0x000a,
2863 };
2864 static const char data4[] = /* _StringData */
2865     "MOOCOWPIGcAARCARBARvwbmwPropertyValuepropval";  /* all the strings squashed together */
2866 static const WCHAR data5[] = { /* _StringPool */
2867 /*  len, refs */
2868     0,   0,    /* string 0 ''    */
2869     3,   2,    /* string 1 'MOO' */
2870     3,   1,    /* string 2 'COW' */
2871     3,   1,    /* string 3 'PIG' */
2872     1,   1,    /* string 4 'c'   */
2873     3,   3,    /* string 5 'AAR' */
2874     3,   1,    /* string 6 'CAR' */
2875     3,   1,    /* string 7 'BAR' */
2876     2,   1,    /* string 8 'vw'  */
2877     3,   1,    /* string 9 'bmw' */
2878     8,   4,    /* string 10 'Property' */
2879     5,   1,    /* string 11 'Value' */
2880     4,   1,    /* string 12 'prop' */
2881     3,   1,    /* string 13 'val' */
2882 };
2883 /* update row, 0x0002 is a bitmask of present column data, keys are excluded */
2884 static const WCHAR data6[] = { /* MOO */
2885     0x000a, 0x8001, 0x0004, 0x8005, /* update row */
2886     0x0000, 0x8003,         /* delete row */
2887 };
2888 
2889 static const WCHAR data7[] = { /* BINARY */
2890     0x0201, 0x8001, 0x0001,
2891 };
2892 
2893 static const char data8[] =  /* stream data for the BINARY table */
2894     "naengmyon";
2895 
2896 static const WCHAR data9[] = { /* Property */
2897     0x0201, 0x000c, 0x000d,
2898 };
2899 
2900 static const struct {
2901     LPCWSTR name;
2902     const void *data;
2903     DWORD size;
2904 } table_transform_data[] =
2905 {
2906     { name1, data1, sizeof data1 },
2907     { name2, data2, sizeof data2 },
2908     { name3, data3, sizeof data3 },
2909     { name4, data4, sizeof data4 - 1 },
2910     { name5, data5, sizeof data5 },
2911     { name6, data6, sizeof data6 },
2912     { name7, data7, sizeof data7 },
2913     { name8, data8, sizeof data8 - 1 },
2914     { name9, data9, sizeof data9 },
2915 };
2916 
2917 static void generate_transform_manual(void)
2918 {
2919     IStorage *stg = NULL;
2920     IStream *stm;
2921     WCHAR name[0x20];
2922     HRESULT r;
2923     DWORD i, count;
2924     const DWORD mode = STGM_CREATE|STGM_READWRITE|STGM_DIRECT|STGM_SHARE_EXCLUSIVE;
2925 
2926     const CLSID CLSID_MsiTransform = { 0xc1082,0,0,{0xc0,0,0,0,0,0,0,0x46}};
2927 
2928     MultiByteToWideChar(CP_ACP, 0, mstfile, -1, name, 0x20);
2929 
2930     r = StgCreateDocfile(name, mode, 0, &stg);
2931     ok(r == S_OK, "failed to create storage\n");
2932     if (!stg)
2933         return;
2934 
2935     r = IStorage_SetClass( stg, &CLSID_MsiTransform );
2936     ok(r == S_OK, "failed to set storage type\n");
2937 
2938     for (i=0; i<ARRAY_SIZE(table_transform_data); i++)
2939     {
2940         r = IStorage_CreateStream( stg, table_transform_data[i].name,
2941                             STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stm );
2942         if (FAILED(r))
2943         {
2944             ok(0, "failed to create stream %#lx\n", r);
2945             continue;
2946         }
2947 
2948         r = IStream_Write( stm, table_transform_data[i].data,
2949                           table_transform_data[i].size, &count );
2950         if (FAILED(r) || count != table_transform_data[i].size)
2951             ok(0, "failed to write stream\n");
2952         IStream_Release(stm);
2953     }
2954 
2955     IStorage_Release(stg);
2956 }
2957 
2958 static UINT set_summary_info(MSIHANDLE hdb)
2959 {
2960     UINT res;
2961     MSIHANDLE suminfo;
2962 
2963     /* build summary info */
2964     res = MsiGetSummaryInformationA(hdb, NULL, 7, &suminfo);
2965     ok( res == ERROR_SUCCESS , "Failed to open summaryinfo\n" );
2966 
2967     res = MsiSummaryInfoSetPropertyA(suminfo,2, VT_LPSTR, 0,NULL,
2968                         "Installation Database");
2969     ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
2970 
2971     res = MsiSummaryInfoSetPropertyA(suminfo,3, VT_LPSTR, 0,NULL,
2972                         "Installation Database");
2973     ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
2974 
2975     res = MsiSummaryInfoSetPropertyA(suminfo,4, VT_LPSTR, 0,NULL,
2976                         "Wine Hackers");
2977     ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
2978 
2979     res = MsiSummaryInfoSetPropertyA(suminfo,7, VT_LPSTR, 0,NULL,
2980                     ";1033,2057");
2981     ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
2982 
2983     res = MsiSummaryInfoSetPropertyA(suminfo,9, VT_LPSTR, 0,NULL,
2984                     "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}");
2985     ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
2986 
2987     res = MsiSummaryInfoSetPropertyA(suminfo, 14, VT_I4, 100, NULL, NULL);
2988     ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
2989 
2990     res = MsiSummaryInfoSetPropertyA(suminfo, 15, VT_I4, 0, NULL, NULL);
2991     ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
2992 
2993     res = MsiSummaryInfoPersist(suminfo);
2994     ok( res == ERROR_SUCCESS , "Failed to make summary info persist\n" );
2995 
2996     res = MsiCloseHandle( suminfo);
2997     ok( res == ERROR_SUCCESS , "Failed to close suminfo\n" );
2998 
2999     return res;
3000 }
3001 
3002 static MSIHANDLE create_package_db(const WCHAR *filename)
3003 {
3004     MSIHANDLE hdb = 0;
3005     UINT res;
3006 
3007     DeleteFileW(msifileW);
3008 
3009     /* create an empty database */
3010     res = MsiOpenDatabaseW(filename, MSIDBOPEN_CREATE, &hdb );
3011     ok( res == ERROR_SUCCESS , "Failed to create database\n" );
3012     if( res != ERROR_SUCCESS )
3013         return hdb;
3014 
3015     res = MsiDatabaseCommit( hdb );
3016     ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
3017 
3018     res = set_summary_info(hdb);
3019     ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
3020 
3021     create_directory_table(hdb);
3022 
3023     return hdb;
3024 }
3025 
3026 static UINT package_from_db(MSIHANDLE hdb, MSIHANDLE *handle)
3027 {
3028     UINT res;
3029     CHAR szPackage[12];
3030     MSIHANDLE hPackage;
3031 
3032     sprintf(szPackage, "#%lu", hdb);
3033     res = MsiOpenPackageA(szPackage, &hPackage);
3034     if (res != ERROR_SUCCESS)
3035         return res;
3036 
3037     res = MsiCloseHandle(hdb);
3038     if (res != ERROR_SUCCESS)
3039     {
3040         MsiCloseHandle(hPackage);
3041         return res;
3042     }
3043 
3044     *handle = hPackage;
3045     return ERROR_SUCCESS;
3046 }
3047 
3048 static void test_try_transform(void)
3049 {
3050     static const struct {
3051         const char *table;
3052         const char *column;
3053         const char *row;
3054         const char *data;
3055         const char *current;
3056     } transform_view[] = {
3057         { "MOO", "OOO", "1", "c", "a" },
3058         { "MOO", "COW", "", "5378", "3" },
3059         { "MOO", "PIG", "", "5378", "4" },
3060         { "MOO", "PIG", "1", "5", "" },
3061         { "MOO", "DELETE", "3", "", "" },
3062         { "BINARY", "BLOB", "1", "BINARY.1", "" },
3063         { "BINARY", "INSERT", "1", "", "" },
3064         { "AAR", "CREATE", "", "", "" },
3065         { "AAR", "CAR", "", "15871", "1" },
3066         { "AAR", "BAR", "", "1282", "2" },
3067         { "AAR", "BAR", "vw", "1", "" },
3068         { "AAR", "BAR", "bmw", "2", "" },
3069         { "AAR", "INSERT", "vw", "", "" },
3070         { "AAR", "INSERT", "bmw", "", "" },
3071         { "Property", "CREATE", "", "", "" },
3072         { "Property", "Property", "", "11592", "1" },
3073         { "Property", "Value", "", "7424", "2" },
3074         { "Property", "Value", "prop", "val", "" },
3075         { "Property", "INSERT", "prop", "", "" }
3076     };
3077 
3078     MSIHANDLE hdb, hview, hrec, hpkg = 0;
3079     LPCSTR query;
3080     UINT r;
3081     DWORD sz;
3082     char buffer[MAX_PATH];
3083     int i, matched;
3084 
3085     DeleteFileA(msifile);
3086     DeleteFileA(mstfile);
3087 
3088     /* create the database */
3089     hdb = create_package_db(msifileW);
3090     ok(hdb, "Failed to create package db\n");
3091 
3092     query = "CREATE TABLE `MOO` ( `NOO` SHORT NOT NULL, `OOO` CHAR(255) PRIMARY KEY `NOO`)";
3093     r = run_query(hdb, 0, query);
3094     ok(r == ERROR_SUCCESS, "failed to add table\n");
3095 
3096     query = "INSERT INTO `MOO` ( `NOO`, `OOO` ) VALUES ( 1, 'a' )";
3097     r = run_query(hdb, 0, query);
3098     ok(r == ERROR_SUCCESS, "failed to add row\n");
3099 
3100     query = "INSERT INTO `MOO` ( `NOO`, `OOO` ) VALUES ( 2, 'b' )";
3101     r = run_query(hdb, 0, query);
3102     ok(r == ERROR_SUCCESS, "failed to add row\n");
3103 
3104     query = "INSERT INTO `MOO` ( `NOO`, `OOO` ) VALUES ( 3, 'c' )";
3105     r = run_query(hdb, 0, query);
3106     ok(r == ERROR_SUCCESS, "failed to add row\n");
3107 
3108     query = "CREATE TABLE `BINARY` ( `ID` SHORT NOT NULL, `BLOB` OBJECT PRIMARY KEY `ID`)";
3109     r = run_query(hdb, 0, query);
3110     ok(r == ERROR_SUCCESS, "failed to add table\n");
3111 
3112     hrec = MsiCreateRecord(2);
3113     r = MsiRecordSetInteger(hrec, 1, 2);
3114     ok(r == ERROR_SUCCESS, "failed to set integer\n");
3115 
3116     write_file("testdata.bin", "lamyon", 6);
3117     r = MsiRecordSetStreamA(hrec, 2, "testdata.bin");
3118     ok(r == ERROR_SUCCESS, "failed to set stream\n");
3119 
3120     query = "INSERT INTO `BINARY` ( `ID`, `BLOB` ) VALUES ( ?, ? )";
3121     r = run_query(hdb, hrec, query);
3122     ok(r == ERROR_SUCCESS, "failed to add row with blob\n");
3123 
3124     MsiCloseHandle(hrec);
3125 
3126     r = MsiDatabaseCommit( hdb );
3127     ok( r == ERROR_SUCCESS , "Failed to commit database\n" );
3128 
3129     MsiCloseHandle( hdb );
3130     DeleteFileA("testdata.bin");
3131 
3132     /*
3133      * Both these generate an equivalent transform,
3134      *  but the first doesn't work in Wine yet
3135      *  because MsiDatabaseGenerateTransform is unimplemented.
3136      */
3137     if (0)
3138         generate_transform();
3139     else
3140         generate_transform_manual();
3141 
3142     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_DIRECT, &hdb );
3143     ok( r == ERROR_SUCCESS , "Failed to create database\n" );
3144 
3145     r = MsiDatabaseApplyTransformA(hdb, mstfile, MSITRANSFORM_ERROR_VIEWTRANSFORM);
3146     ok(r == ERROR_SUCCESS, "return code %d, should be ERROR_SUCCESS\n", r);
3147 
3148     query = "select * from `_TransformView`";
3149     r = MsiDatabaseOpenViewA(hdb, query, &hview);
3150     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
3151     r = MsiViewExecute(hview, 0);
3152     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
3153 
3154     r = MsiViewGetColumnInfo(hview, MSICOLINFO_NAMES, &hrec);
3155     ok(r == ERROR_SUCCESS, "error\n");
3156     check_record(hrec, 5, "Table", "Column", "Row", "Data", "Current");
3157     MsiCloseHandle(hrec);
3158 
3159     r = MsiViewGetColumnInfo(hview, MSICOLINFO_TYPES, &hrec);
3160     ok(r == ERROR_SUCCESS, "error\n");
3161     check_record(hrec, 5, "g0", "g0", "G0", "G0", "G0");
3162     MsiCloseHandle(hrec);
3163 
3164     matched = 0;
3165     while (MsiViewFetch(hview, &hrec) == ERROR_SUCCESS)
3166     {
3167         char data[5][256];
3168 
3169         for (i = 1; i <= 5; i++) {
3170             sz = ARRAY_SIZE(data[0]);
3171             r = MsiRecordGetStringA(hrec, i, data[i-1], &sz);
3172             ok(r == ERROR_SUCCESS, "%d) MsiRecordGetStringA failed %d\n", i, r);
3173         }
3174 
3175         for (i = 0; i < ARRAY_SIZE(transform_view); i++)
3176         {
3177             if (strcmp(data[0], transform_view[i].table) ||
3178                     strcmp(data[1], transform_view[i].column) ||
3179                     strcmp(data[2], transform_view[i].row))
3180                 continue;
3181 
3182             matched++;
3183             ok(!strcmp(data[3], transform_view[i].data), "%d) data[3] = %s\n", i, data[3]);
3184             ok(!strcmp(data[4], transform_view[i].current), "%d) data[4] = %s\n", i, data[4]);
3185             break;
3186         }
3187         ok(i != ARRAY_SIZE(transform_view), "invalid row: %s, %s, %s\n",
3188                 wine_dbgstr_a(data[0]), wine_dbgstr_a(data[1]), wine_dbgstr_a(data[2]));
3189         MsiCloseHandle(hrec);
3190     }
3191     ok(matched == ARRAY_SIZE(transform_view), "matched = %d\n", matched);
3192 
3193     r = MsiViewClose(hview);
3194     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
3195     r = MsiCloseHandle(hview);
3196     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
3197 
3198     query = "ALTER TABLE `_TransformView` FREE";
3199     r = run_query( hdb, 0, query );
3200     ok( r == ERROR_SUCCESS, "cannot free _TransformView table: %d\n", r );
3201     r = run_query( hdb, 0, query );
3202     ok( r == ERROR_BAD_QUERY_SYNTAX, "_TransformView table still exist: %d\n", r );
3203 
3204     r = MsiDatabaseApplyTransformA( hdb, mstfile, 0 );
3205     ok( r == ERROR_SUCCESS, "return code %d, should be ERROR_SUCCESS\n", r );
3206 
3207     r = MsiDatabaseCommit( hdb );
3208     ok( r == ERROR_SUCCESS , "Failed to commit database\n" );
3209 
3210     /* check new values */
3211     hrec = 0;
3212     query = "select `BAR`,`CAR` from `AAR` where `BAR` = 1 AND `CAR` = 'vw'";
3213     r = do_query(hdb, query, &hrec);
3214     ok(r == ERROR_SUCCESS, "select query failed\n");
3215     MsiCloseHandle(hrec);
3216 
3217     query = "select `BAR`,`CAR` from `AAR` where `BAR` = 2 AND `CAR` = 'bmw'";
3218     hrec = 0;
3219     r = do_query(hdb, query, &hrec);
3220     ok(r == ERROR_SUCCESS, "select query failed\n");
3221     MsiCloseHandle(hrec);
3222 
3223     /* check updated values */
3224     hrec = 0;
3225     query = "select `NOO`,`OOO` from `MOO` where `NOO` = 1 AND `OOO` = 'c'";
3226     r = do_query(hdb, query, &hrec);
3227     ok(r == ERROR_SUCCESS, "select query failed\n");
3228     MsiCloseHandle(hrec);
3229 
3230     /* check unchanged value */
3231     hrec = 0;
3232     query = "select `NOO`,`OOO` from `MOO` where `NOO` = 2 AND `OOO` = 'b'";
3233     r = do_query(hdb, query, &hrec);
3234     ok(r == ERROR_SUCCESS, "select query failed\n");
3235     MsiCloseHandle(hrec);
3236 
3237     /* check deleted value */
3238     hrec = 0;
3239     query = "select * from `MOO` where `NOO` = 3";
3240     r = do_query(hdb, query, &hrec);
3241     ok(r == ERROR_NO_MORE_ITEMS, "select query failed\n");
3242     if (hrec) MsiCloseHandle(hrec);
3243 
3244     /* check added stream */
3245     hrec = 0;
3246     query = "select `BLOB` from `BINARY` where `ID` = 1";
3247     r = do_query(hdb, query, &hrec);
3248     ok(r == ERROR_SUCCESS, "select query failed\n");
3249 
3250     /* check the contents of the stream */
3251     sz = sizeof buffer;
3252     r = MsiRecordReadStream( hrec, 1, buffer, &sz );
3253     ok(r == ERROR_SUCCESS, "read stream failed\n");
3254     ok(!memcmp(buffer, "naengmyon", 9), "stream data was wrong\n");
3255     ok(sz == 9, "stream data was wrong size\n");
3256     if (hrec) MsiCloseHandle(hrec);
3257 
3258     /* check the validity of the table with a deleted row */
3259     hrec = 0;
3260     query = "select * from `MOO`";
3261     r = MsiDatabaseOpenViewA(hdb, query, &hview);
3262     ok(r == ERROR_SUCCESS, "open view failed\n");
3263 
3264     r = MsiViewExecute(hview, 0);
3265     ok(r == ERROR_SUCCESS, "view execute failed\n");
3266 
3267     r = MsiViewFetch(hview, &hrec);
3268     ok(r == ERROR_SUCCESS, "view fetch failed\n");
3269     check_record(hrec, 4, "1", "c", "", "5");
3270     MsiCloseHandle(hrec);
3271 
3272     r = MsiViewFetch(hview, &hrec);
3273     ok(r == ERROR_SUCCESS, "view fetch failed\n");
3274     check_record(hrec, 4, "2", "b", "", "");
3275     MsiCloseHandle(hrec);
3276 
3277     r = MsiViewFetch(hview, &hrec);
3278     ok(r == ERROR_NO_MORE_ITEMS, "view fetch succeeded\n");
3279 
3280     MsiCloseHandle(hrec);
3281     MsiViewClose(hview);
3282     MsiCloseHandle(hview);
3283 
3284     /* check that the property was added */
3285     r = package_from_db(hdb, &hpkg);
3286     if (r == ERROR_INSTALL_PACKAGE_REJECTED)
3287     {
3288         skip("Not enough rights to perform tests\n");
3289         goto error;
3290     }
3291     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
3292 
3293     sz = MAX_PATH;
3294     r = MsiGetPropertyA(hpkg, "prop", buffer, &sz);
3295     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3296     ok(!lstrcmpA(buffer, "val"), "Expected val, got %s\n", buffer);
3297 
3298     MsiCloseHandle(hpkg);
3299 
3300 error:
3301     MsiCloseHandle(hdb);
3302     DeleteFileA(msifile);
3303     DeleteFileA(mstfile);
3304 }
3305 
3306 static const char *join_res_first[][2] =
3307 {
3308     { "alveolar", "procerus" },
3309     { "septum", "procerus" },
3310     { "septum", "nasalis" },
3311     { "ramus", "nasalis" },
3312     { "malar", "mentalis" },
3313 };
3314 
3315 static const char *join_res_second[][2] =
3316 {
3317     { "nasal", "septum" },
3318     { "mandible", "ramus" },
3319 };
3320 
3321 static const char *join_res_third[][2] =
3322 {
3323     { "msvcp.dll", "abcdefgh" },
3324     { "msvcr.dll", "ijklmnop" },
3325 };
3326 
3327 static const char *join_res_fourth[][2] =
3328 {
3329     { "msvcp.dll.01234", "single.dll.31415" },
3330 };
3331 
3332 static const char *join_res_fifth[][2] =
3333 {
3334     { "malar", "procerus" },
3335 };
3336 
3337 static const char *join_res_sixth[][2] =
3338 {
3339     { "malar", "procerus" },
3340     { "malar", "procerus" },
3341     { "malar", "nasalis" },
3342     { "malar", "nasalis" },
3343     { "malar", "nasalis" },
3344     { "malar", "mentalis" },
3345 };
3346 
3347 static const char *join_res_seventh[][2] =
3348 {
3349     { "malar", "nasalis" },
3350     { "malar", "nasalis" },
3351     { "malar", "nasalis" },
3352 };
3353 
3354 static const char *join_res_eighth[][4] =
3355 {
3356     { "msvcp.dll", "msvcp.dll.01234", "msvcp.dll.01234", "abcdefgh" },
3357     { "msvcr.dll", "msvcr.dll.56789", "msvcp.dll.01234", "abcdefgh" },
3358     { "msvcp.dll", "msvcp.dll.01234", "msvcr.dll.56789", "ijklmnop" },
3359     { "msvcr.dll", "msvcr.dll.56789", "msvcr.dll.56789", "ijklmnop" },
3360     { "msvcp.dll", "msvcp.dll.01234", "single.dll.31415", "msvcp.dll" },
3361     { "msvcr.dll", "msvcr.dll.56789", "single.dll.31415", "msvcp.dll" },
3362 };
3363 
3364 static const char *join_res_ninth[][6] =
3365 {
3366     { "1", "2", "3", "4", "7", "8" },
3367     { "1", "2", "5", "6", "7", "8" },
3368     { "1", "2", "3", "4", "9", "10" },
3369     { "1", "2", "5", "6", "9", "10" },
3370     { "1", "2", "3", "4", "11", "12" },
3371     { "1", "2", "5", "6", "11", "12" },
3372 };
3373 
3374 static void test_join(void)
3375 {
3376     MSIHANDLE hdb, hview, hrec;
3377     LPCSTR query;
3378     UINT r;
3379     DWORD i;
3380 
3381     hdb = create_db();
3382     ok( hdb, "failed to create db\n");
3383 
3384     create_component_table( hdb );
3385     add_component_entry( hdb, "'zygomatic', 'malar', 'INSTALLDIR', 0, '', ''" );
3386     add_component_entry( hdb, "'maxilla', 'alveolar', 'INSTALLDIR', 0, '', ''" );
3387     add_component_entry( hdb, "'nasal', 'septum', 'INSTALLDIR', 0, '', ''" );
3388     add_component_entry( hdb, "'mandible', 'ramus', 'INSTALLDIR', 0, '', ''" );
3389 
3390     create_feature_components_table( hdb );
3391     add_feature_components_entry( hdb, "'procerus', 'maxilla'" );
3392     add_feature_components_entry( hdb, "'procerus', 'nasal'" );
3393     add_feature_components_entry( hdb, "'nasalis', 'nasal'" );
3394     add_feature_components_entry( hdb, "'nasalis', 'mandible'" );
3395     add_feature_components_entry( hdb, "'nasalis', 'notacomponent'" );
3396     add_feature_components_entry( hdb, "'mentalis', 'zygomatic'" );
3397 
3398     create_std_dlls_table( hdb );
3399     add_std_dlls_entry( hdb, "'msvcp.dll', 'msvcp.dll.01234'" );
3400     add_std_dlls_entry( hdb, "'msvcr.dll', 'msvcr.dll.56789'" );
3401 
3402     create_binary_table( hdb );
3403     add_binary_entry( hdb, "'msvcp.dll.01234', 'abcdefgh'" );
3404     add_binary_entry( hdb, "'msvcr.dll.56789', 'ijklmnop'" );
3405     add_binary_entry( hdb, "'single.dll.31415', 'msvcp.dll'" );
3406 
3407     query = "CREATE TABLE `One` (`A` SHORT, `B` SHORT PRIMARY KEY `A`)";
3408     r = run_query( hdb, 0, query);
3409     ok(r == ERROR_SUCCESS, "cannot create table: %d\n", r );
3410 
3411     query = "CREATE TABLE `Two` (`C` SHORT, `D` SHORT PRIMARY KEY `C`)";
3412     r = run_query( hdb, 0, query);
3413     ok(r == ERROR_SUCCESS, "cannot create table: %d\n", r );
3414 
3415     query = "CREATE TABLE `Three` (`E` SHORT, `F` SHORT PRIMARY KEY `E`)";
3416     r = run_query( hdb, 0, query);
3417     ok(r == ERROR_SUCCESS, "cannot create table: %d\n", r );
3418 
3419     query = "INSERT INTO `One` (`A`, `B`) VALUES (1, 2)";
3420     r = run_query( hdb, 0, query);
3421     ok(r == ERROR_SUCCESS, "cannot insert into table: %d\n", r );
3422 
3423     query = "INSERT INTO `Two` (`C`, `D`) VALUES (3, 4)";
3424     r = run_query( hdb, 0, query);
3425     ok(r == ERROR_SUCCESS, "cannot insert into table: %d\n", r );
3426 
3427     query = "INSERT INTO `Two` (`C`, `D`) VALUES (5, 6)";
3428     r = run_query( hdb, 0, query);
3429     ok(r == ERROR_SUCCESS, "cannot insert into table: %d\n", r );
3430 
3431     query = "INSERT INTO `Three` (`E`, `F`) VALUES (7, 8)";
3432     r = run_query( hdb, 0, query);
3433     ok(r == ERROR_SUCCESS, "cannot insert into table: %d\n", r );
3434 
3435     query = "INSERT INTO `Three` (`E`, `F`) VALUES (9, 10)";
3436     r = run_query( hdb, 0, query);
3437     ok(r == ERROR_SUCCESS, "cannot insert into table: %d\n", r );
3438 
3439     query = "INSERT INTO `Three` (`E`, `F`) VALUES (11, 12)";
3440     r = run_query( hdb, 0, query);
3441     ok(r == ERROR_SUCCESS, "cannot insert into table: %d\n", r );
3442 
3443     query = "CREATE TABLE `Four` (`G` SHORT, `H` SHORT PRIMARY KEY `G`)";
3444     r = run_query( hdb, 0, query);
3445     ok(r == ERROR_SUCCESS, "cannot create table: %d\n", r );
3446 
3447     query = "CREATE TABLE `Five` (`I` SHORT, `J` SHORT PRIMARY KEY `I`)";
3448     r = run_query( hdb, 0, query);
3449     ok(r == ERROR_SUCCESS, "cannot create table: %d\n", r );
3450 
3451     query = "INSERT INTO `Five` (`I`, `J`) VALUES (13, 14)";
3452     r = run_query( hdb, 0, query);
3453     ok(r == ERROR_SUCCESS, "cannot insert into table: %d\n", r );
3454 
3455     query = "INSERT INTO `Five` (`I`, `J`) VALUES (15, 16)";
3456     r = run_query( hdb, 0, query);
3457     ok(r == ERROR_SUCCESS, "cannot insert into table: %d\n", r );
3458 
3459     query = "SELECT `Component`.`ComponentId`, `FeatureComponents`.`Feature_` "
3460             "FROM `Component`, `FeatureComponents` "
3461             "WHERE `Component`.`Component` = `FeatureComponents`.`Component_` "
3462             "ORDER BY `Feature_`";
3463     r = MsiDatabaseOpenViewA(hdb, query, &hview);
3464     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3465 
3466     r = MsiViewExecute(hview, 0);
3467     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3468 
3469     i = 0;
3470     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3471     {
3472         check_record(hrec, 2, join_res_first[i][0], join_res_first[i][1]);
3473         i++;
3474         MsiCloseHandle(hrec);
3475     }
3476     ok( i == 5, "Expected 5 rows, got %lu\n", i );
3477     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3478 
3479     MsiViewClose(hview);
3480     MsiCloseHandle(hview);
3481 
3482     /* try a join without a WHERE condition */
3483     query = "SELECT `Component`.`ComponentId`, `FeatureComponents`.`Feature_` "
3484             "FROM `Component`, `FeatureComponents` ";
3485     r = MsiDatabaseOpenViewA(hdb, query, &hview);
3486     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3487 
3488     r = MsiViewExecute(hview, 0);
3489     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3490 
3491     i = 0;
3492     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3493     {
3494         i++;
3495         MsiCloseHandle(hrec);
3496     }
3497     ok( i == 24, "Expected 24 rows, got %lu\n", i );
3498 
3499     MsiViewClose(hview);
3500     MsiCloseHandle(hview);
3501 
3502     query = "SELECT DISTINCT Component, ComponentId FROM FeatureComponents, Component "
3503             "WHERE FeatureComponents.Component_=Component.Component "
3504             "AND (Feature_='nasalis') ORDER BY Feature_";
3505     r = MsiDatabaseOpenViewA(hdb, query, &hview);
3506     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3507 
3508     r = MsiViewExecute(hview, 0);
3509     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3510 
3511     i = 0;
3512     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3513     {
3514         check_record(hrec, 2, join_res_second[i][0], join_res_second[i][1]);
3515         i++;
3516         MsiCloseHandle(hrec);
3517     }
3518 
3519     ok( i == 2, "Expected 2 rows, got %lu\n", i );
3520     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3521 
3522     MsiViewClose(hview);
3523     MsiCloseHandle(hview);
3524 
3525     query = "SELECT `StdDlls`.`File`, `Binary`.`Data` "
3526             "FROM `StdDlls`, `Binary` "
3527             "WHERE `StdDlls`.`Binary_` = `Binary`.`Name` "
3528             "ORDER BY `File`";
3529     r = MsiDatabaseOpenViewA(hdb, query, &hview);
3530     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3531 
3532     r = MsiViewExecute(hview, 0);
3533     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3534 
3535     i = 0;
3536     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3537     {
3538         check_record(hrec, 2, join_res_third[i][0], join_res_third[i][1]);
3539         i++;
3540         MsiCloseHandle(hrec);
3541     }
3542     ok( i == 2, "Expected 2 rows, got %lu\n", i );
3543     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3544 
3545     MsiViewClose(hview);
3546     MsiCloseHandle(hview);
3547 
3548     query = "SELECT `StdDlls`.`Binary_`, `Binary`.`Name` "
3549             "FROM `StdDlls`, `Binary` "
3550             "WHERE `StdDlls`.`File` = `Binary`.`Data` "
3551             "ORDER BY `Name`";
3552     r = MsiDatabaseOpenViewA(hdb, query, &hview);
3553     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3554 
3555     r = MsiViewExecute(hview, 0);
3556     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3557 
3558     i = 0;
3559     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3560     {
3561         check_record(hrec, 2, join_res_fourth[i][0], join_res_fourth[i][1]);
3562         i++;
3563         MsiCloseHandle(hrec);
3564     }
3565     ok( i == 1, "Expected 1 rows, got %lu\n", i );
3566     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3567 
3568     MsiViewClose(hview);
3569     MsiCloseHandle(hview);
3570 
3571     query = "SELECT `Component`.`ComponentId`, `FeatureComponents`.`Feature_` "
3572             "FROM `Component`, `FeatureComponents` "
3573             "WHERE `Component`.`Component` = 'zygomatic' "
3574             "AND `FeatureComponents`.`Component_` = 'maxilla' "
3575             "ORDER BY `Feature_`";
3576     r = MsiDatabaseOpenViewA(hdb, query, &hview);
3577     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3578 
3579     r = MsiViewExecute(hview, 0);
3580     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3581 
3582     i = 0;
3583     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3584     {
3585         check_record(hrec, 2, join_res_fifth[i][0], join_res_fifth[i][1]);
3586         i++;
3587         MsiCloseHandle(hrec);
3588     }
3589     ok( i == 1, "Expected 1 rows, got %lu\n", i );
3590     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3591 
3592     MsiViewClose(hview);
3593     MsiCloseHandle(hview);
3594 
3595     query = "SELECT `Component`.`ComponentId`, `FeatureComponents`.`Feature_` "
3596             "FROM `Component`, `FeatureComponents` "
3597             "WHERE `Component` = 'zygomatic' "
3598             "ORDER BY `Feature_`";
3599     r = MsiDatabaseOpenViewA(hdb, query, &hview);
3600     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3601 
3602     r = MsiViewExecute(hview, 0);
3603     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3604 
3605     i = 0;
3606     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3607     {
3608         check_record(hrec, 2, join_res_sixth[i][0], join_res_sixth[i][1]);
3609         i++;
3610         MsiCloseHandle(hrec);
3611     }
3612     ok( i == 6, "Expected 6 rows, got %lu\n", i );
3613     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3614 
3615     MsiViewClose(hview);
3616     MsiCloseHandle(hview);
3617 
3618     query = "SELECT `Component`.`ComponentId`, `FeatureComponents`.`Feature_` "
3619             "FROM `Component`, `FeatureComponents` "
3620             "WHERE `Component` = 'zygomatic' "
3621             "AND `Feature_` = 'nasalis' "
3622             "ORDER BY `Feature_`";
3623     r = MsiDatabaseOpenViewA(hdb, query, &hview);
3624     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3625 
3626     r = MsiViewExecute(hview, 0);
3627     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3628 
3629     i = 0;
3630     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3631     {
3632         check_record(hrec, 2, join_res_seventh[i][0], join_res_seventh[i][1]);
3633         i++;
3634         MsiCloseHandle(hrec);
3635     }
3636     ok( i == 3, "Expected 3 rows, got %lu\n", i );
3637     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3638 
3639     MsiViewClose(hview);
3640     MsiCloseHandle(hview);
3641 
3642     query = "SELECT `StdDlls`.`File`, `Binary`.`Data` "
3643             "FROM `StdDlls`, `Binary` ";
3644     r = MsiDatabaseOpenViewA(hdb, query, &hview);
3645     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3646 
3647     r = MsiViewExecute(hview, 0);
3648     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3649 
3650     i = 0;
3651     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3652     {
3653         check_record(hrec, 2, join_res_eighth[i][0], join_res_eighth[i][3]);
3654         i++;
3655         MsiCloseHandle(hrec);
3656     }
3657     ok( i == 6, "Expected 6 rows, got %lu\n", i );
3658     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3659 
3660     MsiViewClose(hview);
3661     MsiCloseHandle(hview);
3662 
3663     query = "SELECT * FROM `StdDlls`, `Binary` ";
3664     r = MsiDatabaseOpenViewA(hdb, query, &hview);
3665     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3666 
3667     r = MsiViewExecute(hview, 0);
3668     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3669 
3670     i = 0;
3671     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3672     {
3673         check_record(hrec, 4, join_res_eighth[i][0], join_res_eighth[i][1],
3674                 join_res_eighth[i][2], join_res_eighth[i][3]);
3675         i++;
3676         MsiCloseHandle(hrec);
3677     }
3678     ok( i == 6, "Expected 6 rows, got %lu\n", i );
3679     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3680 
3681     MsiViewClose(hview);
3682     MsiCloseHandle(hview);
3683 
3684     query = "SELECT * FROM `One`, `Two`, `Three` ";
3685     r = MsiDatabaseOpenViewA(hdb, query, &hview);
3686     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3687 
3688     r = MsiViewExecute(hview, 0);
3689     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3690 
3691     i = 0;
3692     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3693     {
3694         check_record(hrec, 6, join_res_ninth[i][0], join_res_ninth[i][1],
3695                 join_res_ninth[i][2], join_res_ninth[i][3],
3696                 join_res_ninth[i][4], join_res_ninth[i][5]);
3697         i++;
3698         MsiCloseHandle(hrec);
3699     }
3700     ok( i == 6, "Expected 6 rows, got %lu\n", i );
3701     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3702 
3703     MsiViewClose(hview);
3704     MsiCloseHandle(hview);
3705 
3706     query = "SELECT * FROM `Four`, `Five`";
3707     r = MsiDatabaseOpenViewA(hdb, query, &hview);
3708     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3709 
3710     r = MsiViewExecute(hview, 0);
3711     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3712 
3713     r = MsiViewFetch(hview, &hrec);
3714     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
3715 
3716     MsiViewClose(hview);
3717     MsiCloseHandle(hview);
3718 
3719     query = "SELECT * FROM `Nonexistent`, `One`";
3720     r = MsiDatabaseOpenViewA(hdb, query, &hview);
3721     ok( r == ERROR_BAD_QUERY_SYNTAX,
3722         "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r );
3723 
3724     /* try updating a row in a join table */
3725     query = "SELECT `Component`.`ComponentId`, `FeatureComponents`.`Feature_` "
3726             "FROM `Component`, `FeatureComponents` "
3727             "WHERE `Component`.`Component` = `FeatureComponents`.`Component_` "
3728             "ORDER BY `Feature_`";
3729     r = MsiDatabaseOpenViewA(hdb, query, &hview);
3730     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3731 
3732     r = MsiViewExecute(hview, 0);
3733     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3734 
3735     r = MsiViewFetch(hview, &hrec);
3736     ok( r == ERROR_SUCCESS, "failed to fetch view: %d\n", r );
3737     check_record(hrec, 2, "alveolar", "procerus");
3738 
3739     r = MsiRecordSetStringA( hrec, 1, "fascia" );
3740     ok( r == ERROR_SUCCESS, "failed to set string: %d\n", r );
3741     r = MsiRecordSetStringA( hrec, 2, "pterygoid" );
3742     ok( r == ERROR_SUCCESS, "failed to set string: %d\n", r );
3743 
3744     r = MsiViewModify(hview, MSIMODIFY_REFRESH, hrec);
3745     ok( r == ERROR_SUCCESS, "failed to refresh row: %d\n", r );
3746     check_record(hrec, 2, "alveolar", "procerus");
3747 
3748     r = MsiRecordSetStringA( hrec, 1, "epicranius" );
3749     ok( r == ERROR_SUCCESS, "failed to set string: %d\n", r );
3750 
3751     r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
3752     ok( r == ERROR_SUCCESS, "failed to update row: %d\n", r );
3753 
3754     /* primary key cannot be updated */
3755     r = MsiRecordSetStringA( hrec, 2, "epicranius" );
3756     ok( r == ERROR_SUCCESS, "failed to set string: %d\n", r );
3757 
3758     r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
3759     ok( r == ERROR_FUNCTION_FAILED, "failed to update row: %d\n", r );
3760 
3761     /* all other operations are invalid for joins */
3762     r = MsiViewModify(hview, MSIMODIFY_SEEK, hrec);
3763     ok( r == ERROR_FUNCTION_FAILED, "unexpected result: %d\n", r );
3764 
3765     r = MsiViewModify(hview, MSIMODIFY_ASSIGN, hrec);
3766     ok( r == ERROR_FUNCTION_FAILED, "unexpected result: %d\n", r );
3767 
3768     r = MsiViewModify(hview, MSIMODIFY_REPLACE, hrec);
3769     ok( r == ERROR_FUNCTION_FAILED, "unexpected result: %d\n", r );
3770 
3771     r = MsiViewModify(hview, MSIMODIFY_MERGE, hrec);
3772     ok( r == ERROR_FUNCTION_FAILED, "unexpected result: %d\n", r );
3773 
3774     r = MsiViewModify(hview, MSIMODIFY_DELETE, hrec);
3775     ok( r == ERROR_FUNCTION_FAILED, "unexpected result: %d\n", r );
3776 
3777     r = MsiViewModify(hview, MSIMODIFY_VALIDATE, hrec);
3778     ok( r == ERROR_FUNCTION_FAILED, "unexpected result: %d\n", r );
3779 
3780     r = MsiViewModify(hview, MSIMODIFY_VALIDATE_DELETE, hrec);
3781     ok( r == ERROR_FUNCTION_FAILED, "unexpected result: %d\n", r );
3782 
3783     MsiRecordSetStringA(hrec, 2, "epicranius");
3784     r = MsiViewModify(hview, MSIMODIFY_INSERT, hrec);
3785     ok( r == ERROR_FUNCTION_FAILED, "unexpected result: %d\n", r );
3786 
3787     r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec);
3788     ok( r == ERROR_FUNCTION_FAILED, "unexpected result: %d\n", r );
3789 
3790     r = MsiViewModify(hview, MSIMODIFY_VALIDATE_NEW, hrec);
3791     ok( r == ERROR_FUNCTION_FAILED, "unexpected result: %d\n", r );
3792 
3793     r = MsiViewModify(hview, MSIMODIFY_VALIDATE_FIELD, hrec);
3794     ok( r == ERROR_FUNCTION_FAILED, "unexpected result: %d\n", r );
3795 
3796     MsiCloseHandle(hrec);
3797     MsiViewClose(hview);
3798     MsiCloseHandle(hview);
3799 
3800     r = MsiDatabaseOpenViewA(hdb, query, &hview);
3801     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
3802 
3803     r = MsiViewExecute(hview, 0);
3804     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
3805 
3806     r = MsiViewFetch(hview, &hrec);
3807     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
3808     check_record(hrec, 2, "epicranius", "procerus");
3809     MsiCloseHandle(hrec);
3810 
3811     MsiViewClose(hview);
3812     MsiCloseHandle(hview);
3813 
3814     MsiCloseHandle(hdb);
3815     DeleteFileA(msifile);
3816 }
3817 
3818 static void test_temporary_table(void)
3819 {
3820     MSICONDITION cond;
3821     MSIHANDLE hdb = 0, view = 0, rec;
3822     const char *query;
3823     UINT r;
3824 
3825     cond = MsiDatabaseIsTablePersistentA(0, NULL);
3826     ok( cond == MSICONDITION_ERROR, "wrong return condition\n");
3827 
3828     hdb = create_db();
3829     ok( hdb, "failed to create db\n");
3830 
3831     cond = MsiDatabaseIsTablePersistentA(hdb, NULL);
3832     ok( cond == MSICONDITION_ERROR, "wrong return condition\n");
3833 
3834     cond = MsiDatabaseIsTablePersistentA(hdb, "_Tables");
3835     ok( cond == MSICONDITION_NONE, "wrong return condition\n");
3836 
3837     cond = MsiDatabaseIsTablePersistentA(hdb, "_Columns");
3838     ok( cond == MSICONDITION_NONE, "wrong return condition\n");
3839 
3840     cond = MsiDatabaseIsTablePersistentA(hdb, "_Storages");
3841     ok( cond == MSICONDITION_NONE, "wrong return condition\n");
3842 
3843     cond = MsiDatabaseIsTablePersistentA(hdb, "_Streams");
3844     ok( cond == MSICONDITION_NONE, "wrong return condition\n");
3845 
3846     query = "CREATE TABLE `P` ( `B` SHORT NOT NULL, `C` CHAR(255) PRIMARY KEY `C`)";
3847     r = run_query(hdb, 0, query);
3848     ok(r == ERROR_SUCCESS, "failed to add table\n");
3849 
3850     cond = MsiDatabaseIsTablePersistentA(hdb, "P");
3851     ok( cond == MSICONDITION_TRUE, "wrong return condition\n");
3852 
3853     query = "CREATE TABLE `P2` ( `B` SHORT NOT NULL, `C` CHAR(255) PRIMARY KEY `C`) HOLD";
3854     r = run_query(hdb, 0, query);
3855     ok(r == ERROR_SUCCESS, "failed to add table\n");
3856 
3857     cond = MsiDatabaseIsTablePersistentA(hdb, "P2");
3858     ok( cond == MSICONDITION_TRUE, "wrong return condition\n");
3859 
3860     query = "CREATE TABLE `T` ( `B` SHORT NOT NULL TEMPORARY, `C` CHAR(255) TEMPORARY PRIMARY KEY `C`) HOLD";
3861     r = run_query(hdb, 0, query);
3862     ok(r == ERROR_SUCCESS, "failed to add table\n");
3863 
3864     cond = MsiDatabaseIsTablePersistentA(hdb, "T");
3865     ok( cond == MSICONDITION_FALSE, "wrong return condition\n");
3866 
3867     query = "CREATE TABLE `T2` ( `B` SHORT NOT NULL TEMPORARY, `C` CHAR(255) TEMPORARY PRIMARY KEY `C`)";
3868     r = run_query(hdb, 0, query);
3869     ok(r == ERROR_SUCCESS, "failed to add table\n");
3870 
3871     query = "SELECT * FROM `T2`";
3872     r = MsiDatabaseOpenViewA(hdb, query, &view);
3873     ok(r == ERROR_BAD_QUERY_SYNTAX,
3874        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
3875 
3876     cond = MsiDatabaseIsTablePersistentA(hdb, "T2");
3877     ok( cond == MSICONDITION_NONE, "wrong return condition\n");
3878 
3879     query = "CREATE TABLE `T3` ( `B` SHORT NOT NULL TEMPORARY, `C` CHAR(255) PRIMARY KEY `C`)";
3880     r = run_query(hdb, 0, query);
3881     ok(r == ERROR_SUCCESS, "failed to add table\n");
3882 
3883     cond = MsiDatabaseIsTablePersistentA(hdb, "T3");
3884     ok( cond == MSICONDITION_TRUE, "wrong return condition\n");
3885 
3886     query = "CREATE TABLE `T4` ( `B` SHORT NOT NULL, `C` CHAR(255) TEMPORARY PRIMARY KEY `C`)";
3887     r = run_query(hdb, 0, query);
3888     ok(r == ERROR_FUNCTION_FAILED, "failed to add table\n");
3889 
3890     cond = MsiDatabaseIsTablePersistentA(hdb, "T4");
3891     ok( cond == MSICONDITION_NONE, "wrong return condition\n");
3892 
3893     query = "CREATE TABLE `T5` ( `B` SHORT NOT NULL TEMP, `C` CHAR(255) TEMP PRIMARY KEY `C`) HOLD";
3894     r = run_query(hdb, 0, query);
3895     ok(r == ERROR_BAD_QUERY_SYNTAX, "failed to add table\n");
3896 
3897     query = "select * from `T`";
3898     r = MsiDatabaseOpenViewA(hdb, query, &view);
3899     ok(r == ERROR_SUCCESS, "failed to query table\n");
3900     r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
3901     ok(r == ERROR_SUCCESS, "failed to get column info\n");
3902     check_record(rec, 2, "G255", "j2");
3903     MsiCloseHandle( rec );
3904 
3905     MsiViewClose( view );
3906     MsiCloseHandle( view );
3907 
3908     /* query the table data */
3909     rec = 0;
3910     r = do_query(hdb, "select * from `_Tables` where `Name` = 'T'", &rec);
3911     ok( r == ERROR_SUCCESS, "temporary table exists in _Tables\n");
3912     MsiCloseHandle( rec );
3913 
3914     /* query the column data */
3915     rec = 0;
3916     r = do_query(hdb, "select * from `_Columns` where `Table` = 'T' AND `Name` = 'B'", &rec);
3917     ok( r == ERROR_NO_MORE_ITEMS, "temporary table exists in _Columns\n");
3918     if (rec) MsiCloseHandle( rec );
3919 
3920     r = do_query(hdb, "select * from `_Columns` where `Table` = 'T' AND `Name` = 'C'", &rec);
3921     ok( r == ERROR_NO_MORE_ITEMS, "temporary table exists in _Columns\n");
3922     if (rec) MsiCloseHandle( rec );
3923 
3924     MsiCloseHandle( hdb );
3925     DeleteFileA(msifile);
3926 }
3927 
3928 static void test_alter(void)
3929 {
3930     MSICONDITION cond;
3931     MSIHANDLE hdb = 0, rec;
3932     const char *query;
3933     UINT r;
3934 
3935     hdb = create_db();
3936     ok( hdb, "failed to create db\n");
3937 
3938     query = "CREATE TABLE `T` ( `B` SHORT NOT NULL TEMPORARY, `C` CHAR(255) TEMPORARY PRIMARY KEY `C`)";
3939     r = run_query(hdb, 0, query);
3940     ok(r == ERROR_SUCCESS, "failed to add table\n");
3941 
3942     query = "SELECT * FROM `T`";
3943     r = run_query(hdb, 0, query);
3944     ok(r == ERROR_BAD_QUERY_SYNTAX, "expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
3945 
3946     query = "CREATE TABLE `T` ( `B` SHORT NOT NULL TEMPORARY, `C` CHAR(255) TEMPORARY PRIMARY KEY `C`) HOLD";
3947     r = run_query(hdb, 0, query);
3948     ok(r == ERROR_SUCCESS, "failed to add table\n");
3949 
3950     query = "SELECT * FROM `T`";
3951     r = run_query(hdb, 0, query);
3952     ok(r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", r);
3953 
3954     cond = MsiDatabaseIsTablePersistentA(hdb, "T");
3955     ok( cond == MSICONDITION_FALSE, "wrong return condition\n");
3956 
3957     query = "ALTER TABLE `T` HOLD";
3958     r = run_query(hdb, 0, query);
3959     ok(r == ERROR_SUCCESS, "failed to hold table %d\n", r);
3960 
3961     query = "ALTER TABLE `T` FREE";
3962     r = run_query(hdb, 0, query);
3963     ok(r == ERROR_SUCCESS, "failed to free table\n");
3964 
3965     query = "ALTER TABLE `T` FREE";
3966     r = run_query(hdb, 0, query);
3967     ok(r == ERROR_SUCCESS, "failed to free table\n");
3968 
3969     query = "ALTER TABLE `T` FREE";
3970     r = run_query(hdb, 0, query);
3971     ok(r == ERROR_BAD_QUERY_SYNTAX, "failed to free table\n");
3972 
3973     query = "ALTER TABLE `T` HOLD";
3974     r = run_query(hdb, 0, query);
3975     ok(r == ERROR_BAD_QUERY_SYNTAX, "failed to hold table %d\n", r);
3976 
3977     /* table T is removed */
3978     query = "SELECT * FROM `T`";
3979     r = run_query(hdb, 0, query);
3980     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
3981 
3982     /* create the table again */
3983     query = "CREATE TABLE `U` ( `A` INTEGER, `B` INTEGER PRIMARY KEY `B`)";
3984     r = run_query(hdb, 0, query);
3985     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3986 
3987     /* up the ref count */
3988     query = "ALTER TABLE `U` HOLD";
3989     r = run_query(hdb, 0, query);
3990     ok(r == ERROR_SUCCESS, "failed to free table\n");
3991 
3992     /* add column, no data type */
3993     query = "ALTER TABLE `U` ADD `C`";
3994     r = run_query(hdb, 0, query);
3995     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
3996 
3997     query = "ALTER TABLE `U` ADD `C` INTEGER";
3998     r = run_query(hdb, 0, query);
3999     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4000 
4001     query = "SELECT * FROM `_Columns` WHERE `Table` = 'U' AND `Name` = 'C'";
4002     r = do_query(hdb, query, &rec);
4003     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4004 
4005     /* add column C again */
4006     query = "ALTER TABLE `U` ADD `C` INTEGER";
4007     r = run_query(hdb, 0, query);
4008     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
4009 
4010     query = "ALTER TABLE `U` ADD `D` INTEGER TEMPORARY";
4011     r = run_query(hdb, 0, query);
4012     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4013 
4014     query = "INSERT INTO `U` ( `A`, `B`, `C`, `D` ) VALUES ( 1, 2, 3, 4 )";
4015     r = run_query(hdb, 0, query);
4016     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4017 
4018     query = "ALTER TABLE `U` ADD `D` INTEGER TEMPORARY HOLD";
4019     r = run_query(hdb, 0, query);
4020     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
4021 
4022     query = "SELECT * FROM `_Columns` WHERE `Table` = 'U' AND `Name` = 'D'";
4023     r = do_query(hdb, query, &rec);
4024     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
4025 
4026     query = "INSERT INTO `U` ( `A`, `B`, `C`, `D` ) VALUES ( 5, 6, 7, 8 )";
4027     r = run_query(hdb, 0, query);
4028     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4029 
4030     query = "SELECT * FROM `U` WHERE `D` = 8";
4031     r = run_query(hdb, 0, query);
4032     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4033 
4034     query = "ALTER TABLE `U` ADD `D` INTEGER TEMPORARY FREE";
4035     r = run_query(hdb, 0, query);
4036     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
4037 
4038     query = "ALTER COLUMN `D` FREE";
4039     r = run_query(hdb, 0, query);
4040     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
4041 
4042     /* drop the ref count */
4043     query = "ALTER TABLE `U` FREE";
4044     r = run_query(hdb, 0, query);
4045     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4046 
4047     /* table is not empty */
4048     query = "SELECT * FROM `U`";
4049     r = run_query(hdb, 0, query);
4050     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4051 
4052     /* column D is removed */
4053     query = "SELECT * FROM `U` WHERE `D` = 8";
4054     r = run_query(hdb, 0, query);
4055     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
4056 
4057     query = "INSERT INTO `U` ( `A`, `B`, `C`, `D` ) VALUES ( 9, 10, 11, 12 )";
4058     r = run_query(hdb, 0, query);
4059     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
4060 
4061     /* add the column again */
4062     query = "ALTER TABLE `U` ADD `E` INTEGER TEMPORARY HOLD";
4063     r = run_query(hdb, 0, query);
4064     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4065 
4066     /* up the ref count */
4067     query = "ALTER TABLE `U` HOLD";
4068     r = run_query(hdb, 0, query);
4069     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4070 
4071     query = "INSERT INTO `U` ( `A`, `B`, `C`, `E` ) VALUES ( 13, 14, 15, 16 )";
4072     r = run_query(hdb, 0, query);
4073     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4074 
4075     query = "SELECT * FROM `U` WHERE `E` = 16";
4076     r = run_query(hdb, 0, query);
4077     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4078 
4079     /* drop the ref count */
4080     query = "ALTER TABLE `U` FREE";
4081     r = run_query(hdb, 0, query);
4082     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4083 
4084     query = "INSERT INTO `U` ( `A`, `B`, `C`, `E` ) VALUES ( 17, 18, 19, 20 )";
4085     r = run_query(hdb, 0, query);
4086     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4087 
4088     query = "SELECT * FROM `U` WHERE `E` = 20";
4089     r = run_query(hdb, 0, query);
4090     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4091 
4092     /* drop the ref count */
4093     query = "ALTER TABLE `U` FREE";
4094     r = run_query(hdb, 0, query);
4095     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4096 
4097     /* table still exists */
4098     query = "SELECT * FROM `U`";
4099     r = run_query(hdb, 0, query);
4100     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4101 
4102     /* col E is removed */
4103     query = "SELECT * FROM `U` WHERE `E` = 20";
4104     r = run_query(hdb, 0, query);
4105     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
4106 
4107     query = "INSERT INTO `U` ( `A`, `B`, `C`, `E` ) VALUES ( 20, 21, 22, 23 )";
4108     r = run_query(hdb, 0, query);
4109     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
4110 
4111     /* drop the ref count once more */
4112     query = "ALTER TABLE `U` FREE";
4113     r = run_query(hdb, 0, query);
4114     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4115 
4116     /* table still exists */
4117     query = "SELECT * FROM `U`";
4118     r = run_query(hdb, 0, query);
4119     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4120 
4121     MsiCloseHandle( hdb );
4122     DeleteFileA(msifile);
4123 }
4124 
4125 static void test_integers(void)
4126 {
4127     MSIHANDLE hdb = 0, view = 0, rec = 0;
4128     DWORD i;
4129     const char *query;
4130     UINT r;
4131 
4132     /* just MsiOpenDatabase should not create a file */
4133     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
4134     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
4135 
4136     /* create a table */
4137     query = "CREATE TABLE `integers` ( "
4138             "`one` SHORT, `two` INT, `three` INTEGER, `four` LONG, "
4139             "`five` SHORT NOT NULL, `six` INT NOT NULL, "
4140             "`seven` INTEGER NOT NULL, `eight` LONG NOT NULL "
4141             "PRIMARY KEY `one`)";
4142     r = MsiDatabaseOpenViewA(hdb, query, &view);
4143     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
4144     r = MsiViewExecute(view, 0);
4145     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
4146     r = MsiViewClose(view);
4147     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4148     r = MsiCloseHandle(view);
4149     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4150 
4151     query = "SELECT * FROM `integers`";
4152     r = MsiDatabaseOpenViewA(hdb, query, &view);
4153     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4154 
4155     r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec);
4156     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4157     check_record(rec, 8, "one", "two", "three", "four", "five", "six", "seven", "eight");
4158     MsiCloseHandle(rec);
4159 
4160     r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
4161     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4162     check_record(rec, 8, "I2", "I2", "I2", "I4", "i2", "i2", "i2", "i4");
4163     MsiCloseHandle(rec);
4164 
4165     MsiViewClose(view);
4166     MsiCloseHandle(view);
4167 
4168     /* insert values into it, NULL where NOT NULL is specified */
4169     query = "INSERT INTO `integers` ( `one`, `two`, `three`, `four`, `five`, `six`, `seven`, `eight` )"
4170         "VALUES('', '', '', '', '', '', '', '')";
4171     r = MsiDatabaseOpenViewA(hdb, query, &view);
4172     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4173     r = MsiViewExecute(view, 0);
4174     ok(r == ERROR_FUNCTION_FAILED, "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
4175 
4176     MsiViewClose(view);
4177     MsiCloseHandle(view);
4178 
4179     query = "SELECT * FROM `integers`";
4180     r = do_query(hdb, query, &rec);
4181     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
4182 
4183     r = MsiRecordGetFieldCount(rec);
4184     ok(r == -1, "record count wrong: %d\n", r);
4185 
4186     MsiCloseHandle(rec);
4187 
4188     /* insert legitimate values into it */
4189     query = "INSERT INTO `integers` ( `one`, `two`, `three`, `four`, `five`, `six`, `seven`, `eight` )"
4190         "VALUES('', '2', '', '4', '5', '6', '7', '8')";
4191     r = MsiDatabaseOpenViewA(hdb, query, &view);
4192     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4193     r = MsiViewExecute(view, 0);
4194     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4195 
4196     query = "SELECT * FROM `integers`";
4197     r = do_query(hdb, query, &rec);
4198     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4199 
4200     r = MsiRecordGetFieldCount(rec);
4201     ok(r == 8, "record count wrong: %d\n", r);
4202 
4203     i = MsiRecordGetInteger(rec, 1);
4204     ok(i == MSI_NULL_INTEGER, "Expected MSI_NULL_INTEGER, got %lu\n", i);
4205     i = MsiRecordGetInteger(rec, 3);
4206     ok(i == MSI_NULL_INTEGER, "Expected MSI_NULL_INTEGER, got %lu\n", i);
4207     i = MsiRecordGetInteger(rec, 2);
4208     ok(i == 2, "Expected 2, got %lu\n", i);
4209     i = MsiRecordGetInteger(rec, 4);
4210     ok(i == 4, "Expected 4, got %lu\n", i);
4211     i = MsiRecordGetInteger(rec, 5);
4212     ok(i == 5, "Expected 5, got %lu\n", i);
4213     i = MsiRecordGetInteger(rec, 6);
4214     ok(i == 6, "Expected 6, got %lu\n", i);
4215     i = MsiRecordGetInteger(rec, 7);
4216     ok(i == 7, "Expected 7, got %lu\n", i);
4217     i = MsiRecordGetInteger(rec, 8);
4218     ok(i == 8, "Expected 8, got %lu\n", i);
4219 
4220     MsiCloseHandle(rec);
4221     MsiViewClose(view);
4222     MsiCloseHandle(view);
4223 
4224     r = MsiDatabaseCommit(hdb);
4225     ok(r == ERROR_SUCCESS, "MsiDatabaseCommit failed\n");
4226 
4227     r = MsiCloseHandle(hdb);
4228     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4229 
4230     r = DeleteFileA(msifile);
4231     ok(r == TRUE, "file didn't exist after commit\n");
4232 }
4233 
4234 static void test_update(void)
4235 {
4236     MSIHANDLE hdb = 0, view = 0, rec = 0;
4237     const char *query;
4238     UINT r;
4239 
4240     /* just MsiOpenDatabase should not create a file */
4241     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
4242     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
4243 
4244     /* create the Control table */
4245     query = "CREATE TABLE `Control` ( "
4246         "`Dialog_` CHAR(72) NOT NULL, `Control` CHAR(50) NOT NULL, `Type` SHORT NOT NULL, "
4247         "`X` SHORT NOT NULL, `Y` SHORT NOT NULL, `Width` SHORT NOT NULL, `Height` SHORT NOT NULL,"
4248         "`Attributes` LONG, `Property` CHAR(50), `Text` CHAR(0) LOCALIZABLE, "
4249         "`Control_Next` CHAR(50), `Help` CHAR(50) LOCALIZABLE PRIMARY KEY `Dialog_`, `Control`)";
4250     r = MsiDatabaseOpenViewA(hdb, query, &view);
4251     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
4252     r = MsiViewExecute(view, 0);
4253     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
4254     r = MsiViewClose(view);
4255     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4256     r = MsiCloseHandle(view);
4257     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4258 
4259     /* add a control */
4260     query = "INSERT INTO `Control` ( "
4261         "`Dialog_`, `Control`, `Type`, `X`, `Y`, `Width`, `Height`, "
4262         "`Property`, `Text`, `Control_Next`, `Help` )"
4263         "VALUES('ErrorDialog', 'ErrorText', '1', '5', '5', '5', '5', '', '', '', '')";
4264     r = MsiDatabaseOpenViewA(hdb, query, &view);
4265     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4266     r = MsiViewExecute(view, 0);
4267     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4268     r = MsiViewClose(view);
4269     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4270     r = MsiCloseHandle(view);
4271     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4272 
4273     /* add a second control */
4274     query = "INSERT INTO `Control` ( "
4275         "`Dialog_`, `Control`, `Type`, `X`, `Y`, `Width`, `Height`, "
4276         "`Property`, `Text`, `Control_Next`, `Help` )"
4277         "VALUES('ErrorDialog', 'Button', '1', '5', '5', '5', '5', '', '', '', '')";
4278     r = MsiDatabaseOpenViewA(hdb, query, &view);
4279     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4280     r = MsiViewExecute(view, 0);
4281     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4282     r = MsiViewClose(view);
4283     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4284     r = MsiCloseHandle(view);
4285     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4286 
4287     /* add a third control */
4288     query = "INSERT INTO `Control` ( "
4289         "`Dialog_`, `Control`, `Type`, `X`, `Y`, `Width`, `Height`, "
4290         "`Property`, `Text`, `Control_Next`, `Help` )"
4291         "VALUES('AnotherDialog', 'ErrorText', '1', '5', '5', '5', '5', '', '', '', '')";
4292     r = MsiDatabaseOpenViewA(hdb, query, &view);
4293     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4294     r = MsiViewExecute(view, 0);
4295     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4296     r = MsiViewClose(view);
4297     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4298     r = MsiCloseHandle(view);
4299     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4300 
4301     /* bad table */
4302     query = "UPDATE `NotATable` SET `Text` = 'this is text' WHERE `Dialog_` = 'ErrorDialog'";
4303     r = MsiDatabaseOpenViewA(hdb, query, &view);
4304     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
4305 
4306     /* bad set column */
4307     query = "UPDATE `Control` SET `NotAColumn` = 'this is text' WHERE `Dialog_` = 'ErrorDialog'";
4308     r = MsiDatabaseOpenViewA(hdb, query, &view);
4309     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
4310 
4311     /* bad where condition */
4312     query = "UPDATE `Control` SET `Text` = 'this is text' WHERE `NotAColumn` = 'ErrorDialog'";
4313     r = MsiDatabaseOpenViewA(hdb, query, &view);
4314     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
4315 
4316     /* just the dialog_ specified */
4317     query = "UPDATE `Control` SET `Text` = 'this is text' WHERE `Dialog_` = 'ErrorDialog'";
4318     r = MsiDatabaseOpenViewA(hdb, query, &view);
4319     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4320     r = MsiViewExecute(view, 0);
4321     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4322     r = MsiViewClose(view);
4323     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4324     r = MsiCloseHandle(view);
4325     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4326 
4327     /* check the modified text */
4328     query = "SELECT `Text` FROM `Control` WHERE `Control` = 'ErrorText'";
4329     r = MsiDatabaseOpenViewA(hdb, query, &view);
4330     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4331     r = MsiViewExecute(view, 0);
4332     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4333 
4334     r = MsiViewFetch(view, &rec);
4335     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4336     check_record(rec, 1, "this is text");
4337     MsiCloseHandle(rec);
4338 
4339     r = MsiViewFetch(view, &rec);
4340     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4341     check_record(rec, 1, "");
4342     MsiCloseHandle(rec);
4343 
4344     r = MsiViewFetch(view, &rec);
4345     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
4346 
4347     r = MsiViewClose(view);
4348     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4349     r = MsiCloseHandle(view);
4350     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4351 
4352     /* dialog_ and control specified */
4353     query = "UPDATE `Control` SET `Text` = 'this is text' WHERE `Dialog_` = 'ErrorDialog' AND `Control` = 'ErrorText'";
4354     r = MsiDatabaseOpenViewA(hdb, query, &view);
4355     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4356     r = MsiViewExecute(view, 0);
4357     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4358     r = MsiViewClose(view);
4359     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4360     r = MsiCloseHandle(view);
4361     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4362 
4363     /* check the modified text */
4364     query = "SELECT `Text` FROM `Control` WHERE `Control` = 'ErrorText'";
4365     r = MsiDatabaseOpenViewA(hdb, query, &view);
4366     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4367     r = MsiViewExecute(view, 0);
4368     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4369 
4370     r = MsiViewFetch(view, &rec);
4371     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4372     check_record(rec, 1, "this is text");
4373     MsiCloseHandle(rec);
4374 
4375     r = MsiViewFetch(view, &rec);
4376     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4377     check_record(rec, 1, "");
4378     MsiCloseHandle(rec);
4379 
4380     r = MsiViewFetch(view, &rec);
4381     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
4382 
4383     r = MsiViewClose(view);
4384     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4385     r = MsiCloseHandle(view);
4386     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4387 
4388     /* no where condition */
4389     query = "UPDATE `Control` SET `Text` = 'this is text'";
4390     r = MsiDatabaseOpenViewA(hdb, query, &view);
4391     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4392     r = MsiViewExecute(view, 0);
4393     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4394     r = MsiViewClose(view);
4395     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4396     r = MsiCloseHandle(view);
4397     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4398 
4399     /* check the modified text */
4400     query = "SELECT `Text` FROM `Control`";
4401     r = MsiDatabaseOpenViewA(hdb, query, &view);
4402     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4403     r = MsiViewExecute(view, 0);
4404     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4405 
4406     r = MsiViewFetch(view, &rec);
4407     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4408     check_record(rec, 1, "this is text");
4409     MsiCloseHandle(rec);
4410 
4411     r = MsiViewFetch(view, &rec);
4412     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4413     check_record(rec, 1, "this is text");
4414     MsiCloseHandle(rec);
4415 
4416     r = MsiViewFetch(view, &rec);
4417     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4418     check_record(rec, 1, "this is text");
4419     MsiCloseHandle(rec);
4420 
4421     r = MsiViewFetch(view, &rec);
4422     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
4423 
4424     r = MsiViewClose(view);
4425     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4426     r = MsiCloseHandle(view);
4427     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4428 
4429     query = "CREATE TABLE `Apple` ( `Banana` CHAR(72) NOT NULL, "
4430         "`Orange` CHAR(72),  `Pear` INT PRIMARY KEY `Banana`)";
4431     r = run_query(hdb, 0, query);
4432     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4433 
4434     query = "INSERT INTO `Apple` ( `Banana`, `Orange`, `Pear` )"
4435         "VALUES('one', 'two', 3)";
4436     r = run_query(hdb, 0, query);
4437     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4438 
4439     query = "INSERT INTO `Apple` ( `Banana`, `Orange`, `Pear` )"
4440         "VALUES('three', 'four', 5)";
4441     r = run_query(hdb, 0, query);
4442     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4443 
4444     query = "INSERT INTO `Apple` ( `Banana`, `Orange`, `Pear` )"
4445         "VALUES('six', 'two', 7)";
4446     r = run_query(hdb, 0, query);
4447     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4448 
4449     rec = MsiCreateRecord(2);
4450     MsiRecordSetInteger(rec, 1, 8);
4451     MsiRecordSetStringA(rec, 2, "two");
4452 
4453     query = "UPDATE `Apple` SET `Pear` = ? WHERE `Orange` = ?";
4454     r = run_query(hdb, rec, query);
4455     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4456 
4457     MsiCloseHandle(rec);
4458 
4459     query = "SELECT `Pear` FROM `Apple` ORDER BY `Orange`";
4460     r = MsiDatabaseOpenViewA(hdb, query, &view);
4461     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4462     r = MsiViewExecute(view, 0);
4463     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4464 
4465     r = MsiViewFetch(view, &rec);
4466     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4467 
4468     r = MsiRecordGetInteger(rec, 1);
4469     ok(r == 8, "Expected 8, got %d\n", r);
4470 
4471     MsiCloseHandle(rec);
4472 
4473     r = MsiViewFetch(view, &rec);
4474     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4475 
4476     r = MsiRecordGetInteger(rec, 1);
4477     ok(r == 8, "Expected 8, got %d\n", r);
4478 
4479     MsiCloseHandle(rec);
4480 
4481     r = MsiViewFetch(view, &rec);
4482     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4483 
4484     r = MsiRecordGetInteger(rec, 1);
4485     ok(r == 5, "Expected 5, got %d\n", r);
4486 
4487     MsiCloseHandle(rec);
4488 
4489     r = MsiViewFetch(view, &rec);
4490     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
4491 
4492     MsiViewClose(view);
4493     MsiCloseHandle(view);
4494 
4495     r = MsiDatabaseCommit(hdb);
4496     ok(r == ERROR_SUCCESS, "MsiDatabaseCommit failed\n");
4497     r = MsiCloseHandle(hdb);
4498     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4499 
4500     DeleteFileA(msifile);
4501 }
4502 
4503 static void test_special_tables(void)
4504 {
4505     const char *query;
4506     MSIHANDLE hdb = 0;
4507     UINT r;
4508 
4509     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
4510     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
4511 
4512     query = "CREATE TABLE `_Properties` ( "
4513         "`foo` INT NOT NULL, `bar` INT LOCALIZABLE PRIMARY KEY `foo`)";
4514     r = run_query(hdb, 0, query);
4515     ok(r == ERROR_SUCCESS, "failed to create table\n");
4516 
4517     query = "CREATE TABLE `_Storages` ( "
4518         "`foo` INT NOT NULL, `bar` INT LOCALIZABLE PRIMARY KEY `foo`)";
4519     r = run_query(hdb, 0, query);
4520     ok(r == ERROR_BAD_QUERY_SYNTAX, "created _Streams table\n");
4521 
4522     query = "CREATE TABLE `_Streams` ( "
4523         "`foo` INT NOT NULL, `bar` INT LOCALIZABLE PRIMARY KEY `foo`)";
4524     r = run_query(hdb, 0, query);
4525     ok(r == ERROR_BAD_QUERY_SYNTAX, "created _Streams table\n");
4526 
4527     query = "CREATE TABLE `_Tables` ( "
4528         "`foo` INT NOT NULL, `bar` INT LOCALIZABLE PRIMARY KEY `foo`)";
4529     r = run_query(hdb, 0, query);
4530     ok(r == ERROR_BAD_QUERY_SYNTAX, "created _Tables table\n");
4531 
4532     query = "CREATE TABLE `_Columns` ( "
4533         "`foo` INT NOT NULL, `bar` INT LOCALIZABLE PRIMARY KEY `foo`)";
4534     r = run_query(hdb, 0, query);
4535     ok(r == ERROR_BAD_QUERY_SYNTAX, "created _Columns table\n");
4536 
4537     r = MsiCloseHandle(hdb);
4538     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4539 }
4540 
4541 static void test_tables_order(void)
4542 {
4543     const char *query;
4544     MSIHANDLE hdb = 0, hview = 0, hrec = 0;
4545     UINT r;
4546 
4547     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
4548     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
4549 
4550     query = "CREATE TABLE `foo` ( "
4551         "`baz` INT NOT NULL PRIMARY KEY `baz`)";
4552     r = run_query(hdb, 0, query);
4553     ok(r == ERROR_SUCCESS, "failed to create table\n");
4554 
4555     query = "CREATE TABLE `bar` ( "
4556         "`foo` INT NOT NULL PRIMARY KEY `foo`)";
4557     r = run_query(hdb, 0, query);
4558     ok(r == ERROR_SUCCESS, "failed to create table\n");
4559 
4560     query = "CREATE TABLE `baz` ( "
4561         "`bar` INT NOT NULL, "
4562         "`baz` INT NOT NULL, "
4563         "`foo` INT NOT NULL PRIMARY KEY `bar`)";
4564     r = run_query(hdb, 0, query);
4565     ok(r == ERROR_SUCCESS, "failed to create table\n");
4566 
4567     /* The names of the tables in the _Tables table must
4568        be in the same order as these names are created in
4569        the strings table. */
4570     query = "SELECT `Name` FROM `_Tables`";
4571     r = MsiDatabaseOpenViewA(hdb, query, &hview);
4572     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
4573     r = MsiViewExecute(hview, 0);
4574     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
4575 
4576     r = MsiViewFetch(hview, &hrec);
4577     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4578     check_record(hrec, 1, "foo");
4579     r = MsiCloseHandle(hrec);
4580     ok(r == ERROR_SUCCESS, "failed to close record\n");
4581 
4582     r = MsiViewFetch(hview, &hrec);
4583     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4584     check_record(hrec, 1, "baz");
4585     r = MsiCloseHandle(hrec);
4586     ok(r == ERROR_SUCCESS, "failed to close record\n");
4587 
4588     r = MsiViewFetch(hview, &hrec);
4589     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4590     check_record(hrec, 1, "bar");
4591     r = MsiCloseHandle(hrec);
4592     ok(r == ERROR_SUCCESS, "failed to close record\n");
4593 
4594     r = MsiViewClose(hview);
4595     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4596     r = MsiCloseHandle(hview);
4597     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4598 
4599     /* The names of the tables in the _Columns table must
4600        be in the same order as these names are created in
4601        the strings table. */
4602     query = "SELECT `Table`, `Number`, `Name` FROM `_Columns`";
4603     r = MsiDatabaseOpenViewA(hdb, query, &hview);
4604     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
4605     r = MsiViewExecute(hview, 0);
4606     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
4607 
4608     r = MsiViewFetch(hview, &hrec);
4609     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4610     check_record(hrec, 3, "foo", "1", "baz");
4611     r = MsiCloseHandle(hrec);
4612     ok(r == ERROR_SUCCESS, "failed to close record\n");
4613 
4614     r = MsiViewFetch(hview, &hrec);
4615     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4616     check_record(hrec, 3, "baz", "1", "bar");
4617     r = MsiCloseHandle(hrec);
4618     ok(r == ERROR_SUCCESS, "failed to close record\n");
4619 
4620     r = MsiViewFetch(hview, &hrec);
4621     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4622     check_record(hrec, 3, "baz", "2", "baz");
4623     r = MsiCloseHandle(hrec);
4624     ok(r == ERROR_SUCCESS, "failed to close record\n");
4625 
4626     r = MsiViewFetch(hview, &hrec);
4627     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4628     check_record(hrec, 3, "baz", "3", "foo");
4629     r = MsiCloseHandle(hrec);
4630     ok(r == ERROR_SUCCESS, "failed to close record\n");
4631 
4632     r = MsiViewFetch(hview, &hrec);
4633     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4634     check_record(hrec, 3, "bar", "1", "foo");
4635     r = MsiCloseHandle(hrec);
4636     ok(r == ERROR_SUCCESS, "failed to close record\n");
4637 
4638     r = MsiViewClose(hview);
4639     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4640     r = MsiCloseHandle(hview);
4641     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4642 
4643     r = MsiCloseHandle(hdb);
4644     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4645 
4646     DeleteFileA(msifile);
4647 }
4648 
4649 static void test_rows_order(void)
4650 {
4651     const char *query;
4652     MSIHANDLE hdb = 0, hview = 0, hrec = 0;
4653     UINT r;
4654 
4655     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
4656     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
4657 
4658     query = "CREATE TABLE `foo` ( "
4659         "`bar` LONGCHAR NOT NULL PRIMARY KEY `bar`)";
4660     r = run_query(hdb, 0, query);
4661     ok(r == ERROR_SUCCESS, "failed to create table\n");
4662 
4663     r = run_query(hdb, 0, "INSERT INTO `foo` "
4664             "( `bar` ) VALUES ( 'A' )");
4665     ok(r == ERROR_SUCCESS, "cannot add value to table\n");
4666 
4667     r = run_query(hdb, 0, "INSERT INTO `foo` "
4668             "( `bar` ) VALUES ( 'B' )");
4669     ok(r == ERROR_SUCCESS, "cannot add value to table\n");
4670 
4671     r = run_query(hdb, 0, "INSERT INTO `foo` "
4672             "( `bar` ) VALUES ( 'C' )");
4673     ok(r == ERROR_SUCCESS, "cannot add value to table\n");
4674 
4675     r = run_query(hdb, 0, "INSERT INTO `foo` "
4676             "( `bar` ) VALUES ( 'D' )");
4677     ok(r == ERROR_SUCCESS, "cannot add value to table\n");
4678 
4679     r = run_query(hdb, 0, "INSERT INTO `foo` "
4680             "( `bar` ) VALUES ( 'E' )");
4681     ok(r == ERROR_SUCCESS, "cannot add value to table\n");
4682 
4683     r = run_query(hdb, 0, "INSERT INTO `foo` "
4684             "( `bar` ) VALUES ( 'F' )");
4685     ok(r == ERROR_SUCCESS, "cannot add value to table\n");
4686 
4687     query = "CREATE TABLE `bar` ( "
4688         "`foo` LONGCHAR NOT NULL, "
4689         "`baz` LONGCHAR NOT NULL "
4690         "PRIMARY KEY `foo` )";
4691     r = run_query(hdb, 0, query);
4692     ok(r == ERROR_SUCCESS, "failed to create table\n");
4693 
4694     r = run_query(hdb, 0, "INSERT INTO `bar` "
4695             "( `foo`, `baz` ) VALUES ( 'C', 'E' )");
4696     ok(r == ERROR_SUCCESS, "cannot add value to table\n");
4697 
4698     r = run_query(hdb, 0, "INSERT INTO `bar` "
4699             "( `foo`, `baz` ) VALUES ( 'F', 'A' )");
4700     ok(r == ERROR_SUCCESS, "cannot add value to table\n");
4701 
4702     r = run_query(hdb, 0, "INSERT INTO `bar` "
4703             "( `foo`, `baz` ) VALUES ( 'A', 'B' )");
4704     ok(r == ERROR_SUCCESS, "cannot add value to table\n");
4705 
4706     r = run_query(hdb, 0, "INSERT INTO `bar` "
4707             "( `foo`, `baz` ) VALUES ( 'D', 'E' )");
4708     ok(r == ERROR_SUCCESS, "cannot add value to table\n");
4709 
4710     /* The rows of the table must be ordered by the column values of
4711        each row. For strings, the column value is the string id
4712        in the string table.  */
4713 
4714     query = "SELECT * FROM `bar`";
4715     r = MsiDatabaseOpenViewA(hdb, query, &hview);
4716     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
4717     r = MsiViewExecute(hview, 0);
4718     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
4719 
4720     r = MsiViewFetch(hview, &hrec);
4721     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4722     check_record(hrec, 2, "A", "B");
4723     r = MsiCloseHandle(hrec);
4724     ok(r == ERROR_SUCCESS, "failed to close record\n");
4725 
4726     r = MsiViewFetch(hview, &hrec);
4727     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4728     check_record(hrec, 2, "C", "E");
4729     r = MsiCloseHandle(hrec);
4730     ok(r == ERROR_SUCCESS, "failed to close record\n");
4731 
4732     r = MsiViewFetch(hview, &hrec);
4733     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4734     check_record(hrec, 2, "D", "E");
4735     r = MsiCloseHandle(hrec);
4736     ok(r == ERROR_SUCCESS, "failed to close record\n");
4737 
4738     r = MsiViewFetch(hview, &hrec);
4739     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4740     check_record(hrec, 2, "F", "A");
4741     r = MsiCloseHandle(hrec);
4742     ok(r == ERROR_SUCCESS, "failed to close record\n");
4743 
4744     r = MsiViewClose(hview);
4745     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4746     r = MsiCloseHandle(hview);
4747     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4748 
4749     r = MsiCloseHandle(hdb);
4750     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4751 
4752     DeleteFileA(msifile);
4753 }
4754 
4755 static void test_collation(void)
4756 {
4757     const char *query;
4758     MSIHANDLE hdb = 0, hview = 0, hrec = 0;
4759     UINT r;
4760     char buffer[100];
4761     WCHAR bufferW[100];
4762     DWORD sz;
4763 
4764     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
4765     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
4766 
4767     query = "CREATE TABLE `bar` ( "
4768         "`foo` LONGCHAR NOT NULL, "
4769         "`baz` LONGCHAR NOT NULL "
4770         "PRIMARY KEY `foo` )";
4771     r = run_query(hdb, 0, query);
4772     ok(r == ERROR_SUCCESS, "failed to create table\n");
4773 
4774     r = run_query(hdb, 0, query);
4775     ok(r == ERROR_BAD_QUERY_SYNTAX, "wrong error %u\n", r);
4776 
4777     r = run_query(hdb, 0, "INSERT INTO `bar` "
4778             "( `foo`, `baz` ) VALUES ( '\2', 'A' )");
4779     ok(r == ERROR_SUCCESS, "cannot add value to table %u\n", r);
4780 
4781     r = run_query(hdb, 0, "INSERT INTO `bar` "
4782             "( `foo`, `baz` ) VALUES ( '\1', 'B' )");
4783     ok(r == ERROR_SUCCESS, "cannot add value to table %u\n", r);
4784 
4785     r = run_queryW(hdb, 0, L"INSERT INTO `bar` (`foo`,`baz`) VALUES ('a\x30a','C')");
4786     ok(r == ERROR_SUCCESS, "cannot add value to table %u\n", r);
4787 
4788     r = run_queryW(hdb, 0, L"INSERT INTO `bar` (`foo`,`baz`) VALUES ('\xe5','D')");
4789     ok(r == ERROR_SUCCESS, "cannot add value to table %u\n", r);
4790 
4791     r = run_queryW(hdb, 0, L"CREATE TABLE `baz` ( `a\x30a` LONGCHAR NOT NULL, `\xe5` LONGCHAR NOT NULL PRIMARY KEY `a\x30a`)");
4792     ok(r == ERROR_SUCCESS, "cannot create table %u\n", r);
4793 
4794     r = run_queryW(hdb, 0, L"CREATE TABLE `a\x30a` ( `foo` LONGCHAR NOT NULL PRIMARY KEY `foo`)");
4795     ok(r == ERROR_SUCCESS, "cannot create table %u\n", r);
4796 
4797     r = run_queryW(hdb, 0, L"CREATE TABLE `\xe5` ( `foo` LONGCHAR NOT NULL PRIMARY KEY `foo`)");
4798     ok(r == ERROR_SUCCESS, "cannot create table %u\n", r);
4799 
4800     query = "SELECT * FROM `bar`";
4801     r = MsiDatabaseOpenViewA(hdb, query, &hview);
4802     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
4803     r = MsiViewExecute(hview, 0);
4804     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
4805 
4806     r = MsiViewFetch(hview, &hrec);
4807     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4808     sz = sizeof(buffer);
4809     r = MsiRecordGetStringA(hrec, 1, buffer, &sz);
4810     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4811     ok(!lstrcmpA(buffer, "\2"), "Expected \\2, got '%s'\n", buffer);
4812     sz = sizeof(buffer);
4813     r = MsiRecordGetStringA(hrec, 2, buffer, &sz);
4814     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4815     ok(!lstrcmpA(buffer, "A"), "Expected A, got '%s'\n", buffer);
4816     MsiCloseHandle(hrec);
4817 
4818     r = MsiViewFetch(hview, &hrec);
4819     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4820     sz = sizeof(buffer);
4821     r = MsiRecordGetStringA(hrec, 1, buffer, &sz);
4822     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4823     ok(!lstrcmpA(buffer, "\1"), "Expected \\1, got '%s'\n", buffer);
4824     sz = sizeof(buffer);
4825     r = MsiRecordGetStringA(hrec, 2, buffer, &sz);
4826     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4827     ok(!lstrcmpA(buffer, "B"), "Expected B, got '%s'\n", buffer);
4828     MsiCloseHandle(hrec);
4829 
4830     r = MsiViewFetch(hview, &hrec);
4831     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4832     sz = ARRAY_SIZE(bufferW);
4833     r = MsiRecordGetStringW(hrec, 1, bufferW, &sz);
4834     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4835     ok(!memcmp(bufferW, L"a\x30a", sizeof(L"a\x30a")),
4836        "Expected %s, got %s\n", wine_dbgstr_w(L"a\x30a"), wine_dbgstr_w(bufferW));
4837     sz = ARRAY_SIZE(bufferW);
4838     r = MsiRecordGetStringW(hrec, 2, bufferW, &sz);
4839     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4840     ok(!lstrcmpW(bufferW, L"C"), "Expected C, got %s\n", wine_dbgstr_w(bufferW));
4841     MsiCloseHandle(hrec);
4842 
4843     r = MsiViewFetch(hview, &hrec);
4844     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4845     sz = ARRAY_SIZE(bufferW);
4846     r = MsiRecordGetStringW(hrec, 1, bufferW, &sz);
4847     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4848     ok(!memcmp(bufferW, L"\xe5", sizeof(L"\xe5")),
4849        "Expected %s, got %s\n", wine_dbgstr_w(L"\xe5"), wine_dbgstr_w(bufferW));
4850     sz = ARRAY_SIZE(bufferW);
4851     r = MsiRecordGetStringW(hrec, 2, bufferW, &sz);
4852     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4853     ok(!lstrcmpW(bufferW, L"D"), "Expected D, got %s\n", wine_dbgstr_w(bufferW));
4854     MsiCloseHandle(hrec);
4855 
4856     r = MsiViewClose(hview);
4857     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4858     r = MsiCloseHandle(hview);
4859     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4860 
4861     r = MsiDatabaseOpenViewW(hdb, L"SELECT * FROM `bar` WHERE `foo` ='\xe5'", &hview);
4862     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
4863     r = MsiViewExecute(hview, 0);
4864     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
4865 
4866     r = MsiViewFetch(hview, &hrec);
4867     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4868     sz = ARRAY_SIZE(bufferW);
4869     r = MsiRecordGetStringW(hrec, 1, bufferW, &sz);
4870     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4871     ok(!memcmp(bufferW, L"\xe5", sizeof(L"\xe5")),
4872        "Expected %s, got %s\n", wine_dbgstr_w(L"\xe5"), wine_dbgstr_w(bufferW));
4873     sz = ARRAY_SIZE(bufferW);
4874     r = MsiRecordGetStringW(hrec, 2, bufferW, &sz);
4875     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4876     ok(!lstrcmpW(bufferW, L"D"), "Expected D, got %s\n", wine_dbgstr_w(bufferW));
4877     MsiCloseHandle(hrec);
4878 
4879     r = MsiViewFetch(hview, &hrec);
4880     ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch failed\n");
4881 
4882     r = MsiViewClose(hview);
4883     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4884     r = MsiCloseHandle(hview);
4885     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4886 
4887     r = MsiCloseHandle(hdb);
4888     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4889 
4890     DeleteFileA(msifile);
4891 }
4892 
4893 static void test_select_markers(void)
4894 {
4895     MSIHANDLE hdb = 0, rec, view, res;
4896     LPCSTR query;
4897     UINT r;
4898 
4899     hdb = create_db();
4900     ok( hdb, "failed to create db\n");
4901 
4902     r = run_query(hdb, 0,
4903             "CREATE TABLE `Table` (`One` CHAR(72), `Two` CHAR(72), `Three` SHORT PRIMARY KEY `One`, `Two`, `Three`)");
4904     ok(r == S_OK, "cannot create table: %d\n", r);
4905 
4906     r = run_query(hdb, 0, "INSERT INTO `Table` "
4907             "( `One`, `Two`, `Three` ) VALUES ( 'apple', 'one', 1 )");
4908     ok(r == S_OK, "cannot add file to the Media table: %d\n", r);
4909 
4910     r = run_query(hdb, 0, "INSERT INTO `Table` "
4911             "( `One`, `Two`, `Three` ) VALUES ( 'apple', 'two', 1 )");
4912     ok(r == S_OK, "cannot add file to the Media table: %d\n", r);
4913 
4914     r = run_query(hdb, 0, "INSERT INTO `Table` "
4915             "( `One`, `Two`, `Three` ) VALUES ( 'apple', 'two', 2 )");
4916     ok(r == S_OK, "cannot add file to the Media table: %d\n", r);
4917 
4918     r = run_query(hdb, 0, "INSERT INTO `Table` "
4919             "( `One`, `Two`, `Three` ) VALUES ( 'banana', 'three', 3 )");
4920     ok(r == S_OK, "cannot add file to the Media table: %d\n", r);
4921 
4922     rec = MsiCreateRecord(2);
4923     MsiRecordSetStringA(rec, 1, "apple");
4924     MsiRecordSetStringA(rec, 2, "two");
4925 
4926     query = "SELECT * FROM `Table` WHERE `One`=? AND `Two`=? ORDER BY `Three`";
4927     r = MsiDatabaseOpenViewA(hdb, query, &view);
4928     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4929 
4930     r = MsiViewExecute(view, rec);
4931     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4932 
4933     r = MsiViewFetch(view, &res);
4934     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4935     check_record(res, 3, "apple", "two", "1");
4936     MsiCloseHandle(res);
4937 
4938     r = MsiViewFetch(view, &res);
4939     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4940     check_record(res, 3, "apple", "two", "2");
4941     MsiCloseHandle(res);
4942 
4943     r = MsiViewFetch(view, &res);
4944     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
4945 
4946     MsiCloseHandle(rec);
4947     MsiViewClose(view);
4948     MsiCloseHandle(view);
4949 
4950     rec = MsiCreateRecord(2);
4951     MsiRecordSetStringA(rec, 1, "one");
4952     MsiRecordSetInteger(rec, 2, 1);
4953 
4954     query = "SELECT * FROM `Table` WHERE `Two`<>? AND `Three`>? ORDER BY `Three`";
4955     r = MsiDatabaseOpenViewA(hdb, query, &view);
4956     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4957     r = MsiViewExecute(view, rec);
4958     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4959 
4960     r = MsiViewFetch(view, &res);
4961     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4962     check_record(res, 3, "apple", "two", "2");
4963     MsiCloseHandle(res);
4964 
4965     r = MsiViewFetch(view, &res);
4966     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4967     check_record(res, 3, "banana", "three", "3");
4968     MsiCloseHandle(res);
4969 
4970     r = MsiViewFetch(view, &res);
4971     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
4972 
4973     MsiCloseHandle(rec);
4974     MsiViewClose(view);
4975     MsiCloseHandle(view);
4976     MsiCloseHandle(hdb);
4977     DeleteFileA(msifile);
4978 }
4979 
4980 static void test_viewmodify_update(void)
4981 {
4982     MSIHANDLE hdb = 0, hview = 0, hrec = 0;
4983     UINT i, test_max, offset, count;
4984     const char *query;
4985     UINT r;
4986 
4987     DeleteFileA(msifile);
4988 
4989     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
4990     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
4991 
4992     query = "CREATE TABLE `table` (`A` INT, `B` INT PRIMARY KEY `A`)";
4993     r = run_query( hdb, 0, query );
4994     ok(r == ERROR_SUCCESS, "query failed\n");
4995 
4996     query = "INSERT INTO `table` (`A`, `B`) VALUES (1, 2)";
4997     r = run_query( hdb, 0, query );
4998     ok(r == ERROR_SUCCESS, "query failed\n");
4999 
5000     query = "INSERT INTO `table` (`A`, `B`) VALUES (3, 4)";
5001     r = run_query( hdb, 0, query );
5002     ok(r == ERROR_SUCCESS, "query failed\n");
5003 
5004     query = "INSERT INTO `table` (`A`, `B`) VALUES (5, 6)";
5005     r = run_query( hdb, 0, query );
5006     ok(r == ERROR_SUCCESS, "query failed\n");
5007 
5008     query = "SELECT `B` FROM `table`";
5009     r = MsiDatabaseOpenViewA(hdb, query, &hview);
5010     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
5011     r = MsiViewExecute(hview, 0);
5012     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
5013     r = MsiViewFetch(hview, &hrec);
5014     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
5015 
5016     r = MsiRecordSetInteger(hrec, 1, 0);
5017     ok(r == ERROR_SUCCESS, "failed to set integer\n");
5018 
5019     r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
5020     ok(r == ERROR_SUCCESS, "MsiViewModify failed: %d\n", r);
5021 
5022     r = MsiCloseHandle(hrec);
5023     ok(r == ERROR_SUCCESS, "failed to close record\n");
5024 
5025     r = MsiViewClose(hview);
5026     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
5027     r = MsiCloseHandle(hview);
5028     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
5029 
5030     query = "SELECT * FROM `table`";
5031     r = MsiDatabaseOpenViewA(hdb, query, &hview);
5032     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
5033     r = MsiViewExecute(hview, 0);
5034     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
5035     r = MsiViewFetch(hview, &hrec);
5036     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
5037 
5038     r = MsiRecordGetInteger(hrec, 1);
5039     ok(r == 1, "Expected 1, got %d\n", r);
5040     r = MsiRecordGetInteger(hrec, 2);
5041     ok(r == 0, "Expected 0, got %d\n", r);
5042 
5043     r = MsiCloseHandle(hrec);
5044     ok(r == ERROR_SUCCESS, "failed to close record\n");
5045 
5046     r = MsiViewFetch(hview, &hrec);
5047     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
5048 
5049     r = MsiRecordGetInteger(hrec, 1);
5050     ok(r == 3, "Expected 3, got %d\n", r);
5051     r = MsiRecordGetInteger(hrec, 2);
5052     ok(r == 4, "Expected 4, got %d\n", r);
5053 
5054     r = MsiCloseHandle(hrec);
5055     ok(r == ERROR_SUCCESS, "failed to close record\n");
5056 
5057     r = MsiViewFetch(hview, &hrec);
5058     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
5059 
5060     r = MsiRecordGetInteger(hrec, 1);
5061     ok(r == 5, "Expected 5, got %d\n", r);
5062     r = MsiRecordGetInteger(hrec, 2);
5063     ok(r == 6, "Expected 6, got %d\n", r);
5064 
5065     r = MsiCloseHandle(hrec);
5066     ok(r == ERROR_SUCCESS, "failed to close record\n");
5067 
5068     r = MsiViewFetch(hview, &hrec);
5069     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5070 
5071     r = MsiViewClose(hview);
5072     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
5073     r = MsiCloseHandle(hview);
5074     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
5075 
5076     /* loop through all elements */
5077     query = "SELECT `B` FROM `table`";
5078     r = MsiDatabaseOpenViewA(hdb, query, &hview);
5079     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
5080     r = MsiViewExecute(hview, 0);
5081     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
5082 
5083     while (TRUE)
5084     {
5085         r = MsiViewFetch(hview, &hrec);
5086         if (r != ERROR_SUCCESS)
5087             break;
5088 
5089         r = MsiRecordSetInteger(hrec, 1, 0);
5090         ok(r == ERROR_SUCCESS, "failed to set integer\n");
5091 
5092         r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
5093         ok(r == ERROR_SUCCESS, "MsiViewModify failed: %d\n", r);
5094 
5095         r = MsiCloseHandle(hrec);
5096         ok(r == ERROR_SUCCESS, "failed to close record\n");
5097     }
5098 
5099     r = MsiViewClose(hview);
5100     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
5101     r = MsiCloseHandle(hview);
5102     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
5103 
5104     query = "SELECT * FROM `table`";
5105     r = MsiDatabaseOpenViewA(hdb, query, &hview);
5106     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
5107     r = MsiViewExecute(hview, 0);
5108     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
5109     r = MsiViewFetch(hview, &hrec);
5110     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
5111 
5112     r = MsiRecordGetInteger(hrec, 1);
5113     ok(r == 1, "Expected 1, got %d\n", r);
5114     r = MsiRecordGetInteger(hrec, 2);
5115     ok(r == 0, "Expected 0, got %d\n", r);
5116 
5117     r = MsiCloseHandle(hrec);
5118     ok(r == ERROR_SUCCESS, "failed to close record\n");
5119 
5120     r = MsiViewFetch(hview, &hrec);
5121     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
5122 
5123     r = MsiRecordGetInteger(hrec, 1);
5124     ok(r == 3, "Expected 3, got %d\n", r);
5125     r = MsiRecordGetInteger(hrec, 2);
5126     ok(r == 0, "Expected 0, got %d\n", r);
5127 
5128     r = MsiCloseHandle(hrec);
5129     ok(r == ERROR_SUCCESS, "failed to close record\n");
5130 
5131     r = MsiViewFetch(hview, &hrec);
5132     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
5133 
5134     r = MsiRecordGetInteger(hrec, 1);
5135     ok(r == 5, "Expected 5, got %d\n", r);
5136     r = MsiRecordGetInteger(hrec, 2);
5137     ok(r == 0, "Expected 0, got %d\n", r);
5138 
5139     r = MsiCloseHandle(hrec);
5140     ok(r == ERROR_SUCCESS, "failed to close record\n");
5141 
5142     r = MsiViewFetch(hview, &hrec);
5143     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5144 
5145     r = MsiViewClose(hview);
5146     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
5147     r = MsiCloseHandle(hview);
5148     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
5149 
5150     query = "CREATE TABLE `table2` (`A` INT, `B` INT PRIMARY KEY `A`)";
5151     r = run_query( hdb, 0, query );
5152     ok(r == ERROR_SUCCESS, "query failed\n");
5153 
5154     query = "INSERT INTO `table2` (`A`, `B`) VALUES (?, ?)";
5155     r = MsiDatabaseOpenViewA( hdb, query, &hview );
5156     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
5157 
5158     test_max = 100;
5159     offset = 1234;
5160     for(i = 0; i < test_max; i++)
5161     {
5162 
5163         hrec = MsiCreateRecord( 2 );
5164         MsiRecordSetInteger( hrec, 1, test_max - i );
5165         MsiRecordSetInteger( hrec, 2, i );
5166 
5167         r = MsiViewExecute( hview, hrec );
5168         ok(r == ERROR_SUCCESS, "Got %d\n", r);
5169 
5170         r = MsiCloseHandle( hrec );
5171         ok(r == ERROR_SUCCESS, "Got %d\n", r);
5172     }
5173 
5174     r = MsiViewClose( hview );
5175     ok(r == ERROR_SUCCESS, "Got %d\n", r);
5176     r = MsiCloseHandle( hview );
5177     ok(r == ERROR_SUCCESS, "Got %d\n", r);
5178 
5179     /* Update. */
5180     query = "SELECT * FROM `table2` ORDER BY `B`";
5181     r = MsiDatabaseOpenViewA( hdb, query, &hview);
5182     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
5183     r = MsiViewExecute( hview, 0 );
5184     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
5185 
5186     count = 0;
5187     while (MsiViewFetch( hview, &hrec ) == ERROR_SUCCESS)
5188     {
5189         UINT b = MsiRecordGetInteger( hrec, 2 );
5190 
5191         r = MsiRecordSetInteger( hrec, 2, b + offset);
5192         ok(r == ERROR_SUCCESS, "Got %d\n", r);
5193 
5194         r = MsiViewModify( hview, MSIMODIFY_UPDATE, hrec );
5195         ok(r == ERROR_SUCCESS, "Got %d\n", r);
5196 
5197         r = MsiCloseHandle(hrec);
5198         ok(r == ERROR_SUCCESS, "failed to close record\n");
5199         count++;
5200     }
5201     ok(count == test_max, "Got count %d\n", count);
5202 
5203     r = MsiViewClose(hview);
5204     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
5205     r = MsiCloseHandle(hview);
5206     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
5207 
5208     /* Recheck. */
5209     query = "SELECT * FROM `table2` ORDER BY `B`";
5210     r = MsiDatabaseOpenViewA( hdb, query, &hview);
5211     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
5212     r = MsiViewExecute( hview, 0 );
5213     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
5214 
5215     count = 0;
5216     while (MsiViewFetch( hview, &hrec ) == ERROR_SUCCESS)
5217     {
5218         UINT a = MsiRecordGetInteger( hrec, 1 );
5219         UINT b = MsiRecordGetInteger( hrec, 2 );
5220         ok( ( test_max - a + offset) == b, "Got (%d, %d), expected (%d, %d)\n",
5221             a, b, test_max - a + offset, b);
5222 
5223         r = MsiCloseHandle(hrec);
5224         ok(r == ERROR_SUCCESS, "failed to close record\n");
5225         count++;
5226     }
5227     ok(count == test_max, "Got count %d\n", count);
5228 
5229     r = MsiViewClose(hview);
5230     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
5231     r = MsiCloseHandle(hview);
5232     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
5233 
5234     r = MsiCloseHandle( hdb );
5235     ok(r == ERROR_SUCCESS, "MsiOpenDatabase close failed\n");
5236 }
5237 
5238 static void test_viewmodify_assign(void)
5239 {
5240     MSIHANDLE hdb = 0, hview = 0, hrec = 0;
5241     const char *query;
5242     UINT r;
5243 
5244     /* setup database */
5245     DeleteFileA(msifile);
5246 
5247     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
5248     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
5249 
5250     query = "CREATE TABLE `table` (`A` INT, `B` INT PRIMARY KEY `A`)";
5251     r = run_query( hdb, 0, query );
5252     ok(r == ERROR_SUCCESS, "query failed\n");
5253 
5254     /* assign to view, new primary key */
5255     query = "SELECT * FROM `table`";
5256     r = MsiDatabaseOpenViewA(hdb, query, &hview);
5257     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
5258     r = MsiViewExecute(hview, 0);
5259     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
5260 
5261     hrec = MsiCreateRecord(2);
5262     ok(hrec != 0, "MsiCreateRecord failed\n");
5263 
5264     r = MsiRecordSetInteger(hrec, 1, 1);
5265     ok(r == ERROR_SUCCESS, "failed to set integer\n");
5266     r = MsiRecordSetInteger(hrec, 2, 2);
5267     ok(r == ERROR_SUCCESS, "failed to set integer\n");
5268 
5269     r = MsiViewModify(hview, MSIMODIFY_ASSIGN, hrec);
5270     ok(r == ERROR_SUCCESS, "MsiViewModify failed: %d\n", r);
5271 
5272     r = MsiCloseHandle(hrec);
5273     ok(r == ERROR_SUCCESS, "failed to close record\n");
5274 
5275     r = MsiViewClose(hview);
5276     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
5277     r = MsiCloseHandle(hview);
5278     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
5279 
5280     query = "SELECT * FROM `table`";
5281     r = MsiDatabaseOpenViewA(hdb, query, &hview);
5282     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
5283     r = MsiViewExecute(hview, 0);
5284     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
5285     r = MsiViewFetch(hview, &hrec);
5286     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
5287     check_record(hrec, 2, "1", "2");
5288     r = MsiCloseHandle(hrec);
5289     ok(r == ERROR_SUCCESS, "failed to close record\n");
5290 
5291     r = MsiViewFetch(hview, &hrec);
5292     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5293 
5294     r = MsiViewClose(hview);
5295     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
5296     r = MsiCloseHandle(hview);
5297     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
5298 
5299     /* assign to view, primary key matches */
5300     query = "SELECT * FROM `table`";
5301     r = MsiDatabaseOpenViewA(hdb, query, &hview);
5302     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
5303     r = MsiViewExecute(hview, 0);
5304     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
5305 
5306     hrec = MsiCreateRecord(2);
5307     ok(hrec != 0, "MsiCreateRecord failed\n");
5308 
5309     r = MsiRecordSetInteger(hrec, 1, 1);
5310     ok(r == ERROR_SUCCESS, "failed to set integer\n");
5311     r = MsiRecordSetInteger(hrec, 2, 4);
5312     ok(r == ERROR_SUCCESS, "failed to set integer\n");
5313 
5314     r = MsiViewModify(hview, MSIMODIFY_ASSIGN, hrec);
5315     ok(r == ERROR_SUCCESS, "MsiViewModify failed: %d\n", r);
5316 
5317     r = MsiCloseHandle(hrec);
5318     ok(r == ERROR_SUCCESS, "failed to close record\n");
5319 
5320     r = MsiViewClose(hview);
5321     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
5322     r = MsiCloseHandle(hview);
5323     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
5324 
5325     query = "SELECT * FROM `table`";
5326     r = MsiDatabaseOpenViewA(hdb, query, &hview);
5327     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
5328     r = MsiViewExecute(hview, 0);
5329     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
5330     r = MsiViewFetch(hview, &hrec);
5331     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
5332     check_record(hrec, 2, "1", "4");
5333     r = MsiCloseHandle(hrec);
5334     ok(r == ERROR_SUCCESS, "failed to close record\n");
5335 
5336     r = MsiViewFetch(hview, &hrec);
5337     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5338 
5339     r = MsiViewClose(hview);
5340     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
5341     r = MsiCloseHandle(hview);
5342     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
5343 
5344     r = run_query(hdb, 0, "CREATE TABLE `table2` (`A` INT, `B` INT, `C` INT, `D` INT PRIMARY KEY `A`,`B`)");
5345     ok(!r, "got %u\n", r);
5346 
5347     r = MsiDatabaseOpenViewA(hdb, "SELECT * FROM `table2`", &hview);
5348     ok(!r, "got %u\n", r);
5349     r = MsiViewExecute(hview, 0);
5350     ok(!r, "got %u\n", r);
5351 
5352     hrec = MsiCreateRecord(4);
5353     MsiRecordSetInteger(hrec, 1, 1);
5354     MsiRecordSetInteger(hrec, 2, 2);
5355     MsiRecordSetInteger(hrec, 3, 3);
5356     MsiRecordSetInteger(hrec, 4, 4);
5357     r = MsiViewModify(hview, MSIMODIFY_ASSIGN, hrec);
5358     ok(!r, "got %u\n", r);
5359     MsiCloseHandle(hrec);
5360 
5361     MsiCloseHandle(hview);
5362 
5363     r = MsiDatabaseOpenViewA(hdb, "SELECT * FROM `table2`", &hview);
5364     ok(!r, "got %u\n", r);
5365     r = MsiViewExecute(hview, 0);
5366     ok(!r, "got %u\n", r);
5367 
5368     r = MsiViewFetch(hview, &hrec);
5369     ok(!r, "got %u\n", r);
5370     check_record(hrec, 4, "1", "2", "3", "4");
5371     MsiCloseHandle(hrec);
5372 
5373     r = MsiViewFetch(hview, &hrec);
5374     ok(r == ERROR_NO_MORE_ITEMS, "got %u\n", r);
5375     MsiCloseHandle(hview);
5376 
5377     r = MsiDatabaseOpenViewA(hdb, "SELECT * FROM `table2`", &hview);
5378     ok(!r, "got %u\n", r);
5379     r = MsiViewExecute(hview, 0);
5380     ok(!r, "got %u\n", r);
5381 
5382     hrec = MsiCreateRecord(4);
5383     MsiRecordSetInteger(hrec, 1, 1);
5384     MsiRecordSetInteger(hrec, 2, 4);
5385     MsiRecordSetInteger(hrec, 3, 3);
5386     MsiRecordSetInteger(hrec, 4, 3);
5387     r = MsiViewModify(hview, MSIMODIFY_ASSIGN, hrec);
5388     ok(!r, "got %u\n", r);
5389     MsiCloseHandle(hrec);
5390 
5391     MsiCloseHandle(hview);
5392 
5393     r = MsiDatabaseOpenViewA(hdb, "SELECT * FROM `table2`", &hview);
5394     ok(!r, "got %u\n", r);
5395     r = MsiViewExecute(hview, 0);
5396     ok(!r, "got %u\n", r);
5397 
5398     r = MsiViewFetch(hview, &hrec);
5399     ok(!r, "got %u\n", r);
5400     check_record(hrec, 4, "1", "2", "3", "4");
5401     MsiCloseHandle(hrec);
5402 
5403     r = MsiViewFetch(hview, &hrec);
5404     ok(!r, "got %u\n", r);
5405     check_record(hrec, 4, "1", "4", "3", "3");
5406     MsiCloseHandle(hrec);
5407 
5408     r = MsiViewFetch(hview, &hrec);
5409     ok(r == ERROR_NO_MORE_ITEMS, "got %u\n", r);
5410     MsiCloseHandle(hview);
5411 
5412     r = MsiDatabaseOpenViewA(hdb, "SELECT `B`, `C` FROM `table2`", &hview);
5413     ok(!r, "got %u\n", r);
5414     r = MsiViewExecute(hview, 0);
5415     ok(!r, "got %u\n", r);
5416 
5417     hrec = MsiCreateRecord(2);
5418     MsiRecordSetInteger(hrec, 1, 2);
5419     MsiRecordSetInteger(hrec, 2, 4);
5420     r = MsiViewModify(hview, MSIMODIFY_ASSIGN, hrec);
5421     ok(!r, "got %u\n", r);
5422     MsiRecordSetInteger(hrec, 1, 3);
5423     r = MsiViewModify(hview, MSIMODIFY_ASSIGN, hrec);
5424     ok(!r, "got %u\n", r);
5425     MsiCloseHandle(hrec);
5426 
5427     MsiCloseHandle(hview);
5428 
5429     r = MsiDatabaseOpenViewA(hdb, "SELECT * FROM `table2` ORDER BY `A`", &hview);
5430     ok(!r, "got %u\n", r);
5431     r = MsiViewExecute(hview, 0);
5432     ok(!r, "got %u\n", r);
5433 
5434     r = MsiViewFetch(hview, &hrec);
5435     ok(!r, "got %u\n", r);
5436     check_record(hrec, 4, "", "2", "4", "");
5437     MsiCloseHandle(hrec);
5438 
5439     r = MsiViewFetch(hview, &hrec);
5440     ok(!r, "got %u\n", r);
5441     check_record(hrec, 4, "", "3", "4", "");
5442     MsiCloseHandle(hrec);
5443 
5444     r = MsiViewFetch(hview, &hrec);
5445     ok(!r, "got %u\n", r);
5446     check_record(hrec, 4, "1", "2", "3", "4");
5447     MsiCloseHandle(hrec);
5448 
5449     r = MsiViewFetch(hview, &hrec);
5450     ok(!r, "got %u\n", r);
5451     check_record(hrec, 4, "1", "4", "3", "3");
5452     MsiCloseHandle(hrec);
5453 
5454     r = MsiViewFetch(hview, &hrec);
5455     ok(r == ERROR_NO_MORE_ITEMS, "got %u\n", r);
5456     MsiCloseHandle(hview);
5457 
5458     r = MsiDatabaseOpenViewA(hdb, "SELECT `A`, `B`, `C` FROM `table2`", &hview);
5459     ok(!r, "got %u\n", r);
5460     r = MsiViewExecute(hview, 0);
5461     ok(!r, "got %u\n", r);
5462 
5463     hrec = MsiCreateRecord(3);
5464     MsiRecordSetInteger(hrec, 1, 1);
5465     MsiRecordSetInteger(hrec, 2, 2);
5466     MsiRecordSetInteger(hrec, 3, 5);
5467     r = MsiViewModify(hview, MSIMODIFY_ASSIGN, hrec);
5468     ok(!r, "got %u\n", r);
5469     MsiCloseHandle(hrec);
5470 
5471     MsiCloseHandle(hview);
5472 
5473     r = MsiDatabaseOpenViewA(hdb, "SELECT * FROM `table2` ORDER BY `A`", &hview);
5474     ok(!r, "got %u\n", r);
5475     r = MsiViewExecute(hview, 0);
5476     ok(!r, "got %u\n", r);
5477 
5478     r = MsiViewFetch(hview, &hrec);
5479     ok(!r, "got %u\n", r);
5480     check_record(hrec, 4, "", "2", "4", "");
5481     MsiCloseHandle(hrec);
5482 
5483     r = MsiViewFetch(hview, &hrec);
5484     ok(!r, "got %u\n", r);
5485     check_record(hrec, 4, "", "3", "4", "");
5486     MsiCloseHandle(hrec);
5487 
5488     r = MsiViewFetch(hview, &hrec);
5489     ok(!r, "got %u\n", r);
5490     check_record(hrec, 4, "1", "2", "5", "");
5491     MsiCloseHandle(hrec);
5492 
5493     r = MsiViewFetch(hview, &hrec);
5494     ok(!r, "got %u\n", r);
5495     check_record(hrec, 4, "1", "4", "3", "3");
5496     MsiCloseHandle(hrec);
5497 
5498     r = MsiViewFetch(hview, &hrec);
5499     ok(r == ERROR_NO_MORE_ITEMS, "got %u\n", r);
5500     MsiCloseHandle(hview);
5501 
5502     /* close database */
5503     r = MsiCloseHandle( hdb );
5504     ok(r == ERROR_SUCCESS, "MsiOpenDatabase close failed\n");
5505 }
5506 
5507 static const WCHAR data10[] = { /* MOO */
5508     0x8001, 0x000b,
5509 };
5510 static const WCHAR data11[] = { /* AAR */
5511     0x8002, 0x8005,
5512     0x000c, 0x000f,
5513 };
5514 static const char data12[] = /* _StringData */
5515     "MOOABAARCDonetwofourfive";
5516 static const WCHAR data13[] = { /* _StringPool */
5517 /*  len, refs */
5518     0,   0,    /* string 0 ''     */
5519     0,   0,    /* string 1 ''     */
5520     0,   0,    /* string 2 ''     */
5521     0,   0,    /* string 3 ''     */
5522     0,   0,    /* string 4 ''     */
5523     3,   3,    /* string 5 'MOO'  */
5524     1,   1,    /* string 6 'A'    */
5525     1,   1,    /* string 7 'B'    */
5526     3,   3,    /* string 8 'AAR'  */
5527     1,   1,    /* string 9 'C'    */
5528     1,   1,    /* string a 'D'    */
5529     3,   1,    /* string b 'one'  */
5530     3,   1,    /* string c 'two'  */
5531     0,   0,    /* string d ''     */
5532     4,   1,    /* string e 'four' */
5533     4,   1,    /* string f 'five' */
5534 };
5535 
5536 static void test_stringtable(void)
5537 {
5538     MSIHANDLE hdb = 0, hview = 0, hrec = 0;
5539     IStorage *stg = NULL;
5540     IStream *stm;
5541     WCHAR name[0x20];
5542     HRESULT hr;
5543     const char *query;
5544     char buffer[MAX_PATH];
5545     WCHAR data[MAX_PATH];
5546     DWORD read;
5547     UINT r;
5548 
5549     static const DWORD mode = STGM_DIRECT | STGM_READ | STGM_SHARE_DENY_WRITE;
5550     static const WCHAR stringdata[] = {0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0}; /* _StringData */
5551     static const WCHAR stringpool[] = {0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0}; /* _StringPool */
5552     static const WCHAR moo[] = {0x4840, 0x3e16, 0x4818, 0}; /* MOO */
5553     static const WCHAR aar[] = {0x4840, 0x3a8a, 0x481b, 0}; /* AAR */
5554 
5555     DeleteFileA(msifile);
5556 
5557     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
5558     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5559 
5560     query = "CREATE TABLE `MOO` (`A` INT, `B` CHAR(72) PRIMARY KEY `A`)";
5561     r = run_query(hdb, 0, query);
5562     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5563 
5564     query = "CREATE TABLE `AAR` (`C` INT, `D` CHAR(72) PRIMARY KEY `C`)";
5565     r = run_query(hdb, 0, query);
5566     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5567 
5568     /* insert persistent row */
5569     query = "INSERT INTO `MOO` (`A`, `B`) VALUES (1, 'one')";
5570     r = run_query(hdb, 0, query);
5571     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5572 
5573     /* insert persistent row */
5574     query = "INSERT INTO `AAR` (`C`, `D`) VALUES (2, 'two')";
5575     r = run_query(hdb, 0, query);
5576     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5577 
5578     /* open a view */
5579     query = "SELECT * FROM `MOO`";
5580     r = MsiDatabaseOpenViewA(hdb, query, &hview);
5581     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5582     r = MsiViewExecute(hview, 0);
5583     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5584 
5585     hrec = MsiCreateRecord(2);
5586 
5587     r = MsiRecordSetInteger(hrec, 1, 3);
5588     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5589     r = MsiRecordSetStringA(hrec, 2, "three");
5590     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5591 
5592     /* insert a nonpersistent row */
5593     r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec);
5594     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5595 
5596     r = MsiCloseHandle(hrec);
5597     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5598     r = MsiViewClose(hview);
5599     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5600     r = MsiCloseHandle(hview);
5601     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5602 
5603     /* insert persistent row */
5604     query = "INSERT INTO `MOO` (`A`, `B`) VALUES (4, 'four')";
5605     r = run_query(hdb, 0, query);
5606     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5607 
5608     /* insert persistent row */
5609     query = "INSERT INTO `AAR` (`C`, `D`) VALUES (5, 'five')";
5610     r = run_query(hdb, 0, query);
5611     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5612 
5613     r = MsiDatabaseCommit(hdb);
5614     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5615 
5616     r = MsiCloseHandle(hdb);
5617     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5618 
5619     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_READONLY, &hdb);
5620     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5621 
5622     query = "SELECT * FROM `MOO`";
5623     r = MsiDatabaseOpenViewA(hdb, query, &hview);
5624     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5625 
5626     r = MsiViewExecute(hview, 0);
5627     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5628 
5629     r = MsiViewFetch(hview, &hrec);
5630     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5631     check_record(hrec, 2, "1", "one");
5632     r = MsiCloseHandle(hrec);
5633     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5634 
5635     r = MsiViewFetch(hview, &hrec);
5636     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5637 
5638     r = MsiViewClose(hview);
5639     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5640     r = MsiCloseHandle(hview);
5641     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5642     r = MsiCloseHandle(hrec);
5643     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5644 
5645     query = "SELECT * FROM `AAR`";
5646     r = MsiDatabaseOpenViewA(hdb, query, &hview);
5647     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5648 
5649     r = MsiViewExecute(hview, 0);
5650     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5651 
5652     r = MsiViewFetch(hview, &hrec);
5653     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5654     check_record(hrec, 2, "2", "two");
5655     r = MsiCloseHandle(hrec);
5656     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5657 
5658     r = MsiViewFetch(hview, &hrec);
5659     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5660     check_record(hrec, 2, "5", "five");
5661     r = MsiCloseHandle(hrec);
5662     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5663 
5664     r = MsiViewFetch(hview, &hrec);
5665     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5666 
5667     r = MsiViewClose(hview);
5668     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5669     r = MsiCloseHandle(hview);
5670     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5671     r = MsiCloseHandle(hrec);
5672     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5673     r = MsiCloseHandle(hdb);
5674     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5675 
5676     MultiByteToWideChar(CP_ACP, 0, msifile, -1, name, 0x20);
5677     hr = StgOpenStorage(name, NULL, mode, NULL, 0, &stg);
5678     ok(hr == S_OK, "Expected S_OK, got %#lx\n", hr);
5679     ok(stg != NULL, "Expected non-NULL storage\n");
5680 
5681     hr = IStorage_OpenStream(stg, moo, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm);
5682     ok(hr == S_OK, "Expected S_OK, got %#lx\n", hr);
5683     ok(stm != NULL, "Expected non-NULL stream\n");
5684 
5685     hr = IStream_Read(stm, data, MAX_PATH, &read);
5686     ok(hr == S_OK, "Expected S_OK, got %#lx\n", hr);
5687     ok(read == 4, "Expected 4, got %lu\n", read);
5688     todo_wine ok(!memcmp(data, data10, read), "Unexpected data\n");
5689 
5690     hr = IStream_Release(stm);
5691     ok(hr == S_OK, "Expected S_OK, got %#lx\n", hr);
5692 
5693     hr = IStorage_OpenStream(stg, aar, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm);
5694     ok(hr == S_OK, "Expected S_OK, got %#lx\n", hr);
5695     ok(stm != NULL, "Expected non-NULL stream\n");
5696 
5697     hr = IStream_Read(stm, data, MAX_PATH, &read);
5698     ok(hr == S_OK, "Expected S_OK, got %#lx\n", hr);
5699     ok(read == 8, "Expected 8, got %lu\n", read);
5700     todo_wine
5701     {
5702         ok(!memcmp(data, data11, read), "Unexpected data\n");
5703     }
5704 
5705     hr = IStream_Release(stm);
5706     ok(hr == S_OK, "Expected S_OK, got %#lx\n", hr);
5707 
5708     hr = IStorage_OpenStream(stg, stringdata, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm);
5709     ok(hr == S_OK, "Expected S_OK, got %#lx\n", hr);
5710     ok(stm != NULL, "Expected non-NULL stream\n");
5711 
5712     hr = IStream_Read(stm, buffer, MAX_PATH, &read);
5713     ok(hr == S_OK, "Expected S_OK, got %#lx\n", hr);
5714     ok(read == 24, "Expected 24, got %lu\n", read);
5715     ok(!memcmp(buffer, data12, read), "Unexpected data\n");
5716 
5717     hr = IStream_Release(stm);
5718     ok(hr == S_OK, "Expected S_OK, got %#lx\n", hr);
5719 
5720     hr = IStorage_OpenStream(stg, stringpool, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm);
5721     ok(hr == S_OK, "Expected S_OK, got %#lx\n", hr);
5722     ok(stm != NULL, "Expected non-NULL stream\n");
5723 
5724     hr = IStream_Read(stm, data, MAX_PATH, &read);
5725     ok(hr == S_OK, "Expected S_OK, got %#lx\n", hr);
5726     todo_wine
5727     {
5728         ok(read == 64, "Expected 64, got %lu\n", read);
5729         ok(!memcmp(data, data13, read), "Unexpected data\n");
5730     }
5731 
5732     hr = IStream_Release(stm);
5733     ok(hr == S_OK, "Expected S_OK, got %#lx\n", hr);
5734 
5735     hr = IStorage_Release(stg);
5736     ok(hr == S_OK, "Expected S_OK, got %#lx\n", hr);
5737 
5738     DeleteFileA(msifile);
5739 }
5740 
5741 static void test_viewmodify_delete(void)
5742 {
5743     MSIHANDLE hdb = 0, hview = 0, hrec = 0;
5744     UINT r;
5745     const char *query;
5746 
5747     DeleteFileA(msifile);
5748 
5749     /* just MsiOpenDatabase should not create a file */
5750     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
5751     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5752 
5753     query = "CREATE TABLE `phone` ( "
5754             "`id` INT, `name` CHAR(32), `number` CHAR(32) "
5755             "PRIMARY KEY `id`)";
5756     r = run_query(hdb, 0, query);
5757     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5758 
5759     query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
5760         "VALUES('1', 'Alan', '5030581')";
5761     r = run_query(hdb, 0, query);
5762     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5763 
5764     query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
5765         "VALUES('2', 'Barry', '928440')";
5766     r = run_query(hdb, 0, query);
5767     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5768 
5769     query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
5770         "VALUES('3', 'Cindy', '2937550')";
5771     r = run_query(hdb, 0, query);
5772     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5773 
5774     query = "SELECT * FROM `phone` WHERE `id` <= 2";
5775     r = MsiDatabaseOpenViewA(hdb, query, &hview);
5776     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5777     r = MsiViewExecute(hview, 0);
5778     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5779     r = MsiViewFetch(hview, &hrec);
5780     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5781 
5782     /* delete 1 */
5783     r = MsiViewModify(hview, MSIMODIFY_DELETE, hrec);
5784     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5785 
5786     r = MsiCloseHandle(hrec);
5787     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5788     r = MsiViewFetch(hview, &hrec);
5789     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5790 
5791     /* delete 2 */
5792     MsiRecordSetInteger(hrec, 1, 4);
5793     r = MsiViewModify(hview, MSIMODIFY_DELETE, hrec);
5794     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5795 
5796     r = MsiCloseHandle(hrec);
5797     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5798     r = MsiViewClose(hview);
5799     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5800     r = MsiCloseHandle(hview);
5801     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5802 
5803     query = "SELECT * FROM `phone`";
5804     r = MsiDatabaseOpenViewA(hdb, query, &hview);
5805     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5806     r = MsiViewExecute(hview, 0);
5807     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5808     r = MsiViewFetch(hview, &hrec);
5809     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5810     check_record(hrec, 3, "3", "Cindy", "2937550");
5811     r = MsiCloseHandle(hrec);
5812     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5813 
5814     r = MsiViewFetch(hview, &hrec);
5815     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5816 
5817     r = MsiViewClose(hview);
5818     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5819     r = MsiCloseHandle(hview);
5820     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5821     r = MsiCloseHandle(hdb);
5822     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5823 }
5824 
5825 static const WCHAR _Tables[] = {0x4840, 0x3f7f, 0x4164, 0x422f, 0x4836, 0};
5826 static const WCHAR _StringData[] = {0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0};
5827 static const WCHAR _StringPool[] = {0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0};
5828 
5829 static const WCHAR data14[] = { /* _StringPool */
5830 /*  len, refs */
5831     0,   0,    /* string 0 ''    */
5832 };
5833 
5834 static const struct {
5835     LPCWSTR name;
5836     const void *data;
5837     DWORD size;
5838 } database_table_data[] =
5839 {
5840     {_Tables, NULL, 0},
5841     {_StringData, NULL, 0},
5842     {_StringPool, data14, sizeof data14},
5843 };
5844 
5845 static void enum_stream_names(IStorage *stg)
5846 {
5847     IEnumSTATSTG *stgenum = NULL;
5848     IStream *stm;
5849     HRESULT hr;
5850     STATSTG stat;
5851     ULONG n, count;
5852     BYTE data[MAX_PATH];
5853     BYTE check[MAX_PATH];
5854     DWORD sz;
5855 
5856     memset(check, 'a', MAX_PATH);
5857 
5858     hr = IStorage_EnumElements(stg, 0, NULL, 0, &stgenum);
5859     ok(hr == S_OK, "Expected S_OK, got %#lx\n", hr);
5860 
5861     n = 0;
5862     while(TRUE)
5863     {
5864         count = 0;
5865         hr = IEnumSTATSTG_Next(stgenum, 1, &stat, &count);
5866         if(FAILED(hr) || !count)
5867             break;
5868 
5869         ok(!lstrcmpW(stat.pwcsName, database_table_data[n].name),
5870            "Expected table %lu name to match\n", n);
5871 
5872         stm = NULL;
5873         hr = IStorage_OpenStream(stg, stat.pwcsName, NULL,
5874                                  STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm);
5875         ok(hr == S_OK, "Expected S_OK, got %#lx\n", hr);
5876         ok(stm != NULL, "Expected non-NULL stream\n");
5877 
5878         CoTaskMemFree(stat.pwcsName);
5879 
5880         sz = MAX_PATH;
5881         memset(data, 'a', MAX_PATH);
5882         hr = IStream_Read(stm, data, sz, &count);
5883         ok(hr == S_OK, "Expected S_OK, got %#lx\n", hr);
5884 
5885         ok(count == database_table_data[n].size,
5886            "Expected %lu, got %lu\n", database_table_data[n].size, count);
5887 
5888         if (!database_table_data[n].size)
5889             ok(!memcmp(data, check, MAX_PATH), "data should not be changed\n");
5890         else
5891             ok(!memcmp(data, database_table_data[n].data, database_table_data[n].size),
5892                "Expected table %lu data to match\n", n);
5893 
5894         IStream_Release(stm);
5895         n++;
5896     }
5897 
5898     ok(n == 3, "Expected 3, got %lu\n", n);
5899 
5900     IEnumSTATSTG_Release(stgenum);
5901 }
5902 
5903 static void test_defaultdatabase(void)
5904 {
5905     UINT r;
5906     HRESULT hr;
5907     MSIHANDLE hdb;
5908     IStorage *stg = NULL;
5909 
5910     DeleteFileA(msifile);
5911 
5912     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
5913     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5914 
5915     r = MsiDatabaseCommit(hdb);
5916     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5917 
5918     MsiCloseHandle(hdb);
5919 
5920     hr = StgOpenStorage(msifileW, NULL, STGM_READ | STGM_SHARE_DENY_WRITE, NULL, 0, &stg);
5921     ok(hr == S_OK, "Expected S_OK, got %#lx\n", hr);
5922     ok(stg != NULL, "Expected non-NULL stg\n");
5923 
5924     enum_stream_names(stg);
5925 
5926     IStorage_Release(stg);
5927     DeleteFileA(msifile);
5928 }
5929 
5930 static void test_order(void)
5931 {
5932     MSIHANDLE hdb, hview, hrec;
5933     LPCSTR query;
5934     int val;
5935     UINT r;
5936 
5937     hdb = create_db();
5938     ok(hdb, "failed to create db\n");
5939 
5940     query = "CREATE TABLE `Empty` ( `A` SHORT NOT NULL PRIMARY KEY `A`)";
5941     r = run_query(hdb, 0, query);
5942     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5943 
5944     query = "CREATE TABLE `Mesa` ( `A` SHORT NOT NULL, `B` SHORT, `C` SHORT PRIMARY KEY `A`)";
5945     r = run_query(hdb, 0, query);
5946     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5947 
5948     query = "INSERT INTO `Mesa` ( `A`, `B`, `C` ) VALUES ( 1, 2, 9 )";
5949     r = run_query(hdb, 0, query);
5950     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5951 
5952     query = "INSERT INTO `Mesa` ( `A`, `B`, `C` ) VALUES ( 3, 4, 7 )";
5953     r = run_query(hdb, 0, query);
5954     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5955 
5956     query = "INSERT INTO `Mesa` ( `A`, `B`, `C` ) VALUES ( 5, 6, 8 )";
5957     r = run_query(hdb, 0, query);
5958     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5959 
5960     query = "CREATE TABLE `Sideboard` ( `D` SHORT NOT NULL, `E` SHORT, `F` SHORT PRIMARY KEY `D`)";
5961     r = run_query(hdb, 0, query);
5962     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5963 
5964     query = "INSERT INTO `Sideboard` ( `D`, `E`, `F` ) VALUES ( 10, 11, 18 )";
5965     r = run_query(hdb, 0, query);
5966     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5967 
5968     query = "INSERT INTO `Sideboard` ( `D`, `E`, `F` ) VALUES ( 12, 13, 16 )";
5969     r = run_query(hdb, 0, query);
5970     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5971 
5972     query = "INSERT INTO `Sideboard` ( `D`, `E`, `F` ) VALUES ( 14, 15, 17 )";
5973     r = run_query(hdb, 0, query);
5974     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5975 
5976     query = "SELECT `A`, `B` FROM `Mesa` ORDER BY `C`";
5977     r = MsiDatabaseOpenViewA(hdb, query, &hview);
5978     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5979     r = MsiViewExecute(hview, 0);
5980     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5981 
5982     r = MsiViewFetch(hview, &hrec);
5983     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5984 
5985     val = MsiRecordGetInteger(hrec, 1);
5986     ok(val == 3, "Expected 3, got %d\n", val);
5987 
5988     val = MsiRecordGetInteger(hrec, 2);
5989     ok(val == 4, "Expected 3, got %d\n", val);
5990 
5991     MsiCloseHandle(hrec);
5992 
5993     r = MsiViewFetch(hview, &hrec);
5994     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5995 
5996     val = MsiRecordGetInteger(hrec, 1);
5997     ok(val == 5, "Expected 5, got %d\n", val);
5998 
5999     val = MsiRecordGetInteger(hrec, 2);
6000     ok(val == 6, "Expected 6, got %d\n", val);
6001 
6002     MsiCloseHandle(hrec);
6003 
6004     r = MsiViewFetch(hview, &hrec);
6005     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6006 
6007     val = MsiRecordGetInteger(hrec, 1);
6008     ok(val == 1, "Expected 1, got %d\n", val);
6009 
6010     val = MsiRecordGetInteger(hrec, 2);
6011     ok(val == 2, "Expected 2, got %d\n", val);
6012 
6013     MsiCloseHandle(hrec);
6014 
6015     r = MsiViewFetch(hview, &hrec);
6016     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6017 
6018     MsiViewClose(hview);
6019     MsiCloseHandle(hview);
6020 
6021     query = "SELECT `A`, `D` FROM `Mesa`, `Sideboard` ORDER BY `F`";
6022     r = MsiDatabaseOpenViewA(hdb, query, &hview);
6023     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6024     r = MsiViewExecute(hview, 0);
6025     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6026 
6027     r = MsiViewFetch(hview, &hrec);
6028     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6029 
6030     val = MsiRecordGetInteger(hrec, 1);
6031     ok(val == 1, "Expected 1, got %d\n", val);
6032 
6033     val = MsiRecordGetInteger(hrec, 2);
6034     ok(val == 12, "Expected 12, got %d\n", val);
6035 
6036     MsiCloseHandle(hrec);
6037 
6038     r = MsiViewFetch(hview, &hrec);
6039     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6040 
6041     val = MsiRecordGetInteger(hrec, 1);
6042     ok(val == 3, "Expected 3, got %d\n", val);
6043 
6044     val = MsiRecordGetInteger(hrec, 2);
6045     ok(val == 12, "Expected 12, got %d\n", val);
6046 
6047     MsiCloseHandle(hrec);
6048 
6049     r = MsiViewFetch(hview, &hrec);
6050     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6051 
6052     val = MsiRecordGetInteger(hrec, 1);
6053     ok(val == 5, "Expected 5, got %d\n", val);
6054 
6055     val = MsiRecordGetInteger(hrec, 2);
6056     ok(val == 12, "Expected 12, got %d\n", val);
6057 
6058     MsiCloseHandle(hrec);
6059 
6060     r = MsiViewFetch(hview, &hrec);
6061     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6062 
6063     val = MsiRecordGetInteger(hrec, 1);
6064     ok(val == 1, "Expected 1, got %d\n", val);
6065 
6066     val = MsiRecordGetInteger(hrec, 2);
6067     ok(val == 14, "Expected 14, got %d\n", val);
6068 
6069     MsiCloseHandle(hrec);
6070 
6071     r = MsiViewFetch(hview, &hrec);
6072     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6073 
6074     val = MsiRecordGetInteger(hrec, 1);
6075     ok(val == 3, "Expected 3, got %d\n", val);
6076 
6077     val = MsiRecordGetInteger(hrec, 2);
6078     ok(val == 14, "Expected 14, got %d\n", val);
6079 
6080     MsiCloseHandle(hrec);
6081 
6082     r = MsiViewFetch(hview, &hrec);
6083     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6084 
6085     val = MsiRecordGetInteger(hrec, 1);
6086     ok(val == 5, "Expected 5, got %d\n", val);
6087 
6088     val = MsiRecordGetInteger(hrec, 2);
6089     ok(val == 14, "Expected 14, got %d\n", val);
6090 
6091     MsiCloseHandle(hrec);
6092 
6093     r = MsiViewFetch(hview, &hrec);
6094     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6095 
6096     val = MsiRecordGetInteger(hrec, 1);
6097     ok(val == 1, "Expected 1, got %d\n", val);
6098 
6099     val = MsiRecordGetInteger(hrec, 2);
6100     ok(val == 10, "Expected 10, got %d\n", val);
6101 
6102     MsiCloseHandle(hrec);
6103 
6104     r = MsiViewFetch(hview, &hrec);
6105     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6106 
6107     val = MsiRecordGetInteger(hrec, 1);
6108     ok(val == 3, "Expected 3, got %d\n", val);
6109 
6110     val = MsiRecordGetInteger(hrec, 2);
6111     ok(val == 10, "Expected 10, got %d\n", val);
6112 
6113     MsiCloseHandle(hrec);
6114 
6115     r = MsiViewFetch(hview, &hrec);
6116     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6117 
6118     val = MsiRecordGetInteger(hrec, 1);
6119     ok(val == 5, "Expected 5, got %d\n", val);
6120 
6121     val = MsiRecordGetInteger(hrec, 2);
6122     ok(val == 10, "Expected 10, got %d\n", val);
6123 
6124     MsiCloseHandle(hrec);
6125 
6126     r = MsiViewFetch(hview, &hrec);
6127     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6128 
6129     MsiViewClose(hview);
6130     MsiCloseHandle(hview);
6131 
6132     query = "SELECT * FROM `Empty` ORDER BY `A`";
6133     r = MsiDatabaseOpenViewA(hdb, query, &hview);
6134     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6135     r = MsiViewExecute(hview, 0);
6136     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6137 
6138     r = MsiViewFetch(hview, &hrec);
6139     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6140 
6141     MsiViewClose(hview);
6142     MsiCloseHandle(hview);
6143 
6144     query = "CREATE TABLE `Buffet` ( `One` CHAR(72), `Two` SHORT PRIMARY KEY `One`)";
6145     r = run_query(hdb, 0, query);
6146     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6147 
6148     query = "INSERT INTO `Buffet` ( `One`, `Two` ) VALUES ( 'uno',  2)";
6149     r = run_query(hdb, 0, query);
6150     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6151 
6152     query = "INSERT INTO `Buffet` ( `One`, `Two` ) VALUES ( 'dos',  3)";
6153     r = run_query(hdb, 0, query);
6154     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6155 
6156     query = "INSERT INTO `Buffet` ( `One`, `Two` ) VALUES ( 'tres',  1)";
6157     r = run_query(hdb, 0, query);
6158     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6159 
6160     query = "SELECT * FROM `Buffet` WHERE `One` = 'dos' ORDER BY `Two`";
6161     r = MsiDatabaseOpenViewA(hdb, query, &hview);
6162     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6163     r = MsiViewExecute(hview, 0);
6164     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6165 
6166     r = MsiViewFetch(hview, &hrec);
6167     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6168     check_record(hrec, 2, "dos", "3");
6169     MsiCloseHandle(hrec);
6170 
6171     r = MsiViewFetch(hview, &hrec);
6172     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6173 
6174     MsiViewClose(hview);
6175     MsiCloseHandle(hview);
6176     MsiCloseHandle(hdb);
6177 }
6178 
6179 static void test_viewmodify_delete_temporary(void)
6180 {
6181     MSIHANDLE hdb, hview, hrec;
6182     const char *query;
6183     UINT r;
6184 
6185     DeleteFileA(msifile);
6186 
6187     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
6188     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6189 
6190     query = "CREATE TABLE `Table` ( `A` SHORT PRIMARY KEY `A` )";
6191     r = run_query(hdb, 0, query);
6192     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6193 
6194     query = "SELECT * FROM `Table`";
6195     r = MsiDatabaseOpenViewA(hdb, query, &hview);
6196     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6197     r = MsiViewExecute(hview, 0);
6198     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6199 
6200     hrec = MsiCreateRecord(1);
6201     MsiRecordSetInteger(hrec, 1, 1);
6202 
6203     r = MsiViewModify(hview, MSIMODIFY_INSERT, hrec);
6204     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6205 
6206     MsiCloseHandle(hrec);
6207 
6208     hrec = MsiCreateRecord(1);
6209     MsiRecordSetInteger(hrec, 1, 2);
6210 
6211     r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec);
6212     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6213 
6214     MsiCloseHandle(hrec);
6215 
6216     hrec = MsiCreateRecord(1);
6217     MsiRecordSetInteger(hrec, 1, 3);
6218 
6219     r = MsiViewModify(hview, MSIMODIFY_INSERT, hrec);
6220     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6221 
6222     MsiCloseHandle(hrec);
6223 
6224     hrec = MsiCreateRecord(1);
6225     MsiRecordSetInteger(hrec, 1, 4);
6226 
6227     r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec);
6228     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6229 
6230     MsiCloseHandle(hrec);
6231     MsiViewClose(hview);
6232     MsiCloseHandle(hview);
6233 
6234     query = "SELECT * FROM `Table` WHERE  `A` = 2";
6235     r = MsiDatabaseOpenViewA(hdb, query, &hview);
6236     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6237     r = MsiViewExecute(hview, 0);
6238     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6239     r = MsiViewFetch(hview, &hrec);
6240     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6241 
6242     r = MsiViewModify(hview, MSIMODIFY_DELETE, hrec);
6243     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6244 
6245     MsiCloseHandle(hrec);
6246     MsiViewClose(hview);
6247     MsiCloseHandle(hview);
6248 
6249     query = "SELECT * FROM `Table` WHERE  `A` = 3";
6250     r = MsiDatabaseOpenViewA(hdb, query, &hview);
6251     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6252     r = MsiViewExecute(hview, 0);
6253     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6254     r = MsiViewFetch(hview, &hrec);
6255     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6256 
6257     r = MsiViewModify(hview, MSIMODIFY_DELETE, hrec);
6258     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6259 
6260     MsiCloseHandle(hrec);
6261     MsiViewClose(hview);
6262     MsiCloseHandle(hview);
6263 
6264     query = "SELECT * FROM `Table` ORDER BY `A`";
6265     r = MsiDatabaseOpenViewA(hdb, query, &hview);
6266     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6267     r = MsiViewExecute(hview, 0);
6268     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6269 
6270     r = MsiViewFetch(hview, &hrec);
6271     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6272 
6273     r = MsiRecordGetInteger(hrec, 1);
6274     ok(r == 1, "Expected 1, got %d\n", r);
6275 
6276     MsiCloseHandle(hrec);
6277 
6278     r = MsiViewFetch(hview, &hrec);
6279     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6280 
6281     r = MsiRecordGetInteger(hrec, 1);
6282     ok(r == 4, "Expected 4, got %d\n", r);
6283 
6284     MsiCloseHandle(hrec);
6285 
6286     r = MsiViewFetch(hview, &hrec);
6287     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6288 
6289     MsiViewClose(hview);
6290     MsiCloseHandle(hview);
6291     MsiCloseHandle(hdb);
6292     DeleteFileA(msifile);
6293 }
6294 
6295 static void test_deleterow(void)
6296 {
6297     MSIHANDLE hdb, hview, hrec;
6298     const char *query;
6299     UINT r;
6300 
6301     DeleteFileA(msifile);
6302 
6303     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
6304     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6305 
6306     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6307     r = run_query(hdb, 0, query);
6308     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6309 
6310     query = "INSERT INTO `Table` (`A`) VALUES ('one')";
6311     r = run_query(hdb, 0, query);
6312     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6313 
6314     query = "INSERT INTO `Table` (`A`) VALUES ('two')";
6315     r = run_query(hdb, 0, query);
6316     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6317 
6318     query = "DELETE FROM `Table` WHERE `A` = 'one'";
6319     r = run_query(hdb, 0, query);
6320     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6321 
6322     r = MsiDatabaseCommit(hdb);
6323     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6324 
6325     MsiCloseHandle(hdb);
6326 
6327     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_READONLY, &hdb);
6328     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6329 
6330     query = "SELECT * FROM `Table`";
6331     r = MsiDatabaseOpenViewA(hdb, query, &hview);
6332     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6333     r = MsiViewExecute(hview, 0);
6334     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6335 
6336     r = MsiViewFetch(hview, &hrec);
6337     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6338     check_record(hrec, 1, "two");
6339     MsiCloseHandle(hrec);
6340 
6341     r = MsiViewFetch(hview, &hrec);
6342     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6343 
6344     MsiViewClose(hview);
6345     MsiCloseHandle(hview);
6346     MsiCloseHandle(hdb);
6347     DeleteFileA(msifile);
6348 }
6349 
6350 static const CHAR import_dat[] = "A\n"
6351                                  "s72\n"
6352                                  "Table\tA\n"
6353                                  "This is a new 'string' ok\n";
6354 
6355 static void test_quotes(void)
6356 {
6357     MSIHANDLE hdb, hview, hrec;
6358     const char *query;
6359     UINT r;
6360 
6361     DeleteFileA(msifile);
6362 
6363     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
6364     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6365 
6366     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6367     r = run_query(hdb, 0, query);
6368     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6369 
6370     query = "INSERT INTO `Table` ( `A` ) VALUES ( 'This is a 'string' ok' )";
6371     r = run_query(hdb, 0, query);
6372     ok(r == ERROR_BAD_QUERY_SYNTAX,
6373        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6374 
6375     query = "INSERT INTO `Table` ( `A` ) VALUES ( \"This is a 'string' ok\" )";
6376     r = run_query(hdb, 0, query);
6377     ok(r == ERROR_BAD_QUERY_SYNTAX,
6378        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6379 
6380     query = "INSERT INTO `Table` ( `A` ) VALUES ( \"test\" )";
6381     r = run_query(hdb, 0, query);
6382     ok(r == ERROR_BAD_QUERY_SYNTAX,
6383        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6384 
6385     query = "INSERT INTO `Table` ( `A` ) VALUES ( 'This is a ''string'' ok' )";
6386     r = run_query(hdb, 0, query);
6387     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6388 
6389     query = "INSERT INTO `Table` ( `A` ) VALUES ( 'This is a '''string''' ok' )";
6390     r = run_query(hdb, 0, query);
6391     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6392 
6393     query = "INSERT INTO `Table` ( `A` ) VALUES ( 'This is a \'string\' ok' )";
6394     r = run_query(hdb, 0, query);
6395     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6396 
6397     query = "INSERT INTO `Table` ( `A` ) VALUES ( 'This is a \"string\" ok' )";
6398     r = run_query(hdb, 0, query);
6399     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6400 
6401     query = "SELECT * FROM `Table`";
6402     r = MsiDatabaseOpenViewA(hdb, query, &hview);
6403     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6404 
6405     r = MsiViewExecute(hview, 0);
6406     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6407 
6408     r = MsiViewFetch(hview, &hrec);
6409     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6410     check_record(hrec, 1, "This is a \"string\" ok");
6411     MsiCloseHandle(hrec);
6412 
6413     r = MsiViewFetch(hview, &hrec);
6414     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6415 
6416     MsiViewClose(hview);
6417     MsiCloseHandle(hview);
6418 
6419     write_file("import.idt", import_dat, (sizeof(import_dat) - 1) * sizeof(char));
6420 
6421     r = MsiDatabaseImportA(hdb, CURR_DIR, "import.idt");
6422     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6423 
6424     DeleteFileA("import.idt");
6425 
6426     query = "SELECT * FROM `Table`";
6427     r = MsiDatabaseOpenViewA(hdb, query, &hview);
6428     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6429 
6430     r = MsiViewExecute(hview, 0);
6431     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6432 
6433     r = MsiViewFetch(hview, &hrec);
6434     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6435     check_record(hrec, 1, "This is a new 'string' ok");
6436     MsiCloseHandle(hrec);
6437 
6438     r = MsiViewFetch(hview, &hrec);
6439     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6440 
6441     MsiViewClose(hview);
6442     MsiCloseHandle(hview);
6443     MsiCloseHandle(hdb);
6444     DeleteFileA(msifile);
6445 }
6446 
6447 static void test_carriagereturn(void)
6448 {
6449     MSIHANDLE hdb, hview, hrec;
6450     const char *query;
6451     UINT r;
6452 
6453     DeleteFileA(msifile);
6454 
6455     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
6456     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6457 
6458     query = "CREATE TABLE `Table`\r ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6459     r = run_query(hdb, 0, query);
6460     ok(r == ERROR_BAD_QUERY_SYNTAX,
6461        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6462 
6463     query = "CREATE TABLE `Table` \r( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6464     r = run_query(hdb, 0, query);
6465     ok(r == ERROR_BAD_QUERY_SYNTAX,
6466        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6467 
6468     query = "CREATE\r TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6469     r = run_query(hdb, 0, query);
6470     ok(r == ERROR_BAD_QUERY_SYNTAX,
6471        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6472 
6473     query = "CREATE TABLE\r `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6474     r = run_query(hdb, 0, query);
6475     ok(r == ERROR_BAD_QUERY_SYNTAX,
6476        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6477 
6478     query = "CREATE TABLE `Table` (\r `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6479     r = run_query(hdb, 0, query);
6480     ok(r == ERROR_BAD_QUERY_SYNTAX,
6481        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6482 
6483     query = "CREATE TABLE `Table` ( `A`\r CHAR(72) NOT NULL PRIMARY KEY `A` )";
6484     r = run_query(hdb, 0, query);
6485     ok(r == ERROR_BAD_QUERY_SYNTAX,
6486        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6487 
6488     query = "CREATE TABLE `Table` ( `A` CHAR(72)\r NOT NULL PRIMARY KEY `A` )";
6489     r = run_query(hdb, 0, query);
6490     ok(r == ERROR_BAD_QUERY_SYNTAX,
6491        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6492 
6493     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT\r NULL PRIMARY KEY `A` )";
6494     r = run_query(hdb, 0, query);
6495     ok(r == ERROR_BAD_QUERY_SYNTAX,
6496        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6497 
6498     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT \rNULL PRIMARY KEY `A` )";
6499     r = run_query(hdb, 0, query);
6500     ok(r == ERROR_BAD_QUERY_SYNTAX,
6501        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6502 
6503     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL\r PRIMARY KEY `A` )";
6504     r = run_query(hdb, 0, query);
6505     ok(r == ERROR_BAD_QUERY_SYNTAX,
6506        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6507 
6508     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL \rPRIMARY KEY `A` )";
6509     r = run_query(hdb, 0, query);
6510     ok(r == ERROR_BAD_QUERY_SYNTAX,
6511        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6512 
6513     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY\r KEY `A` )";
6514     r = run_query(hdb, 0, query);
6515     ok(r == ERROR_BAD_QUERY_SYNTAX,
6516        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6517 
6518     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY \rKEY `A` )";
6519     r = run_query(hdb, 0, query);
6520     ok(r == ERROR_BAD_QUERY_SYNTAX,
6521        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6522 
6523     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY\r `A` )";
6524     r = run_query(hdb, 0, query);
6525     ok(r == ERROR_BAD_QUERY_SYNTAX,
6526        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6527 
6528     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A`\r )";
6529     r = run_query(hdb, 0, query);
6530     ok(r == ERROR_BAD_QUERY_SYNTAX,
6531        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6532 
6533     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )\r";
6534     r = run_query(hdb, 0, query);
6535     ok(r == ERROR_BAD_QUERY_SYNTAX,
6536        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6537 
6538     query = "CREATE TABLE `\rOne` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6539     r = run_query(hdb, 0, query);
6540     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6541 
6542     query = "CREATE TABLE `Tw\ro` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6543     r = run_query(hdb, 0, query);
6544     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6545 
6546     query = "CREATE TABLE `Three\r` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6547     r = run_query(hdb, 0, query);
6548     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6549 
6550     query = "CREATE TABLE `Four` ( `A\r` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6551     r = run_query(hdb, 0, query);
6552     ok(r == ERROR_BAD_QUERY_SYNTAX,
6553        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6554 
6555     query = "CREATE TABLE `Four` ( `\rA` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6556     r = run_query(hdb, 0, query);
6557     ok(r == ERROR_BAD_QUERY_SYNTAX,
6558        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6559 
6560     query = "CREATE TABLE `Four` ( `A` CHAR(72\r) NOT NULL PRIMARY KEY `A` )";
6561     r = run_query(hdb, 0, query);
6562     ok(r == ERROR_BAD_QUERY_SYNTAX,
6563        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6564 
6565     query = "CREATE TABLE `Four` ( `A` CHAR(\r72) NOT NULL PRIMARY KEY `A` )";
6566     r = run_query(hdb, 0, query);
6567     ok(r == ERROR_BAD_QUERY_SYNTAX,
6568        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6569 
6570     query = "CREATE TABLE `Four` ( `A` CHAR(72) NOT NULL PRIMARY KEY `\rA` )";
6571     r = run_query(hdb, 0, query);
6572     ok(r == ERROR_BAD_QUERY_SYNTAX,
6573        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6574 
6575     query = "CREATE TABLE `Four` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A\r` )";
6576     r = run_query(hdb, 0, query);
6577     ok(r == ERROR_BAD_QUERY_SYNTAX,
6578        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6579 
6580     query = "CREATE TABLE `Four` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A\r` )";
6581     r = run_query(hdb, 0, query);
6582     ok(r == ERROR_BAD_QUERY_SYNTAX,
6583        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6584 
6585     query = "SELECT `Name` FROM `_Tables`";
6586     r = MsiDatabaseOpenViewA(hdb, query, &hview);
6587     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6588     r = MsiViewExecute(hview, 0);
6589     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6590 
6591     r = MsiViewFetch(hview, &hrec);
6592     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6593     check_record(hrec, 1, "\rOne");
6594     MsiCloseHandle(hrec);
6595 
6596     r = MsiViewFetch(hview, &hrec);
6597     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6598     check_record(hrec, 1, "Tw\ro");
6599     MsiCloseHandle(hrec);
6600 
6601     r = MsiViewFetch(hview, &hrec);
6602     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6603     check_record(hrec, 1, "Three\r");
6604     MsiCloseHandle(hrec);
6605 
6606     r = MsiViewFetch(hview, &hrec);
6607     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6608 
6609     MsiViewClose(hview);
6610     MsiCloseHandle(hview);
6611 
6612     MsiCloseHandle(hdb);
6613     DeleteFileA(msifile);
6614 }
6615 
6616 static void test_noquotes(void)
6617 {
6618     MSIHANDLE hdb, hview, hrec;
6619     const char *query;
6620     UINT r;
6621 
6622     DeleteFileA(msifile);
6623 
6624     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
6625     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6626 
6627     query = "CREATE TABLE Table ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6628     r = run_query(hdb, 0, query);
6629     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6630 
6631     query = "CREATE TABLE `Table` ( A CHAR(72) NOT NULL PRIMARY KEY `A` )";
6632     r = run_query(hdb, 0, query);
6633     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6634 
6635     query = "CREATE TABLE `Table2` ( `A` CHAR(72) NOT NULL PRIMARY KEY A )";
6636     r = run_query(hdb, 0, query);
6637     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6638 
6639     query = "CREATE TABLE `Table3` ( A CHAR(72) NOT NULL PRIMARY KEY A )";
6640     r = run_query(hdb, 0, query);
6641     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6642 
6643     query = "SELECT `Name` FROM `_Tables`";
6644     r = MsiDatabaseOpenViewA(hdb, query, &hview);
6645     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6646     r = MsiViewExecute(hview, 0);
6647     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6648 
6649     r = MsiViewFetch(hview, &hrec);
6650     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6651     check_record(hrec, 1, "Table");
6652     MsiCloseHandle(hrec);
6653 
6654     r = MsiViewFetch(hview, &hrec);
6655     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6656     check_record(hrec, 1, "Table2");
6657     MsiCloseHandle(hrec);
6658 
6659     r = MsiViewFetch(hview, &hrec);
6660     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6661     check_record(hrec, 1, "Table3");
6662     MsiCloseHandle(hrec);
6663 
6664     r = MsiViewFetch(hview, &hrec);
6665     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6666 
6667     MsiViewClose(hview);
6668     MsiCloseHandle(hview);
6669 
6670     query = "SELECT `Table`, `Number`, `Name` FROM `_Columns`";
6671     r = MsiDatabaseOpenViewA(hdb, query, &hview);
6672     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6673     r = MsiViewExecute(hview, 0);
6674     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6675 
6676     r = MsiViewFetch(hview, &hrec);
6677     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6678     check_record(hrec, 3, "Table", "1", "A");
6679     MsiCloseHandle(hrec);
6680 
6681     r = MsiViewFetch(hview, &hrec);
6682     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6683     check_record(hrec, 3, "Table2", "1", "A");
6684     MsiCloseHandle(hrec);
6685 
6686     r = MsiViewFetch(hview, &hrec);
6687     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6688     check_record(hrec, 3, "Table3", "1", "A");
6689     MsiCloseHandle(hrec);
6690 
6691     r = MsiViewFetch(hview, &hrec);
6692     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6693 
6694     MsiViewClose(hview);
6695     MsiCloseHandle(hview);
6696 
6697     query = "INSERT INTO Table ( `A` ) VALUES ( 'hi' )";
6698     r = run_query(hdb, 0, query);
6699     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6700 
6701     query = "INSERT INTO `Table` ( A ) VALUES ( 'hi' )";
6702     r = run_query(hdb, 0, query);
6703     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6704 
6705     query = "INSERT INTO `Table` ( `A` ) VALUES ( hi )";
6706     r = run_query(hdb, 0, query);
6707     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6708 
6709     query = "SELECT * FROM Table WHERE `A` = 'hi'";
6710     r = run_query(hdb, 0, query);
6711     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6712 
6713     query = "SELECT * FROM `Table` WHERE `A` = hi";
6714     r = run_query(hdb, 0, query);
6715     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6716 
6717     query = "SELECT * FROM Table";
6718     r = run_query(hdb, 0, query);
6719     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6720 
6721     query = "SELECT * FROM Table2";
6722     r = MsiDatabaseOpenViewA(hdb, query, &hview);
6723     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6724     r = MsiViewExecute(hview, 0);
6725     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6726 
6727     r = MsiViewFetch(hview, &hrec);
6728     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6729 
6730     MsiViewClose(hview);
6731     MsiCloseHandle(hview);
6732 
6733     query = "SELECT * FROM `Table` WHERE A = 'hi'";
6734     r = MsiDatabaseOpenViewA(hdb, query, &hview);
6735     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6736     r = MsiViewExecute(hview, 0);
6737     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6738 
6739     r = MsiViewFetch(hview, &hrec);
6740     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6741     check_record(hrec, 1, "hi");
6742     MsiCloseHandle(hrec);
6743 
6744     r = MsiViewFetch(hview, &hrec);
6745     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6746 
6747     MsiViewClose(hview);
6748     MsiCloseHandle(hview);
6749     MsiCloseHandle(hdb);
6750     DeleteFileA(msifile);
6751 }
6752 
6753 static void read_file_data(LPCSTR filename, LPSTR buffer)
6754 {
6755     HANDLE file;
6756     DWORD read;
6757 
6758     file = CreateFileA( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
6759     ZeroMemory(buffer, MAX_PATH);
6760     ReadFile(file, buffer, MAX_PATH, &read, NULL);
6761     CloseHandle(file);
6762 }
6763 
6764 static void test_forcecodepage(void)
6765 {
6766     MSIHANDLE hdb;
6767     const char *query;
6768     char buffer[MAX_PATH];
6769     UINT r;
6770 
6771     DeleteFileA(msifile);
6772     GetCurrentDirectoryA(MAX_PATH, CURR_DIR);
6773 
6774     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
6775     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6776 
6777     query = "SELECT * FROM `_ForceCodepage`";
6778     r = run_query(hdb, 0, query);
6779     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6780 
6781     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6782     r = run_query(hdb, 0, query);
6783     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6784 
6785     query = "SELECT * FROM `_ForceCodepage`";
6786     r = run_query(hdb, 0, query);
6787     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6788 
6789     r = MsiDatabaseCommit(hdb);
6790     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6791 
6792     query = "SELECT * FROM `_ForceCodepage`";
6793     r = run_query(hdb, 0, query);
6794     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6795 
6796     MsiCloseHandle(hdb);
6797 
6798     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_DIRECT, &hdb);
6799     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6800 
6801     query = "SELECT * FROM `_ForceCodepage`";
6802     r = run_query(hdb, 0, query);
6803     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6804 
6805     r = MsiDatabaseExportA(hdb, "_ForceCodepage", CURR_DIR, "forcecodepage.idt");
6806     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6807 
6808     read_file_data("forcecodepage.idt", buffer);
6809     ok(!lstrcmpA(buffer, "\r\n\r\n0\t_ForceCodepage\r\n"),
6810        "Expected \"\r\n\r\n0\t_ForceCodepage\r\n\", got \"%s\"\n", buffer);
6811 
6812     create_file_data("forcecodepage.idt", "\r\n\r\n850\t_ForceCodepage\r\n", 0);
6813 
6814     r = MsiDatabaseImportA(hdb, CURR_DIR, "forcecodepage.idt");
6815     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6816 
6817     r = MsiDatabaseExportA(hdb, "_ForceCodepage", CURR_DIR, "forcecodepage.idt");
6818     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6819 
6820     read_file_data("forcecodepage.idt", buffer);
6821     ok(!lstrcmpA(buffer, "\r\n\r\n850\t_ForceCodepage\r\n"),
6822        "Expected \"\r\n\r\n850\t_ForceCodepage\r\n\", got \"%s\"\n", buffer);
6823 
6824     create_file_data("forcecodepage.idt", "\r\n\r\n9999\t_ForceCodepage\r\n", 0);
6825 
6826     r = MsiDatabaseImportA(hdb, CURR_DIR, "forcecodepage.idt");
6827     ok(r == ERROR_FUNCTION_FAILED, "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
6828 
6829     MsiCloseHandle(hdb);
6830     DeleteFileA(msifile);
6831     DeleteFileA("forcecodepage.idt");
6832 }
6833 
6834 static void test_viewmodify_refresh(void)
6835 {
6836     MSIHANDLE hdb, hview, hrec;
6837     const char *query;
6838     UINT r;
6839 
6840     DeleteFileA(msifile);
6841 
6842     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
6843     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6844 
6845     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL, `B` INT PRIMARY KEY `A` )";
6846     r = run_query(hdb, 0, query);
6847     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6848 
6849     query = "INSERT INTO `Table` ( `A`, `B` ) VALUES ( 'hi', 1 )";
6850     r = run_query(hdb, 0, query);
6851     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6852 
6853     query = "SELECT * FROM `Table`";
6854     r = MsiDatabaseOpenViewA(hdb, query, &hview);
6855     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6856     r = MsiViewExecute(hview, 0);
6857     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6858 
6859     r = MsiViewFetch(hview, &hrec);
6860     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6861     check_record(hrec, 2, "hi", "1");
6862 
6863     MsiRecordSetInteger(hrec, 2, 5);
6864     r = MsiViewModify(hview, MSIMODIFY_REFRESH, hrec);
6865     ok(!r, "got %u\n", r);
6866     check_record(hrec, 2, "hi", "1");
6867 
6868     MsiRecordSetStringA(hrec, 1, "foo");
6869     r = MsiViewModify(hview, MSIMODIFY_REFRESH, hrec);
6870     ok(!r, "got %u\n", r);
6871     check_record(hrec, 2, "hi", "1");
6872 
6873     query = "UPDATE `Table` SET `B` = 2 WHERE `A` = 'hi'";
6874     r = run_query(hdb, 0, query);
6875     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6876 
6877     r = MsiViewModify(hview, MSIMODIFY_REFRESH, hrec);
6878     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6879     check_record(hrec, 2, "hi", "2");
6880 
6881     r = run_query(hdb, 0, "UPDATE `Table` SET `B` = NULL WHERE `A` = 'hi'");
6882     ok(!r, "got %u\n", r);
6883 
6884     r = MsiViewModify(hview, MSIMODIFY_REFRESH, hrec);
6885     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6886     check_record(hrec, 2, "hi", "");
6887 
6888     MsiCloseHandle(hrec);
6889 
6890     MsiViewClose(hview);
6891     MsiCloseHandle(hview);
6892 
6893     query = "INSERT INTO `Table` ( `A`, `B` ) VALUES ( 'hello', 3 )";
6894     r = run_query(hdb, 0, query);
6895     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6896 
6897     query = "SELECT * FROM `Table` WHERE `B` = 3";
6898     r = MsiDatabaseOpenViewA(hdb, query, &hview);
6899     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6900     r = MsiViewExecute(hview, 0);
6901     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6902 
6903     r = MsiViewFetch(hview, &hrec);
6904     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6905 
6906     query = "UPDATE `Table` SET `B` = 2 WHERE `A` = 'hello'";
6907     r = run_query(hdb, 0, query);
6908     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6909 
6910     query = "INSERT INTO `Table` ( `A`, `B` ) VALUES ( 'hithere', 3 )";
6911     r = run_query(hdb, 0, query);
6912     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6913 
6914     r = MsiViewModify(hview, MSIMODIFY_REFRESH, hrec);
6915     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6916     check_record(hrec, 2, "hello", "2");
6917     MsiCloseHandle(hrec);
6918 
6919     MsiViewClose(hview);
6920     MsiCloseHandle(hview);
6921 
6922     r = MsiDatabaseOpenViewA(hdb, "SELECT `B` FROM `Table` WHERE `A` = 'hello'", &hview);
6923     ok(!r, "got %u\n", r);
6924     r = MsiViewExecute(hview, 0);
6925     ok(!r, "got %u\n", r);
6926 
6927     r = MsiViewFetch(hview, &hrec);
6928     ok(!r, "got %u\n", r);
6929     check_record(hrec, 1, "2");
6930 
6931     MsiRecordSetInteger(hrec, 1, 8);
6932     r = MsiViewModify(hview, MSIMODIFY_REFRESH, hrec);
6933     ok(!r, "got %u\n", r);
6934     check_record(hrec, 1, "2");
6935 
6936     MsiCloseHandle(hrec);
6937     MsiCloseHandle(hview);
6938 
6939     MsiCloseHandle(hdb);
6940     DeleteFileA(msifile);
6941 }
6942 
6943 static void test_where_viewmodify(void)
6944 {
6945     MSIHANDLE hdb, hview, hrec;
6946     const char *query;
6947     UINT r;
6948 
6949     DeleteFileA(msifile);
6950 
6951     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
6952     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6953 
6954     query = "CREATE TABLE `Table` ( `A` INT, `B` INT PRIMARY KEY `A` )";
6955     r = run_query(hdb, 0, query);
6956     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6957 
6958     query = "INSERT INTO `Table` ( `A`, `B` ) VALUES ( 1, 2 )";
6959     r = run_query(hdb, 0, query);
6960     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6961 
6962     query = "INSERT INTO `Table` ( `A`, `B` ) VALUES ( 3, 4 )";
6963     r = run_query(hdb, 0, query);
6964     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6965 
6966     query = "INSERT INTO `Table` ( `A`, `B` ) VALUES ( 5, 6 )";
6967     r = run_query(hdb, 0, query);
6968     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6969 
6970     /* `B` = 3 doesn't match, but the view shouldn't be executed */
6971     query = "SELECT * FROM `Table` WHERE `B` = 3";
6972     r = MsiDatabaseOpenViewA(hdb, query, &hview);
6973     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6974 
6975     hrec = MsiCreateRecord(2);
6976     MsiRecordSetInteger(hrec, 1, 7);
6977     MsiRecordSetInteger(hrec, 2, 8);
6978 
6979     r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec);
6980     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6981 
6982     MsiCloseHandle(hrec);
6983     MsiViewClose(hview);
6984     MsiCloseHandle(hview);
6985 
6986     query = "SELECT * FROM `Table` WHERE `A` = 7";
6987     r = MsiDatabaseOpenViewA(hdb, query, &hview);
6988     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6989     r = MsiViewExecute(hview, 0);
6990     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6991 
6992     r = MsiViewFetch(hview, &hrec);
6993     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6994 
6995     r = MsiRecordGetInteger(hrec, 1);
6996     ok(r == 7, "Expected 7, got %d\n", r);
6997 
6998     r = MsiRecordGetInteger(hrec, 2);
6999     ok(r == 8, "Expected 8, got %d\n", r);
7000 
7001     MsiRecordSetInteger(hrec, 2, 9);
7002 
7003     r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
7004     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7005 
7006     MsiCloseHandle(hrec);
7007     MsiViewClose(hview);
7008     MsiCloseHandle(hview);
7009 
7010     query = "SELECT * FROM `Table` WHERE `A` = 7";
7011     r = MsiDatabaseOpenViewA(hdb, query, &hview);
7012     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7013     r = MsiViewExecute(hview, 0);
7014     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7015 
7016     r = MsiViewFetch(hview, &hrec);
7017     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7018 
7019     r = MsiRecordGetInteger(hrec, 1);
7020     ok(r == 7, "Expected 7, got %d\n", r);
7021 
7022     r = MsiRecordGetInteger(hrec, 2);
7023     ok(r == 9, "Expected 9, got %d\n", r);
7024 
7025     query = "UPDATE `Table` SET `B` = 10 WHERE `A` = 7";
7026     r = run_query(hdb, 0, query);
7027     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7028 
7029     r = MsiViewModify(hview, MSIMODIFY_REFRESH, hrec);
7030     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7031 
7032     r = MsiRecordGetInteger(hrec, 1);
7033     ok(r == 7, "Expected 7, got %d\n", r);
7034 
7035     r = MsiRecordGetInteger(hrec, 2);
7036     ok(r == 10, "Expected 10, got %d\n", r);
7037 
7038     MsiCloseHandle(hrec);
7039     MsiViewClose(hview);
7040     MsiCloseHandle(hview);
7041     MsiCloseHandle(hdb);
7042 }
7043 
7044 static BOOL create_storage(LPCSTR name)
7045 {
7046     WCHAR nameW[MAX_PATH];
7047     IStorage *stg;
7048     IStream *stm;
7049     HRESULT hr;
7050     DWORD count;
7051     BOOL res = FALSE;
7052 
7053     MultiByteToWideChar(CP_ACP, 0, name, -1, nameW, MAX_PATH);
7054     hr = StgCreateDocfile(nameW, STGM_CREATE | STGM_READWRITE |
7055                           STGM_DIRECT | STGM_SHARE_EXCLUSIVE, 0, &stg);
7056     if (FAILED(hr))
7057         return FALSE;
7058 
7059     hr = IStorage_CreateStream(stg, nameW, STGM_WRITE | STGM_SHARE_EXCLUSIVE,
7060                                0, 0, &stm);
7061     if (FAILED(hr))
7062         goto done;
7063 
7064     hr = IStream_Write(stm, "stgdata", 8, &count);
7065     if (SUCCEEDED(hr))
7066         res = TRUE;
7067 
7068 done:
7069     IStream_Release(stm);
7070     IStorage_Release(stg);
7071 
7072     return res;
7073 }
7074 
7075 static void test_storages_table(void)
7076 {
7077     MSIHANDLE hdb, hview, hrec;
7078     IStorage *stg, *inner;
7079     IStream *stm;
7080     char file[MAX_PATH];
7081     char buf[MAX_PATH];
7082     WCHAR name[MAX_PATH];
7083     LPCSTR query;
7084     HRESULT hr;
7085     DWORD size;
7086     UINT r;
7087 
7088     hdb = create_db();
7089     ok(hdb, "failed to create db\n");
7090 
7091     r = MsiDatabaseCommit(hdb);
7092     ok(r == ERROR_SUCCESS , "Failed to commit database\n");
7093 
7094     MsiCloseHandle(hdb);
7095 
7096     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_TRANSACT, &hdb);
7097     ok(r == ERROR_SUCCESS , "Failed to open database\n");
7098 
7099     /* check the column types */
7100     hrec = get_column_info(hdb, "SELECT * FROM `_Storages`", MSICOLINFO_TYPES);
7101     ok(hrec, "failed to get column info hrecord\n");
7102     check_record(hrec, 2, "s62", "V0");
7103     MsiCloseHandle(hrec);
7104 
7105     /* now try the names */
7106     hrec = get_column_info(hdb, "SELECT * FROM `_Storages`", MSICOLINFO_NAMES);
7107     ok(hrec, "failed to get column info hrecord\n");
7108     check_record(hrec, 2, "Name", "Data");
7109     MsiCloseHandle(hrec);
7110 
7111     create_storage("storage.bin");
7112 
7113     hrec = MsiCreateRecord(2);
7114     MsiRecordSetStringA(hrec, 1, "stgname");
7115 
7116     r = MsiRecordSetStreamA(hrec, 2, "storage.bin");
7117     ok(r == ERROR_SUCCESS, "Failed to add stream data to the hrecord: %d\n", r);
7118 
7119     DeleteFileA("storage.bin");
7120 
7121     query = "INSERT INTO `_Storages` (`Name`, `Data`) VALUES (?, ?)";
7122     r = MsiDatabaseOpenViewA(hdb, query, &hview);
7123     ok(r == ERROR_SUCCESS, "Failed to open database hview: %d\n", r);
7124 
7125     r = MsiViewExecute(hview, hrec);
7126     ok(r == ERROR_SUCCESS, "Failed to execute hview: %d\n", r);
7127 
7128     MsiCloseHandle(hrec);
7129     MsiViewClose(hview);
7130     MsiCloseHandle(hview);
7131 
7132     query = "SELECT `Name`, `Data` FROM `_Storages`";
7133     r = MsiDatabaseOpenViewA(hdb, query, &hview);
7134     ok(r == ERROR_SUCCESS, "Failed to open database hview: %d\n", r);
7135 
7136     r = MsiViewExecute(hview, 0);
7137     ok(r == ERROR_SUCCESS, "Failed to execute hview: %d\n", r);
7138 
7139     r = MsiViewFetch(hview, &hrec);
7140     ok(r == ERROR_SUCCESS, "Failed to fetch hrecord: %d\n", r);
7141 
7142     size = MAX_PATH;
7143     r = MsiRecordGetStringA(hrec, 1, file, &size);
7144     ok(r == ERROR_SUCCESS, "Failed to get string: %d\n", r);
7145     ok(!lstrcmpA(file, "stgname"), "Expected \"stgname\", got \"%s\"\n", file);
7146 
7147     size = MAX_PATH;
7148     lstrcpyA(buf, "apple");
7149     r = MsiRecordReadStream(hrec, 2, buf, &size);
7150     ok(r == ERROR_INVALID_DATA, "Expected ERROR_INVALID_DATA, got %d\n", r);
7151     ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf);
7152     ok(size == 0, "Expected 0, got %lu\n", size);
7153 
7154     MsiCloseHandle(hrec);
7155 
7156     r = MsiViewFetch(hview, &hrec);
7157     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7158 
7159     MsiViewClose(hview);
7160     MsiCloseHandle(hview);
7161 
7162     MsiDatabaseCommit(hdb);
7163     MsiCloseHandle(hdb);
7164 
7165     MultiByteToWideChar(CP_ACP, 0, msifile, -1, name, MAX_PATH);
7166     hr = StgOpenStorage(name, NULL, STGM_DIRECT | STGM_READ |
7167                         STGM_SHARE_DENY_WRITE, NULL, 0, &stg);
7168     ok(hr == S_OK, "Expected S_OK, got %#lx\n", hr);
7169     ok(stg != NULL, "Expected non-NULL storage\n");
7170 
7171     MultiByteToWideChar(CP_ACP, 0, "stgname", -1, name, MAX_PATH);
7172     hr = IStorage_OpenStorage(stg, name, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE,
7173                               NULL, 0, &inner);
7174     ok(hr == S_OK, "Expected S_OK, got %#lx\n", hr);
7175     ok(inner != NULL, "Expected non-NULL storage\n");
7176 
7177     MultiByteToWideChar(CP_ACP, 0, "storage.bin", -1, name, MAX_PATH);
7178     hr = IStorage_OpenStream(inner, name, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm);
7179     ok(hr == S_OK, "Expected S_OK, got %#lx\n", hr);
7180     ok(stm != NULL, "Expected non-NULL stream\n");
7181 
7182     hr = IStream_Read(stm, buf, MAX_PATH, &size);
7183     ok(hr == S_OK, "Expected S_OK, got %#lx\n", hr);
7184     ok(size == 8, "Expected 8, got %lu\n", size);
7185     ok(!lstrcmpA(buf, "stgdata"), "Expected \"stgdata\", got \"%s\"\n", buf);
7186 
7187     IStream_Release(stm);
7188     IStorage_Release(inner);
7189 
7190     IStorage_Release(stg);
7191     DeleteFileA(msifile);
7192 }
7193 
7194 static void test_dbtopackage(void)
7195 {
7196     MSIHANDLE hdb, hpkg;
7197     CHAR package[12], buf[MAX_PATH];
7198     DWORD size;
7199     UINT r;
7200 
7201     /* create an empty database, transact mode */
7202     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
7203     ok(r == ERROR_SUCCESS, "Failed to create database\n");
7204 
7205     set_summary_info(hdb);
7206 
7207     create_directory_table(hdb);
7208 
7209     create_custom_action_table(hdb);
7210     add_custom_action_entry(hdb, "'SetProp', 51, 'MYPROP', 'grape'");
7211 
7212     sprintf(package, "#%lu", hdb);
7213     r = MsiOpenPackageA(package, &hpkg);
7214     if (r == ERROR_INSTALL_PACKAGE_REJECTED)
7215     {
7216         skip("Not enough rights to perform tests\n");
7217         goto error;
7218     }
7219     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7220 
7221     /* property is not set yet */
7222     size = MAX_PATH;
7223     lstrcpyA(buf, "kiwi");
7224     r = MsiGetPropertyA(hpkg, "MYPROP", buf, &size);
7225     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7226     ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf);
7227     ok(size == 0, "Expected 0, got %lu\n", size);
7228 
7229     /* run the custom action to set the property */
7230     r = MsiDoActionA(hpkg, "SetProp");
7231     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7232 
7233     /* property is now set */
7234     size = MAX_PATH;
7235     lstrcpyA(buf, "kiwi");
7236     r = MsiGetPropertyA(hpkg, "MYPROP", buf, &size);
7237     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7238     ok(!lstrcmpA(buf, "grape"), "Expected \"grape\", got \"%s\"\n", buf);
7239     ok(size == 5, "Expected 5, got %lu\n", size);
7240 
7241     MsiCloseHandle(hpkg);
7242 
7243     /* reset the package */
7244     r = MsiOpenPackageA(package, &hpkg);
7245     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7246 
7247     /* property is not set anymore */
7248     size = MAX_PATH;
7249     lstrcpyA(buf, "kiwi");
7250     r = MsiGetPropertyA(hpkg, "MYPROP", buf, &size);
7251     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7252     todo_wine
7253     {
7254         ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf);
7255         ok(size == 0, "Expected 0, got %lu\n", size);
7256     }
7257 
7258     MsiCloseHandle(hdb);
7259     MsiCloseHandle(hpkg);
7260 
7261     /* create an empty database, direct mode */
7262     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATEDIRECT, &hdb);
7263     ok(r == ERROR_SUCCESS, "Failed to create database\n");
7264 
7265     set_summary_info(hdb);
7266 
7267     create_directory_table(hdb);
7268 
7269     create_custom_action_table(hdb);
7270     add_custom_action_entry(hdb, "'SetProp', 51, 'MYPROP', 'grape'");
7271 
7272     sprintf(package, "#%lu", hdb);
7273     r = MsiOpenPackageA(package, &hpkg);
7274     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7275 
7276     /* property is not set yet */
7277     size = MAX_PATH;
7278     lstrcpyA(buf, "kiwi");
7279     r = MsiGetPropertyA(hpkg, "MYPROP", buf, &size);
7280     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7281     ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf);
7282     ok(size == 0, "Expected 0, got %lu\n", size);
7283 
7284     /* run the custom action to set the property */
7285     r = MsiDoActionA(hpkg, "SetProp");
7286     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7287 
7288     /* property is now set */
7289     size = MAX_PATH;
7290     lstrcpyA(buf, "kiwi");
7291     r = MsiGetPropertyA(hpkg, "MYPROP", buf, &size);
7292     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7293     ok(!lstrcmpA(buf, "grape"), "Expected \"grape\", got \"%s\"\n", buf);
7294     ok(size == 5, "Expected 5, got %lu\n", size);
7295 
7296     MsiCloseHandle(hpkg);
7297 
7298     /* reset the package */
7299     r = MsiOpenPackageA(package, &hpkg);
7300     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7301 
7302     /* property is not set anymore */
7303     size = MAX_PATH;
7304     lstrcpyA(buf, "kiwi");
7305     r = MsiGetPropertyA(hpkg, "MYPROP", buf, &size);
7306     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7307     todo_wine
7308     {
7309         ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf);
7310         ok(size == 0, "Expected 0, got %lu\n", size);
7311     }
7312 
7313     MsiCloseHandle(hpkg);
7314 
7315 error:
7316     MsiCloseHandle(hdb);
7317     DeleteFileA(msifile);
7318 }
7319 
7320 static void test_droptable(void)
7321 {
7322     MSIHANDLE hdb, hview, hrec;
7323     LPCSTR query;
7324     UINT r;
7325 
7326     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
7327     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7328 
7329     query = "CREATE TABLE `One` ( `A` INT PRIMARY KEY `A` )";
7330     r = run_query(hdb, 0, query);
7331     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7332 
7333     query = "SELECT * FROM `One`";
7334     r = do_query(hdb, query, &hrec);
7335     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7336 
7337     query = "SELECT `Name` FROM `_Tables` WHERE `Name` = 'One'";
7338     r = MsiDatabaseOpenViewA(hdb, query, &hview);
7339     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7340     r = MsiViewExecute(hview, 0);
7341     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7342 
7343     r = MsiViewFetch(hview, &hrec);
7344     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7345     check_record(hrec, 1, "One");
7346     MsiCloseHandle(hrec);
7347 
7348     MsiViewClose(hview);
7349     MsiCloseHandle(hview);
7350 
7351     query = "SELECT `Table`, `Number`, `Name` FROM `_Columns` WHERE `Table` = 'One'";
7352     r = MsiDatabaseOpenViewA(hdb, query, &hview);
7353     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7354     r = MsiViewExecute(hview, 0);
7355     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7356 
7357     r = MsiViewFetch(hview, &hrec);
7358     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7359     check_record(hrec, 3, "One", "1", "A");
7360     MsiCloseHandle(hrec);
7361 
7362     r = MsiViewFetch(hview, &hrec);
7363     ok(r == ERROR_NO_MORE_ITEMS,
7364        "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7365 
7366     MsiViewClose(hview);
7367     MsiCloseHandle(hview);
7368 
7369     query = "DROP `One`";
7370     r = run_query(hdb, 0, query);
7371     ok(r == ERROR_BAD_QUERY_SYNTAX,
7372        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7373 
7374     query = "DROP TABLE";
7375     r = run_query(hdb, 0, query);
7376     ok(r == ERROR_BAD_QUERY_SYNTAX,
7377        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7378 
7379     query = "DROP TABLE `One`";
7380     hview = 0;
7381     r = MsiDatabaseOpenViewA(hdb, query, &hview);
7382     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7383     r = MsiViewExecute(hview, 0);
7384     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7385 
7386     r = MsiViewFetch(hview, &hrec);
7387     ok(r == ERROR_FUNCTION_FAILED,
7388        "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
7389 
7390     MsiViewClose(hview);
7391     MsiCloseHandle(hview);
7392 
7393     query = "SELECT * FROM `IDontExist`";
7394     r = do_query(hdb, query, &hrec);
7395     ok(r == ERROR_BAD_QUERY_SYNTAX,
7396        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7397 
7398     query = "SELECT * FROM `One`";
7399     r = do_query(hdb, query, &hrec);
7400     ok(r == ERROR_BAD_QUERY_SYNTAX,
7401        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7402 
7403     query = "CREATE TABLE `One` ( `A` INT PRIMARY KEY `A` )";
7404     r = run_query(hdb, 0, query);
7405     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, 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 = "SELECT * FROM `One`";
7412     r = do_query(hdb, query, &hrec);
7413     ok(r == ERROR_BAD_QUERY_SYNTAX,
7414        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7415 
7416     query = "SELECT * FROM `_Tables` WHERE `Name` = 'One'";
7417     r = do_query(hdb, query, &hrec);
7418     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7419 
7420     query = "SELECT * FROM `_Columns` WHERE `Table` = 'One'";
7421     r = do_query(hdb, query, &hrec);
7422     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7423 
7424     query = "CREATE TABLE `One` ( `B` INT, `C` INT PRIMARY KEY `B` )";
7425     r = run_query(hdb, 0, query);
7426     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7427 
7428     query = "SELECT * FROM `One`";
7429     r = do_query(hdb, query, &hrec);
7430     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7431 
7432     query = "SELECT `Name` FROM `_Tables` WHERE `Name` = 'One'";
7433     r = MsiDatabaseOpenViewA(hdb, query, &hview);
7434     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7435     r = MsiViewExecute(hview, 0);
7436     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7437 
7438     r = MsiViewFetch(hview, &hrec);
7439     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7440     check_record(hrec, 1, "One");
7441     MsiCloseHandle(hrec);
7442 
7443     MsiViewClose(hview);
7444     MsiCloseHandle(hview);
7445 
7446     query = "SELECT `Table`, `Number`, `Name` FROM `_Columns` WHERE `Table` = 'One'";
7447     r = MsiDatabaseOpenViewA(hdb, query, &hview);
7448     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7449     r = MsiViewExecute(hview, 0);
7450     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7451 
7452     r = MsiViewFetch(hview, &hrec);
7453     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7454     check_record(hrec, 3, "One", "1", "B");
7455     MsiCloseHandle(hrec);
7456 
7457     r = MsiViewFetch(hview, &hrec);
7458     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7459     check_record(hrec, 3, "One", "2", "C");
7460     MsiCloseHandle(hrec);
7461 
7462     r = MsiViewFetch(hview, &hrec);
7463     ok(r == ERROR_NO_MORE_ITEMS,
7464        "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7465 
7466     MsiViewClose(hview);
7467     MsiCloseHandle(hview);
7468 
7469     query = "DROP TABLE One";
7470     r = run_query(hdb, 0, query);
7471     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7472 
7473     query = "SELECT * FROM `One`";
7474     r = do_query(hdb, query, &hrec);
7475     ok(r == ERROR_BAD_QUERY_SYNTAX,
7476        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7477 
7478     query = "SELECT * FROM `_Tables` WHERE `Name` = 'One'";
7479     r = do_query(hdb, query, &hrec);
7480     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7481 
7482     query = "SELECT * FROM `_Columns` WHERE `Table` = 'One'";
7483     r = do_query(hdb, query, &hrec);
7484     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7485 
7486     MsiCloseHandle(hdb);
7487     DeleteFileA(msifile);
7488 }
7489 
7490 static void test_dbmerge(void)
7491 {
7492     MSIHANDLE hdb, href, hview, hrec;
7493     CHAR buf[MAX_PATH];
7494     LPCSTR query;
7495     DWORD size;
7496     UINT r;
7497 
7498     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
7499     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7500 
7501     r = MsiOpenDatabaseW(L"refdb.msi", MSIDBOPEN_CREATE, &href);
7502     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7503 
7504     /* hDatabase is invalid */
7505     r = MsiDatabaseMergeA(0, href, "MergeErrors");
7506     ok(r == ERROR_INVALID_HANDLE,
7507        "Expected ERROR_INVALID_HANDLE, got %d\n", r);
7508 
7509     /* hDatabaseMerge is invalid */
7510     r = MsiDatabaseMergeA(hdb, 0, "MergeErrors");
7511     ok(r == ERROR_INVALID_HANDLE,
7512        "Expected ERROR_INVALID_HANDLE, got %d\n", r);
7513 
7514     /* szTableName is NULL */
7515     r = MsiDatabaseMergeA(hdb, href, NULL);
7516     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7517 
7518     /* szTableName is empty */
7519     r = MsiDatabaseMergeA(hdb, href, "");
7520     ok(r == ERROR_INVALID_TABLE, "Expected ERROR_INVALID_TABLE, got %d\n", r);
7521 
7522     /* both DBs empty, szTableName is valid */
7523     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7524     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7525 
7526     query = "CREATE TABLE `One` ( `A` INT PRIMARY KEY `A` )";
7527     r = run_query(hdb, 0, query);
7528     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7529 
7530     query = "CREATE TABLE `One` ( `A` CHAR(72) PRIMARY KEY `A` )";
7531     r = run_query(href, 0, query);
7532     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7533 
7534     /* column types don't match */
7535     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7536     ok(r == ERROR_DATATYPE_MISMATCH,
7537        "Expected ERROR_DATATYPE_MISMATCH, got %d\n", r);
7538 
7539     /* nothing in MergeErrors */
7540     query = "SELECT * FROM `MergeErrors`";
7541     r = do_query(hdb, query, &hrec);
7542     ok(r == ERROR_BAD_QUERY_SYNTAX,
7543        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7544 
7545     query = "DROP TABLE `One`";
7546     r = run_query(hdb, 0, query);
7547     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7548 
7549     query = "DROP TABLE `One`";
7550     r = run_query(href, 0, query);
7551     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7552 
7553     query = "CREATE TABLE `One` ( "
7554         "`A` CHAR(72), "
7555         "`B` CHAR(56), "
7556         "`C` CHAR(64) LOCALIZABLE, "
7557         "`D` LONGCHAR, "
7558         "`E` CHAR(72) NOT NULL, "
7559         "`F` CHAR(56) NOT NULL, "
7560         "`G` CHAR(64) NOT NULL LOCALIZABLE, "
7561         "`H` LONGCHAR NOT NULL "
7562         "PRIMARY KEY `A` )";
7563     r = run_query(hdb, 0, query);
7564     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7565 
7566     query = "CREATE TABLE `One` ( "
7567         "`A` CHAR(64), "
7568         "`B` CHAR(64), "
7569         "`C` CHAR(64), "
7570         "`D` CHAR(64), "
7571         "`E` CHAR(64) NOT NULL, "
7572         "`F` CHAR(64) NOT NULL, "
7573         "`G` CHAR(64) NOT NULL, "
7574         "`H` CHAR(64) NOT NULL "
7575         "PRIMARY KEY `A` )";
7576     r = run_query(href, 0, query);
7577     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7578 
7579     /* column string types don't match exactly */
7580     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7581     ok(r == ERROR_SUCCESS,
7582        "Expected ERROR_SUCCESS, got %d\n", r);
7583 
7584     /* nothing in MergeErrors */
7585     query = "SELECT * FROM `MergeErrors`";
7586     r = do_query(hdb, query, &hrec);
7587     ok(r == ERROR_BAD_QUERY_SYNTAX,
7588        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7589 
7590     query = "DROP TABLE `One`";
7591     r = run_query(hdb, 0, query);
7592     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7593 
7594     query = "DROP TABLE `One`";
7595     r = run_query(href, 0, query);
7596     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7597 
7598     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A` )";
7599     r = run_query(hdb, 0, query);
7600     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7601 
7602     query = "CREATE TABLE `One` ( `A` INT, `C` INT PRIMARY KEY `A` )";
7603     r = run_query(href, 0, query);
7604     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7605 
7606     /* column names don't match */
7607     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7608     ok(r == ERROR_DATATYPE_MISMATCH,
7609        "Expected ERROR_DATATYPE_MISMATCH, got %d\n", r);
7610 
7611     /* nothing in MergeErrors */
7612     query = "SELECT * FROM `MergeErrors`";
7613     r = do_query(hdb, query, &hrec);
7614     ok(r == ERROR_BAD_QUERY_SYNTAX,
7615        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7616 
7617     query = "DROP TABLE `One`";
7618     r = run_query(hdb, 0, query);
7619     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7620 
7621     query = "DROP TABLE `One`";
7622     r = run_query(href, 0, query);
7623     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7624 
7625     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A` )";
7626     r = run_query(hdb, 0, query);
7627     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7628 
7629     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `B` )";
7630     r = run_query(href, 0, query);
7631     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7632 
7633     /* primary keys don't match */
7634     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7635     ok(r == ERROR_DATATYPE_MISMATCH,
7636        "Expected ERROR_DATATYPE_MISMATCH, got %d\n", r);
7637 
7638     /* nothing in MergeErrors */
7639     query = "SELECT * FROM `MergeErrors`";
7640     r = do_query(hdb, query, &hrec);
7641     ok(r == ERROR_BAD_QUERY_SYNTAX,
7642        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7643 
7644     query = "DROP TABLE `One`";
7645     r = run_query(hdb, 0, query);
7646     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7647 
7648     query = "DROP TABLE `One`";
7649     r = run_query(href, 0, query);
7650     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7651 
7652     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A` )";
7653     r = run_query(hdb, 0, query);
7654     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7655 
7656     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A`, `B` )";
7657     r = run_query(href, 0, query);
7658     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7659 
7660     /* number of primary keys doesn't match */
7661     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7662     ok(r == ERROR_DATATYPE_MISMATCH,
7663        "Expected ERROR_DATATYPE_MISMATCH, got %d\n", r);
7664 
7665     /* nothing in MergeErrors */
7666     query = "SELECT * FROM `MergeErrors`";
7667     r = do_query(hdb, query, &hrec);
7668     ok(r == ERROR_BAD_QUERY_SYNTAX,
7669        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7670 
7671     query = "DROP TABLE `One`";
7672     r = run_query(hdb, 0, query);
7673     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7674 
7675     query = "DROP TABLE `One`";
7676     r = run_query(href, 0, query);
7677     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7678 
7679     query = "CREATE TABLE `One` ( `A` INT, `B` INT, `C` INT PRIMARY KEY `A` )";
7680     r = run_query(hdb, 0, query);
7681     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7682 
7683     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A` )";
7684     r = run_query(href, 0, query);
7685     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7686 
7687     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 1, 2 )";
7688     r = run_query(href, 0, query);
7689     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7690 
7691     /* number of columns doesn't match */
7692     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7693     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7694 
7695     query = "SELECT * FROM `One`";
7696     r = do_query(hdb, query, &hrec);
7697     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7698 
7699     r = MsiRecordGetInteger(hrec, 1);
7700     ok(r == 1, "Expected 1, got %d\n", r);
7701 
7702     r = MsiRecordGetInteger(hrec, 2);
7703     ok(r == 2, "Expected 2, got %d\n", r);
7704 
7705     r = MsiRecordGetInteger(hrec, 3);
7706     ok(r == MSI_NULL_INTEGER, "Expected MSI_NULL_INTEGER, got %d\n", r);
7707 
7708     MsiCloseHandle(hrec);
7709 
7710     /* nothing in MergeErrors */
7711     query = "SELECT * FROM `MergeErrors`";
7712     r = do_query(hdb, query, &hrec);
7713     ok(r == ERROR_BAD_QUERY_SYNTAX,
7714        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7715 
7716     query = "DROP TABLE `One`";
7717     r = run_query(hdb, 0, query);
7718     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7719 
7720     query = "DROP TABLE `One`";
7721     r = run_query(href, 0, query);
7722     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7723 
7724     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A` )";
7725     r = run_query(hdb, 0, query);
7726     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7727 
7728     query = "CREATE TABLE `One` ( `A` INT, `B` INT, `C` INT PRIMARY KEY `A` )";
7729     r = run_query(href, 0, query);
7730     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7731 
7732     query = "INSERT INTO `One` ( `A`, `B`, `C` ) VALUES ( 1, 2, 3 )";
7733     r = run_query(href, 0, query);
7734     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7735 
7736     /* number of columns doesn't match */
7737     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7738     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7739 
7740     query = "SELECT * FROM `One`";
7741     r = do_query(hdb, query, &hrec);
7742     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7743 
7744     r = MsiRecordGetInteger(hrec, 1);
7745     ok(r == 1, "Expected 1, got %d\n", r);
7746 
7747     r = MsiRecordGetInteger(hrec, 2);
7748     ok(r == 2, "Expected 2, got %d\n", r);
7749 
7750     r = MsiRecordGetInteger(hrec, 3);
7751     ok(r == MSI_NULL_INTEGER, "Expected MSI_NULL_INTEGER, got %d\n", r);
7752 
7753     MsiCloseHandle(hrec);
7754 
7755     /* nothing in MergeErrors */
7756     query = "SELECT * FROM `MergeErrors`";
7757     r = do_query(hdb, query, &hrec);
7758     ok(r == ERROR_BAD_QUERY_SYNTAX,
7759        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
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` ( `A` INT, `B` INT PRIMARY KEY `A` )";
7770     r = run_query(hdb, 0, query);
7771     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7772 
7773     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 1, 1 )";
7774     r = run_query(hdb, 0, query);
7775     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7776 
7777     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 2, 2 )";
7778     r = run_query(hdb, 0, query);
7779     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7780 
7781     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A` )";
7782     r = run_query(href, 0, query);
7783     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7784 
7785     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 1, 2 )";
7786     r = run_query(href, 0, query);
7787     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7788 
7789     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 2, 3 )";
7790     r = run_query(href, 0, query);
7791     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7792 
7793     /* primary keys match, rows do not */
7794     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7795     ok(r == ERROR_FUNCTION_FAILED,
7796        "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
7797 
7798     /* nothing in MergeErrors */
7799     query = "SELECT * FROM `MergeErrors`";
7800     r = do_query(hdb, query, &hrec);
7801     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7802     check_record(hrec, 2, "One", "2");
7803     MsiCloseHandle(hrec);
7804 
7805     r = MsiDatabaseOpenViewA(hdb, "SELECT * FROM `MergeErrors`", &hview);
7806     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7807 
7808     r = MsiViewGetColumnInfo(hview, MSICOLINFO_NAMES, &hrec);
7809     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7810     check_record(hrec, 2, "Table", "NumRowMergeConflicts");
7811     MsiCloseHandle(hrec);
7812 
7813     r = MsiViewGetColumnInfo(hview, MSICOLINFO_TYPES, &hrec);
7814     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7815     check_record(hrec, 2, "s255", "i2");
7816     MsiCloseHandle(hrec);
7817 
7818     MsiViewClose(hview);
7819     MsiCloseHandle(hview);
7820 
7821     query = "DROP TABLE `MergeErrors`";
7822     r = run_query(hdb, 0, query);
7823     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7824 
7825     query = "DROP TABLE `One`";
7826     r = run_query(hdb, 0, query);
7827     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7828 
7829     query = "DROP TABLE `One`";
7830     r = run_query(href, 0, query);
7831     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7832 
7833     query = "CREATE TABLE `One` ( `A` INT, `B` CHAR(72) PRIMARY KEY `A` )";
7834     r = run_query(href, 0, query);
7835     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7836 
7837     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 1, 'hi' )";
7838     r = run_query(href, 0, query);
7839     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7840 
7841     /* table from merged database is not in target database */
7842     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7843     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7844 
7845     query = "SELECT * FROM `One`";
7846     r = do_query(hdb, query, &hrec);
7847     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7848     check_record(hrec, 2, "1", "hi");
7849     MsiCloseHandle(hrec);
7850 
7851     /* nothing in MergeErrors */
7852     query = "SELECT * FROM `MergeErrors`";
7853     r = do_query(hdb, query, &hrec);
7854     ok(r == ERROR_BAD_QUERY_SYNTAX,
7855        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7856 
7857     query = "DROP TABLE `One`";
7858     r = run_query(hdb, 0, query);
7859     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7860 
7861     query = "DROP TABLE `One`";
7862     r = run_query(href, 0, query);
7863     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7864 
7865     query = "CREATE TABLE `One` ( "
7866             "`A` CHAR(72), `B` INT PRIMARY KEY `A` )";
7867     r = run_query(hdb, 0, query);
7868     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7869 
7870     query = "CREATE TABLE `One` ( "
7871             "`A` CHAR(72), `B` INT PRIMARY KEY `A` )";
7872     r = run_query(href, 0, query);
7873     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7874 
7875     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 'hi', 1 )";
7876     r = run_query(href, 0, query);
7877     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7878 
7879     /* primary key is string */
7880     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7881     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7882 
7883     query = "SELECT * FROM `One`";
7884     r = do_query(hdb, query, &hrec);
7885     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7886     check_record(hrec, 2, "hi", "1");
7887     MsiCloseHandle(hrec);
7888 
7889     /* nothing in MergeErrors */
7890     query = "SELECT * FROM `MergeErrors`";
7891     r = do_query(hdb, query, &hrec);
7892     ok(r == ERROR_BAD_QUERY_SYNTAX,
7893        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7894 
7895     create_file_data("codepage.idt", "\r\n\r\n850\t_ForceCodepage\r\n", 0);
7896 
7897     GetCurrentDirectoryA(MAX_PATH, buf);
7898     r = MsiDatabaseImportA(hdb, buf, "codepage.idt");
7899     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7900 
7901     query = "DROP TABLE `One`";
7902     r = run_query(hdb, 0, query);
7903     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7904 
7905     query = "DROP TABLE `One`";
7906     r = run_query(href, 0, query);
7907     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7908 
7909     query = "CREATE TABLE `One` ( "
7910             "`A` INT, `B` CHAR(72) LOCALIZABLE PRIMARY KEY `A` )";
7911     r = run_query(hdb, 0, query);
7912     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7913 
7914     query = "CREATE TABLE `One` ( "
7915             "`A` INT, `B` CHAR(72) LOCALIZABLE PRIMARY KEY `A` )";
7916     r = run_query(href, 0, query);
7917     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7918 
7919     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 1, 'hi' )";
7920     r = run_query(href, 0, query);
7921     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7922 
7923     /* code page does not match */
7924     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7925     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7926 
7927     query = "SELECT * FROM `One`";
7928     r = do_query(hdb, query, &hrec);
7929     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7930     check_record(hrec, 2, "1", "hi");
7931     MsiCloseHandle(hrec);
7932 
7933     /* nothing in MergeErrors */
7934     query = "SELECT * FROM `MergeErrors`";
7935     r = do_query(hdb, query, &hrec);
7936     ok(r == ERROR_BAD_QUERY_SYNTAX,
7937        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7938 
7939     query = "DROP TABLE `One`";
7940     r = run_query(hdb, 0, query);
7941     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7942 
7943     query = "DROP TABLE `One`";
7944     r = run_query(href, 0, query);
7945     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7946 
7947     query = "CREATE TABLE `One` ( `A` INT, `B` OBJECT PRIMARY KEY `A` )";
7948     r = run_query(hdb, 0, query);
7949     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7950 
7951     query = "CREATE TABLE `One` ( `A` INT, `B` OBJECT PRIMARY KEY `A` )";
7952     r = run_query(href, 0, query);
7953     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7954 
7955     create_file("binary.dat", 0);
7956     hrec = MsiCreateRecord(1);
7957     MsiRecordSetStreamA(hrec, 1, "binary.dat");
7958 
7959     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 1, ? )";
7960     r = run_query(href, hrec, query);
7961     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7962 
7963     MsiCloseHandle(hrec);
7964 
7965     /* binary data to merge */
7966     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7967     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7968 
7969     query = "SELECT * FROM `One`";
7970     r = do_query(hdb, query, &hrec);
7971     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7972 
7973     r = MsiRecordGetInteger(hrec, 1);
7974     ok(r == 1, "Expected 1, got %d\n", r);
7975 
7976     size = MAX_PATH;
7977     ZeroMemory(buf, MAX_PATH);
7978     r = MsiRecordReadStream(hrec, 2, buf, &size);
7979     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7980     ok(!lstrcmpA(buf, "binary.dat"), "Expected \"binary.dat\", got \"%s\"\n", buf);
7981 
7982     MsiCloseHandle(hrec);
7983 
7984     /* nothing in MergeErrors */
7985     query = "SELECT * FROM `MergeErrors`";
7986     r = do_query(hdb, query, &hrec);
7987     ok(r == ERROR_BAD_QUERY_SYNTAX,
7988        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7989 
7990     query = "DROP TABLE `One`";
7991     r = run_query(hdb, 0, query);
7992     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7993 
7994     query = "DROP TABLE `One`";
7995     r = run_query(href, 0, query);
7996     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7997 
7998     query = "CREATE TABLE `One` ( `A` INT, `B` CHAR(72) PRIMARY KEY `A` )";
7999     r = run_query(hdb, 0, query);
8000     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8001     r = run_query(href, 0, query);
8002     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8003 
8004     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 1, 'foo' )";
8005     r = run_query(href, 0, query);
8006     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8007 
8008     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 2, 'bar' )";
8009     r = run_query(href, 0, query);
8010     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8011 
8012     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
8013     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8014 
8015     query = "SELECT * FROM `One`";
8016     r = MsiDatabaseOpenViewA(hdb, query, &hview);
8017     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8018     r = MsiViewExecute(hview, 0);
8019     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8020 
8021     r = MsiViewFetch(hview, &hrec);
8022     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8023     check_record(hrec, 2, "1", "foo");
8024     MsiCloseHandle(hrec);
8025 
8026     r = MsiViewFetch(hview, &hrec);
8027     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8028     check_record(hrec, 2, "2", "bar");
8029     MsiCloseHandle(hrec);
8030 
8031     r = MsiViewFetch(hview, &hrec);
8032     ok(r == ERROR_NO_MORE_ITEMS,
8033        "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
8034 
8035     MsiViewClose(hview);
8036     MsiCloseHandle(hview);
8037 
8038     MsiCloseHandle(hdb);
8039     MsiCloseHandle(href);
8040     DeleteFileA(msifile);
8041     DeleteFileW(L"refdb.msi");
8042     DeleteFileA("codepage.idt");
8043     DeleteFileA("binary.dat");
8044 }
8045 
8046 static void test_select_with_tablenames(void)
8047 {
8048     MSIHANDLE hdb, view, rec;
8049     LPCSTR query;
8050     UINT r;
8051     int i;
8052 
8053     int vals[4][2] = {
8054         {1,12},
8055         {4,12},
8056         {1,15},
8057         {4,15}};
8058 
8059     hdb = create_db();
8060     ok(hdb, "failed to create db\n");
8061 
8062     /* Build a pair of tables with the same column names, but unique data */
8063     query = "CREATE TABLE `T1` ( `A` SHORT, `B` SHORT PRIMARY KEY `A`)";
8064     r = run_query(hdb, 0, query);
8065     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8066 
8067     query = "INSERT INTO `T1` ( `A`, `B` ) VALUES ( 1, 2 )";
8068     r = run_query(hdb, 0, query);
8069     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8070 
8071     query = "INSERT INTO `T1` ( `A`, `B` ) VALUES ( 4, 5 )";
8072     r = run_query(hdb, 0, query);
8073     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8074 
8075     query = "CREATE TABLE `T2` ( `A` SHORT, `B` SHORT PRIMARY KEY `A`)";
8076     r = run_query(hdb, 0, query);
8077     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8078 
8079     query = "INSERT INTO `T2` ( `A`, `B` ) VALUES ( 11, 12 )";
8080     r = run_query(hdb, 0, query);
8081     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8082 
8083     query = "INSERT INTO `T2` ( `A`, `B` ) VALUES ( 14, 15 )";
8084     r = run_query(hdb, 0, query);
8085     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8086 
8087 
8088     /* Test that selection based on prefixing the column with the table
8089      * actually selects the right data */
8090 
8091     query = "SELECT T1.A, T2.B FROM T1,T2";
8092     r = MsiDatabaseOpenViewA(hdb, query, &view);
8093     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8094     r = MsiViewExecute(view, 0);
8095     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8096 
8097     for (i = 0; i < 4; i++)
8098     {
8099         r = MsiViewFetch(view, &rec);
8100         ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8101 
8102         r = MsiRecordGetInteger(rec, 1);
8103         ok(r == vals[i][0], "Expected %d, got %d\n", vals[i][0], r);
8104 
8105         r = MsiRecordGetInteger(rec, 2);
8106         ok(r == vals[i][1], "Expected %d, got %d\n", vals[i][1], r);
8107 
8108         MsiCloseHandle(rec);
8109     }
8110 
8111     r = MsiViewFetch(view, &rec);
8112     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
8113 
8114     MsiViewClose(view);
8115     MsiCloseHandle(view);
8116     MsiCloseHandle(hdb);
8117     DeleteFileA(msifile);
8118 }
8119 
8120 static const UINT ordervals[6][3] =
8121 {
8122     { MSI_NULL_INTEGER, 12, 13 },
8123     { 1, 2, 3 },
8124     { 6, 4, 5 },
8125     { 8, 9, 7 },
8126     { 10, 11, MSI_NULL_INTEGER },
8127     { 14, MSI_NULL_INTEGER, 15 }
8128 };
8129 
8130 static void test_insertorder(void)
8131 {
8132     MSIHANDLE hdb, view, rec;
8133     LPCSTR query;
8134     UINT r;
8135     int i;
8136 
8137     hdb = create_db();
8138     ok(hdb, "failed to create db\n");
8139 
8140     query = "CREATE TABLE `T` ( `A` SHORT, `B` SHORT, `C` SHORT PRIMARY KEY `A`)";
8141     r = run_query(hdb, 0, query);
8142     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8143 
8144     query = "INSERT INTO `T` ( `A`, `B`, `C` ) VALUES ( 1, 2, 3 )";
8145     r = run_query(hdb, 0, query);
8146     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8147 
8148     query = "INSERT INTO `T` ( `B`, `C`, `A` ) VALUES ( 4, 5, 6 )";
8149     r = run_query(hdb, 0, query);
8150     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8151 
8152     query = "INSERT INTO `T` ( `C`, `A`, `B` ) VALUES ( 7, 8, 9 )";
8153     r = run_query(hdb, 0, query);
8154     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8155 
8156     query = "INSERT INTO `T` ( `A`, `B` ) VALUES ( 10, 11 )";
8157     r = run_query(hdb, 0, query);
8158     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8159 
8160     query = "INSERT INTO `T` ( `B`, `C` ) VALUES ( 12, 13 )";
8161     r = run_query(hdb, 0, query);
8162     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8163 
8164     /* fails because the primary key already
8165      * has an MSI_NULL_INTEGER value set above
8166      */
8167     query = "INSERT INTO `T` ( `C` ) VALUES ( 14 )";
8168     r = run_query(hdb, 0, query);
8169     ok(r == ERROR_FUNCTION_FAILED,
8170        "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
8171 
8172     /* replicate the error where primary key is set twice */
8173     query = "INSERT INTO `T` ( `A`, `C` ) VALUES ( 1, 14 )";
8174     r = run_query(hdb, 0, query);
8175     ok(r == ERROR_FUNCTION_FAILED,
8176        "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
8177 
8178     query = "INSERT INTO `T` ( `A`, `C` ) VALUES ( 14, 15 )";
8179     r = run_query(hdb, 0, query);
8180     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8181 
8182     query = "INSERT INTO `T` VALUES ( 16 )";
8183     r = run_query(hdb, 0, query);
8184     ok(r == ERROR_BAD_QUERY_SYNTAX,
8185        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
8186 
8187     query = "INSERT INTO `T` VALUES ( 17, 18 )";
8188     r = run_query(hdb, 0, query);
8189     ok(r == ERROR_BAD_QUERY_SYNTAX,
8190        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
8191 
8192     query = "INSERT INTO `T` VALUES ( 19, 20, 21 )";
8193     r = run_query(hdb, 0, query);
8194     ok(r == ERROR_BAD_QUERY_SYNTAX,
8195        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
8196 
8197     query = "SELECT * FROM `T`";
8198     r = MsiDatabaseOpenViewA(hdb, query, &view);
8199     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8200     r = MsiViewExecute(view, 0);
8201     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8202 
8203     for (i = 0; i < 6; i++)
8204     {
8205         r = MsiViewFetch(view, &rec);
8206         ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8207 
8208         r = MsiRecordGetInteger(rec, 1);
8209         ok(r == ordervals[i][0], "Expected %d, got %d\n", ordervals[i][0], r);
8210 
8211         r = MsiRecordGetInteger(rec, 2);
8212         ok(r == ordervals[i][1], "Expected %d, got %d\n", ordervals[i][1], r);
8213 
8214         r = MsiRecordGetInteger(rec, 3);
8215         ok(r == ordervals[i][2], "Expected %d, got %d\n", ordervals[i][2], r);
8216 
8217         MsiCloseHandle(rec);
8218     }
8219 
8220     r = MsiViewFetch(view, &rec);
8221     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
8222 
8223     MsiViewClose(view);
8224     MsiCloseHandle(view);
8225 
8226     query = "DELETE FROM `T` WHERE `A` IS NULL";
8227     r = run_query(hdb, 0, query);
8228     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8229 
8230     query = "INSERT INTO `T` ( `B`, `C` ) VALUES ( 12, 13 ) TEMPORARY";
8231     r = run_query(hdb, 0, query);
8232     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8233 
8234     query = "SELECT * FROM `T`";
8235     r = MsiDatabaseOpenViewA(hdb, query, &view);
8236     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8237     r = MsiViewExecute(view, 0);
8238     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8239 
8240     for (i = 0; i < 6; i++)
8241     {
8242         r = MsiViewFetch(view, &rec);
8243         ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8244 
8245         r = MsiRecordGetInteger(rec, 1);
8246         ok(r == ordervals[i][0], "Expected %d, got %d\n", ordervals[i][0], r);
8247 
8248         r = MsiRecordGetInteger(rec, 2);
8249         ok(r == ordervals[i][1], "Expected %d, got %d\n", ordervals[i][1], r);
8250 
8251         r = MsiRecordGetInteger(rec, 3);
8252         ok(r == ordervals[i][2], "Expected %d, got %d\n", ordervals[i][2], r);
8253 
8254         MsiCloseHandle(rec);
8255     }
8256 
8257     r = MsiViewFetch(view, &rec);
8258     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
8259 
8260     MsiViewClose(view);
8261     MsiCloseHandle(view);
8262     MsiCloseHandle(hdb);
8263     DeleteFileA(msifile);
8264 }
8265 
8266 static void test_columnorder(void)
8267 {
8268     MSIHANDLE hdb, view, rec;
8269     LPCSTR query;
8270     UINT r;
8271 
8272     hdb = create_db();
8273     ok(hdb, "failed to create db\n");
8274 
8275     /* Each column is a slot:
8276      * ---------------------
8277      * | B | C | A | E | D |
8278      * ---------------------
8279      *
8280      * When a column is selected as a primary key,
8281      * the column occupying the nth primary key slot is swapped
8282      * with the current position of the primary key in question:
8283      *
8284      * set primary key `D`
8285      * ---------------------    ---------------------
8286      * | B | C | A | E | D | -> | D | C | A | E | B |
8287      * ---------------------    ---------------------
8288      *
8289      * set primary key `E`
8290      * ---------------------    ---------------------
8291      * | D | C | A | E | B | -> | D | E | A | C | B |
8292      * ---------------------    ---------------------
8293      */
8294 
8295     query = "CREATE TABLE `T` ( `B` SHORT NOT NULL, `C` SHORT NOT NULL, "
8296             "`A` CHAR(255), `E` INT, `D` CHAR(255) NOT NULL "
8297             "PRIMARY KEY `D`, `E`)";
8298     r = run_query(hdb, 0, query);
8299     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8300 
8301     query = "SELECT * FROM `T`";
8302     r = MsiDatabaseOpenViewA(hdb, query, &view);
8303     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8304 
8305     r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
8306     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8307     check_record(rec, 5, "s255", "I2", "S255", "i2", "i2");
8308     MsiCloseHandle(rec);
8309 
8310     r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec);
8311     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8312     check_record(rec, 5, "D", "E", "A", "C", "B");
8313     MsiCloseHandle(rec);
8314 
8315     MsiViewClose(view);
8316     MsiCloseHandle(view);
8317 
8318     query = "INSERT INTO `T` ( `B`, `C`, `A`, `E`, `D` ) "
8319             "VALUES ( 1, 2, 'a', 3, 'bc' )";
8320     r = run_query(hdb, 0, query);
8321     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8322 
8323     query = "SELECT * FROM `T`";
8324     r = do_query(hdb, query, &rec);
8325     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8326     check_record(rec, 5, "bc", "3", "a", "2", "1");
8327     MsiCloseHandle(rec);
8328 
8329     query = "SELECT `Table`, `Number`, `Name` FROM `_Columns` WHERE `Table` = 'T'";
8330     r = MsiDatabaseOpenViewA(hdb, query, &view);
8331     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8332     r = MsiViewExecute(view, 0);
8333     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8334 
8335     r = MsiViewFetch(view, &rec);
8336     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8337     check_record(rec, 3, "T", "1", "D");
8338     MsiCloseHandle(rec);
8339 
8340     r = MsiViewFetch(view, &rec);
8341     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8342     check_record(rec, 3, "T", "2", "E");
8343     MsiCloseHandle(rec);
8344 
8345     r = MsiViewFetch(view, &rec);
8346     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8347     check_record(rec, 3, "T", "3", "A");
8348     MsiCloseHandle(rec);
8349 
8350     r = MsiViewFetch(view, &rec);
8351     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8352     check_record(rec, 3, "T", "4", "C");
8353     MsiCloseHandle(rec);
8354 
8355     r = MsiViewFetch(view, &rec);
8356     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8357     check_record(rec, 3, "T", "5", "B");
8358     MsiCloseHandle(rec);
8359 
8360     r = MsiViewFetch(view, &rec);
8361     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
8362 
8363     MsiViewClose(view);
8364     MsiCloseHandle(view);
8365 
8366     query = "CREATE TABLE `Z` ( `B` SHORT NOT NULL, `C` SHORT NOT NULL, "
8367             "`A` CHAR(255), `E` INT, `D` CHAR(255) NOT NULL "
8368             "PRIMARY KEY `C`, `A`, `D`)";
8369     r = run_query(hdb, 0, query);
8370     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8371 
8372     query = "SELECT * FROM `Z`";
8373     r = MsiDatabaseOpenViewA(hdb, query, &view);
8374     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8375 
8376     r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
8377     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8378     check_record(rec, 5, "i2", "S255", "s255", "I2", "i2");
8379     MsiCloseHandle(rec);
8380 
8381     r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec);
8382     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8383     check_record(rec, 5, "C", "A", "D", "E", "B");
8384     MsiCloseHandle(rec);
8385 
8386     MsiViewClose(view);
8387     MsiCloseHandle(view);
8388 
8389     query = "INSERT INTO `Z` ( `B`, `C`, `A`, `E`, `D` ) "
8390             "VALUES ( 1, 2, 'a', 3, 'bc' )";
8391     r = run_query(hdb, 0, query);
8392     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8393 
8394     query = "SELECT * FROM `Z`";
8395     r = do_query(hdb, query, &rec);
8396     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8397     check_record(rec, 5, "2", "a", "bc", "3", "1");
8398     MsiCloseHandle(rec);
8399 
8400     query = "SELECT `Table`, `Number`, `Name` FROM `_Columns` WHERE `Table` = 'T'";
8401     r = MsiDatabaseOpenViewA(hdb, query, &view);
8402     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8403     r = MsiViewExecute(view, 0);
8404     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8405 
8406     r = MsiViewFetch(view, &rec);
8407     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8408     check_record(rec, 3, "T", "1", "D");
8409     MsiCloseHandle(rec);
8410 
8411     r = MsiViewFetch(view, &rec);
8412     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8413     check_record(rec, 3, "T", "2", "E");
8414     MsiCloseHandle(rec);
8415 
8416     r = MsiViewFetch(view, &rec);
8417     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8418     check_record(rec, 3, "T", "3", "A");
8419     MsiCloseHandle(rec);
8420 
8421     r = MsiViewFetch(view, &rec);
8422     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8423     check_record(rec, 3, "T", "4", "C");
8424     MsiCloseHandle(rec);
8425 
8426     r = MsiViewFetch(view, &rec);
8427     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8428     check_record(rec, 3, "T", "5", "B");
8429     MsiCloseHandle(rec);
8430 
8431     r = MsiViewFetch(view, &rec);
8432     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
8433 
8434     MsiViewClose(view);
8435     MsiCloseHandle(view);
8436 
8437     MsiCloseHandle(hdb);
8438     DeleteFileA(msifile);
8439 }
8440 
8441 static void test_createtable(void)
8442 {
8443     MSIHANDLE hdb, htab = 0, hrec = 0;
8444     LPCSTR query;
8445     UINT res;
8446     DWORD size;
8447     char buffer[0x20];
8448 
8449     hdb = create_db();
8450     ok(hdb, "failed to create db\n");
8451 
8452     query = "CREATE TABLE `blah` (`foo` CHAR(72) NOT NULL PRIMARY KEY `foo`)";
8453     res = MsiDatabaseOpenViewA( hdb, query, &htab );
8454     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
8455     if(res == ERROR_SUCCESS )
8456     {
8457         res = MsiViewExecute( htab, hrec );
8458         ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
8459 
8460         res = MsiViewGetColumnInfo( htab, MSICOLINFO_NAMES, &hrec );
8461         todo_wine ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
8462 
8463         size = sizeof(buffer);
8464         res = MsiRecordGetStringA(hrec, 1, buffer, &size );
8465         todo_wine ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
8466         MsiCloseHandle( hrec );
8467 
8468         res = MsiViewClose( htab );
8469         ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
8470 
8471         res = MsiCloseHandle( htab );
8472         ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
8473     }
8474 
8475     query = "CREATE TABLE `a` (`b` INT PRIMARY KEY `b`)";
8476     res = MsiDatabaseOpenViewA( hdb, query, &htab );
8477     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
8478     if(res == ERROR_SUCCESS )
8479     {
8480         res = MsiViewExecute( htab, 0 );
8481         ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
8482 
8483         res = MsiViewClose( htab );
8484         ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
8485 
8486         res = MsiCloseHandle( htab );
8487         ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
8488 
8489         query = "SELECT * FROM `a`";
8490         res = MsiDatabaseOpenViewA( hdb, query, &htab );
8491         ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
8492 
8493         res = MsiViewGetColumnInfo( htab, MSICOLINFO_NAMES, &hrec );
8494         ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
8495         check_record(hrec, 1, "b");
8496         MsiCloseHandle( hrec );
8497 
8498         res = MsiViewClose( htab );
8499         ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
8500 
8501         res = MsiCloseHandle( htab );
8502         ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
8503 
8504         res = MsiDatabaseCommit(hdb);
8505         ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
8506 
8507         res = MsiCloseHandle(hdb);
8508         ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
8509 
8510         res = MsiOpenDatabaseW(msifileW, MSIDBOPEN_TRANSACT, &hdb );
8511         ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
8512 
8513         query = "SELECT * FROM `a`";
8514         res = MsiDatabaseOpenViewA( hdb, query, &htab );
8515         ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
8516 
8517         res = MsiViewGetColumnInfo( htab, MSICOLINFO_NAMES, &hrec );
8518         ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
8519         check_record(hrec, 1, "b");
8520         res = MsiCloseHandle( hrec );
8521         ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
8522 
8523         res = MsiViewClose( htab );
8524         ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
8525 
8526         res = MsiCloseHandle( htab );
8527         ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
8528     }
8529 
8530     res = MsiDatabaseCommit(hdb);
8531     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
8532 
8533     res = MsiCloseHandle(hdb);
8534     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
8535 
8536     DeleteFileA(msifile);
8537 }
8538 
8539 static void test_embedded_nulls(void)
8540 {
8541     static const char control_table[] =
8542         "Dialog\tText\n"
8543         "s72\tL0\n"
8544         "Control\tDialog\n"
8545         "LicenseAgreementDlg\ttext\x11\x19text\0text";
8546     static const char export_expected[] =
8547         "Dialog\tText\r\n"
8548         "s72\tL0\r\n"
8549         "Control\tDialog\r\n"
8550         "LicenseAgreementDlg\ttext\x11\x19text\x19text";
8551     /* newlines have alternate representation in idt files */
8552     static const char control_table2[] =
8553         "Dialog\tText\n"
8554         "s72\tL0\n"
8555         "Control\tDialog\n"
8556         "LicenseAgreementDlg\ttext\x11\x19te\nxt\0text";
8557     char data[1024];
8558     UINT r;
8559     DWORD sz;
8560     MSIHANDLE hdb, hrec;
8561     char buffer[32];
8562 
8563     r = MsiOpenDatabaseW( msifileW, MSIDBOPEN_CREATE, &hdb );
8564     ok( r == ERROR_SUCCESS, "failed to open database %u\n", r );
8565 
8566     GetCurrentDirectoryA( MAX_PATH, CURR_DIR );
8567     write_file( "temp_file", control_table, sizeof(control_table) );
8568     r = MsiDatabaseImportA( hdb, CURR_DIR, "temp_file" );
8569     ok( r == ERROR_SUCCESS, "failed to import table %u\n", r );
8570     DeleteFileA( "temp_file" );
8571 
8572     r = do_query( hdb, "SELECT `Text` FROM `Control` WHERE `Dialog` = 'LicenseAgreementDlg'", &hrec );
8573     ok( r == ERROR_SUCCESS, "query failed %u\n", r );
8574 
8575     buffer[0] = 0;
8576     sz = sizeof(buffer);
8577     r = MsiRecordGetStringA( hrec, 1, buffer, &sz );
8578     ok( r == ERROR_SUCCESS, "failed to get string %u\n", r );
8579     ok( !memcmp( "text\r\ntext\ntext", buffer, sizeof("text\r\ntext\ntext") - 1 ), "wrong buffer contents \"%s\"\n", buffer );
8580 
8581     r = MsiDatabaseExportA( hdb, "Control", CURR_DIR, "temp_file1");
8582     ok( r == ERROR_SUCCESS, "failed to export table %u\n", r );
8583     read_file_data( "temp_file1", data );
8584     ok( !memcmp( data, export_expected, sizeof(export_expected) - 1), "expected: \"%s\" got: \"%s\"\n", export_expected, data );
8585     DeleteFileA( "temp_file1" );
8586 
8587     MsiCloseHandle( hrec );
8588     MsiCloseHandle( hdb );
8589     DeleteFileA( msifile );
8590 
8591     r = MsiOpenDatabaseW( msifileW, MSIDBOPEN_CREATE, &hdb );
8592     ok( r == ERROR_SUCCESS, "failed to open database %u\n", r );
8593 
8594     GetCurrentDirectoryA( MAX_PATH, CURR_DIR );
8595     write_file( "temp_file", control_table2, sizeof(control_table2) );
8596     r = MsiDatabaseImportA( hdb, CURR_DIR, "temp_file" );
8597     ok( r == ERROR_FUNCTION_FAILED, "failed to import table %u\n", r );
8598     DeleteFileA( "temp_file" );
8599 
8600     MsiCloseHandle( hdb );
8601     DeleteFileA( msifile );
8602 }
8603 
8604 static void test_select_column_names(void)
8605 {
8606     MSIHANDLE hdb = 0, rec, view;
8607     UINT r;
8608 
8609     DeleteFileA(msifile);
8610 
8611     r = MsiOpenDatabaseW( msifileW, MSIDBOPEN_CREATE, &hdb );
8612     ok( r == ERROR_SUCCESS , "failed to open database: %u\n", r );
8613 
8614     r = try_query( hdb, "CREATE TABLE `t` (`a` CHAR NOT NULL, `b` CHAR PRIMARY KEY `a`)");
8615     ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
8616 
8617     r = try_query( hdb, "SELECT `t`.`b` FROM `t` WHERE `t`.`b` = `x`" );
8618     ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %u\n", r );
8619 
8620     r = try_query( hdb, "SELECT '', `t`.`b` FROM `t` WHERE `t`.`b` = 'x'" );
8621     ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
8622 
8623     r = try_query( hdb, "SELECT *, `t`.`b` FROM `t` WHERE `t`.`b` = 'x'" );
8624     todo_wine ok( r == ERROR_SUCCESS, "query failed: %u\n", r );
8625 
8626     r = try_query( hdb, "SELECT 'b', `t`.`b` FROM `t` WHERE `t`.`b` = 'x'" );
8627     ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
8628 
8629     r = try_query( hdb, "SELECT `t`.`b`, '' FROM `t` WHERE `t`.`b` = 'x'" );
8630     ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
8631 
8632     r = try_query( hdb, "SELECT `t`.`b`, '' FROM `t` WHERE `t`.`b` = 'x' ORDER BY `b`" );
8633     ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
8634 
8635     r = try_query( hdb, "SELECT `t`.`b`, '' FROM `t` WHERE `t`.`b` = 'x' ORDER BY 'b'" );
8636     ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %u\n", r );
8637 
8638     r = try_query( hdb, "SELECT 't'.'b' FROM `t` WHERE `t`.`b` = 'x'" );
8639     ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %u\n", r );
8640 
8641     r = try_query( hdb, "SELECT 'b' FROM `t` WHERE `t`.`b` = 'x'" );
8642     ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
8643 
8644     r = try_query( hdb, "INSERT INTO `t` ( `a`, `b` ) VALUES( '1', '2' )" );
8645     ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
8646 
8647     r = try_query( hdb, "INSERT INTO `t` ( `a`, `b` ) VALUES( '3', '4' )" );
8648     ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
8649 
8650     r = MsiDatabaseOpenViewA( hdb, "SELECT '' FROM `t`", &view );
8651     ok( r == ERROR_SUCCESS, "failed to open database view: %u\n", r );
8652 
8653     r = MsiViewExecute( view, 0 );
8654     ok( r == ERROR_SUCCESS, "failed to execute view: %u\n", r );
8655 
8656     r = MsiViewFetch( view, &rec );
8657     ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r );
8658     check_record(rec, 1, "");
8659     MsiCloseHandle(rec);
8660 
8661     r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec);
8662     ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r );
8663     check_record(rec, 1, "");
8664     MsiCloseHandle(rec);
8665 
8666     r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
8667     ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r );
8668     check_record(rec, 1, "f0");
8669     MsiCloseHandle(rec);
8670 
8671     r = MsiViewFetch( view, &rec );
8672     ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r );
8673     check_record(rec, 1, "");
8674     MsiCloseHandle( rec );
8675 
8676     r = MsiViewFetch( view, &rec );
8677     ok( r == ERROR_NO_MORE_ITEMS, "unexpected result: %u\n", r );
8678     MsiCloseHandle( rec );
8679 
8680     MsiViewClose( view );
8681     MsiCloseHandle( view );
8682 
8683     r = MsiDatabaseOpenViewA( hdb, "SELECT `a`, '' FROM `t`", &view );
8684     ok( r == ERROR_SUCCESS, "failed to open database view: %u\n", r );
8685 
8686     r = MsiViewExecute( view, 0 );
8687     ok( r == ERROR_SUCCESS, "failed to execute view: %u\n", r );
8688 
8689     r = MsiViewFetch( view, &rec );
8690     ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r );
8691     check_record(rec, 2, "1", "");
8692     MsiCloseHandle( rec );
8693 
8694     r = MsiViewFetch( view, &rec );
8695     ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r );
8696     check_record(rec, 2, "3", "");
8697     MsiCloseHandle( rec );
8698 
8699     r = MsiViewFetch( view, &rec );
8700     ok( r == ERROR_NO_MORE_ITEMS, "unexpected result: %u\n", r );
8701     MsiCloseHandle( rec );
8702 
8703     MsiViewClose( view );
8704     MsiCloseHandle( view );
8705 
8706     r = MsiDatabaseOpenViewA( hdb, "SELECT '', `a` FROM `t`", &view );
8707     ok( r == ERROR_SUCCESS, "failed to open database view: %u\n", r );
8708 
8709     r = MsiViewExecute( view, 0 );
8710     ok( r == ERROR_SUCCESS, "failed to execute view: %u\n", r );
8711 
8712     r = MsiViewFetch( view, &rec );
8713     ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r );
8714     check_record(rec, 2, "", "1");
8715     MsiCloseHandle( rec );
8716 
8717     r = MsiViewFetch( view, &rec );
8718     ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r );
8719     check_record(rec, 2, "", "3");
8720     MsiCloseHandle( rec );
8721 
8722     r = MsiViewFetch( view, &rec );
8723     ok( r == ERROR_NO_MORE_ITEMS, "unexpected result: %u\n", r );
8724     MsiCloseHandle( rec );
8725 
8726     MsiViewClose( view );
8727     MsiCloseHandle( view );
8728 
8729     r = MsiDatabaseOpenViewA( hdb, "SELECT `a`, '', `b` FROM `t`", &view );
8730     ok( r == ERROR_SUCCESS, "failed to open database view: %u\n", r );
8731 
8732     r = MsiViewExecute( view, 0 );
8733     ok( r == ERROR_SUCCESS, "failed to execute view: %u\n", r );
8734 
8735     r = MsiViewFetch( view, &rec );
8736     ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r );
8737     check_record(rec, 3, "1", "", "2");
8738     MsiCloseHandle( rec );
8739 
8740     r = MsiViewFetch( view, &rec );
8741     ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r );
8742     check_record(rec, 3, "3", "", "4");
8743     MsiCloseHandle( rec );
8744 
8745     r = MsiViewFetch( view, &rec );
8746     ok( r == ERROR_NO_MORE_ITEMS, "unexpected result: %u\n", r );
8747     MsiCloseHandle( rec );
8748 
8749     MsiViewClose( view );
8750     MsiCloseHandle( view );
8751 
8752     r = try_query( hdb, "SELECT '' FROM `t` WHERE `t`.`b` = 'x'" );
8753     ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
8754 
8755     r = try_query( hdb, "SELECT `` FROM `t` WHERE `t`.`b` = 'x'" );
8756     todo_wine ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %u\n", r );
8757 
8758     r = try_query( hdb, "SELECT `b` FROM 't' WHERE `t`.`b` = 'x'" );
8759     ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %u\n", r );
8760 
8761     r = try_query( hdb, "SELECT `b` FROM `t` WHERE 'b' = 'x'" );
8762     ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %u\n", r );
8763 
8764     r = try_query( hdb, "SELECT `t`.`b`, `` FROM `t` WHERE `t`.`b` = 'x'" );
8765     todo_wine ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %u\n", r );
8766 
8767     r = MsiCloseHandle( hdb );
8768     ok(r == ERROR_SUCCESS , "failed to close database: %u\n", r);
8769 }
8770 
8771 static void test_primary_keys(void)
8772 {
8773     MSIHANDLE hdb, keys;
8774     char buffer[5];
8775     DWORD size;
8776     UINT r;
8777 
8778     hdb = create_db();
8779 
8780     r = MsiDatabaseGetPrimaryKeysA(hdb, "T", &keys);
8781     ok(r == ERROR_INVALID_TABLE, "got %u\n", r);
8782 
8783     r = run_query(hdb, 0, "CREATE TABLE `T` (`A` SHORT, `B` SHORT, `C` SHORT PRIMARY KEY `A`)");
8784     ok(!r, "got %u\n", r);
8785 
8786     r = MsiDatabaseGetPrimaryKeysA(hdb, "T", &keys);
8787     ok(!r, "got %u\n", r);
8788     check_record(keys, 1, "A");
8789     size = sizeof(buffer);
8790     r = MsiRecordGetStringA(keys, 0, buffer, &size);
8791     ok(!r, "got %u\n", r);
8792     ok(!strcmp(buffer, "T"), "got \"%s\"\n", buffer);
8793     MsiCloseHandle(keys);
8794 
8795     r = run_query(hdb, 0, "CREATE TABLE `U` (`A` SHORT, `B` SHORT, `C` SHORT PRIMARY KEY `B`, `C`)");
8796     ok(!r, "got %u\n", r);
8797 
8798     r = MsiDatabaseGetPrimaryKeysA(hdb, "U", &keys);
8799     ok(!r, "got %u\n", r);
8800     check_record(keys, 2, "B", "C");
8801     size = sizeof(buffer);
8802     r = MsiRecordGetStringA(keys, 0, buffer, &size);
8803     ok(!r, "got %u\n", r);
8804     ok(!strcmp(buffer, "U"), "got \"%s\"\n", buffer);
8805     MsiCloseHandle(keys);
8806     MsiCloseHandle(hdb);
8807     DeleteFileA(msifile);
8808 }
8809 
8810 static void test_viewmodify_merge(void)
8811 {
8812     MSIHANDLE view, rec, db = create_db();
8813     UINT r;
8814 
8815     r = run_query(db, 0, "CREATE TABLE `T` (`A` SHORT, `B` SHORT PRIMARY KEY `A`)");
8816     ok(!r, "got %u\n", r);
8817     r = run_query(db, 0, "INSERT INTO `T` (`A`, `B`) VALUES (1, 2)");
8818     ok(!r, "got %u\n", r);
8819 
8820     r = MsiDatabaseOpenViewA(db, "SELECT * FROM `T`", &view);
8821     ok(!r, "got %u\n", r);
8822     r = MsiViewExecute(view, 0);
8823     ok(!r, "got %u\n", r);
8824 
8825     rec = MsiCreateRecord(2);
8826     MsiRecordSetInteger(rec, 1, 1);
8827     MsiRecordSetInteger(rec, 2, 2);
8828     r = MsiViewModify(view, MSIMODIFY_MERGE, rec);
8829     ok(!r, "got %u\n", r);
8830 
8831     MsiCloseHandle(rec);
8832     MsiCloseHandle(view);
8833 
8834     r = MsiDatabaseOpenViewA(db, "SELECT * FROM `T`", &view);
8835     ok(!r, "got %u\n", r);
8836     r = MsiViewExecute(view, 0);
8837     ok(!r, "got %u\n", r);
8838 
8839     r = MsiViewFetch(view, &rec);
8840     ok(!r, "got %u\n", r);
8841     check_record(rec, 2, "1", "2");
8842     MsiCloseHandle(rec);
8843 
8844     r = MsiViewFetch(view, &rec);
8845     ok(r == ERROR_NO_MORE_ITEMS, "got %u\n", r);
8846     MsiCloseHandle(view);
8847 
8848     r = MsiDatabaseOpenViewA(db, "SELECT * FROM `T`", &view);
8849     ok(!r, "got %u\n", r);
8850     r = MsiViewExecute(view, 0);
8851     ok(!r, "got %u\n", r);
8852 
8853     rec = MsiCreateRecord(2);
8854     MsiRecordSetInteger(rec, 1, 1);
8855     MsiRecordSetInteger(rec, 2, 3);
8856     r = MsiViewModify(view, MSIMODIFY_MERGE, rec);
8857     todo_wine
8858     ok(r == ERROR_FUNCTION_FAILED, "got %u\n", r);
8859 
8860     MsiRecordSetInteger(rec, 1, 2);
8861     r = MsiViewModify(view, MSIMODIFY_MERGE, rec);
8862     ok(!r, "got %u\n", r);
8863 
8864     MsiCloseHandle(rec);
8865     MsiCloseHandle(view);
8866 
8867     r = MsiDatabaseOpenViewA(db, "SELECT * FROM `T`", &view);
8868     ok(!r, "got %u\n", r);
8869     r = MsiViewExecute(view, 0);
8870     ok(!r, "got %u\n", r);
8871 
8872     r = MsiViewFetch(view, &rec);
8873     ok(!r, "got %u\n", r);
8874     check_record(rec, 2, "1", "2");
8875     MsiCloseHandle(rec);
8876 
8877     r = MsiViewFetch(view, &rec);
8878     ok(!r, "got %u\n", r);
8879     check_record(rec, 2, "2", "3");
8880     MsiCloseHandle(rec);
8881 
8882     r = MsiViewFetch(view, &rec);
8883     ok(r == ERROR_NO_MORE_ITEMS, "got %u\n", r);
8884     MsiCloseHandle(view);
8885 
8886     r = run_query(db, 0, "CREATE TABLE `U` (`A` SHORT, `B` SHORT, `C` SHORT, `D` SHORT PRIMARY KEY `A`, `B`)");
8887     ok(!r, "got %u\n", r);
8888     r = run_query(db, 0, "INSERT INTO `U` (`A`, `B`, `C`, `D`) VALUES (1, 2, 3, 4)");
8889     ok(!r, "got %u\n", r);
8890 
8891     r = MsiDatabaseOpenViewA(db, "SELECT * FROM `U`", &view);
8892     ok(!r, "got %u\n", r);
8893     r = MsiViewExecute(view, 0);
8894     ok(!r, "got %u\n", r);
8895 
8896     rec = MsiCreateRecord(4);
8897     MsiRecordSetInteger(rec, 1, 1);
8898     MsiRecordSetInteger(rec, 2, 2);
8899     MsiRecordSetInteger(rec, 3, 3);
8900     MsiRecordSetInteger(rec, 4, 4);
8901     r = MsiViewModify(view, MSIMODIFY_MERGE, rec);
8902     ok(!r, "got %u\n", r);
8903 
8904     MsiRecordSetInteger(rec, 3, 4);
8905     r = MsiViewModify(view, MSIMODIFY_MERGE, rec);
8906     todo_wine
8907     ok(r == ERROR_FUNCTION_FAILED, "got %u\n", r);
8908 
8909     MsiRecordSetInteger(rec, 2, 4);
8910     r = MsiViewModify(view, MSIMODIFY_MERGE, rec);
8911     ok(!r, "got %u\n", r);
8912 
8913     MsiCloseHandle(rec);
8914     MsiCloseHandle(view);
8915 
8916     r = MsiDatabaseOpenViewA(db, "SELECT * FROM `U`", &view);
8917     ok(!r, "got %u\n", r);
8918     r = MsiViewExecute(view, 0);
8919     ok(!r, "got %u\n", r);
8920 
8921     r = MsiViewFetch(view, &rec);
8922     ok(!r, "got %u\n", r);
8923     check_record(rec, 4, "1", "2", "3", "4");
8924     MsiCloseHandle(rec);
8925 
8926     r = MsiViewFetch(view, &rec);
8927     ok(!r, "got %u\n", r);
8928     check_record(rec, 4, "1", "4", "4", "4");
8929     MsiCloseHandle(rec);
8930 
8931     r = MsiViewFetch(view, &rec);
8932     ok(r == ERROR_NO_MORE_ITEMS, "got %u\n", r);
8933     MsiCloseHandle(view);
8934 
8935     r = MsiDatabaseOpenViewA(db, "SELECT `A`,`C` FROM `U`", &view);
8936     ok(!r, "got %u\n", r);
8937     r = MsiViewExecute(view, 0);
8938     ok(!r, "got %u\n", r);
8939 
8940     rec = MsiCreateRecord(2);
8941     MsiRecordSetInteger(rec, 1, 1);
8942     MsiRecordSetInteger(rec, 2, 2);
8943     r = MsiViewModify(view, MSIMODIFY_MERGE, rec);
8944     ok(!r, "got %u\n", r);
8945 
8946     r = MsiViewModify(view, MSIMODIFY_MERGE, rec);
8947     ok(!r, "got %u\n", r);
8948 
8949     MsiRecordSetInteger(rec, 2, 3);
8950     r = MsiViewModify(view, MSIMODIFY_MERGE, rec);
8951     todo_wine
8952     ok(r == ERROR_FUNCTION_FAILED, "got %u\n", r);
8953 
8954     MsiCloseHandle(rec);
8955     MsiCloseHandle(view);
8956 
8957     r = MsiDatabaseOpenViewA(db, "SELECT * FROM `U` ORDER BY `B`", &view);
8958     ok(!r, "got %u\n", r);
8959     r = MsiViewExecute(view, 0);
8960     ok(!r, "got %u\n", r);
8961 
8962     r = MsiViewFetch(view, &rec);
8963     ok(!r, "got %u\n", r);
8964     check_record(rec, 4, "1", "", "2", "");
8965     MsiCloseHandle(rec);
8966 
8967     r = MsiViewFetch(view, &rec);
8968     ok(!r, "got %u\n", r);
8969     check_record(rec, 4, "1", "2", "3", "4");
8970     MsiCloseHandle(rec);
8971 
8972     r = MsiViewFetch(view, &rec);
8973     ok(!r, "got %u\n", r);
8974     check_record(rec, 4, "1", "4", "4", "4");
8975     MsiCloseHandle(rec);
8976 
8977     r = MsiViewFetch(view, &rec);
8978     ok(r == ERROR_NO_MORE_ITEMS, "got %u\n", r);
8979     MsiCloseHandle(view);
8980 
8981     r = MsiDatabaseOpenViewA(db, "SELECT `A`,`B`,`C` FROM `U`", &view);
8982     ok(!r, "got %u\n", r);
8983     r = MsiViewExecute(view, 0);
8984     ok(!r, "got %u\n", r);
8985 
8986     rec = MsiCreateRecord(3);
8987     MsiRecordSetInteger(rec, 1, 1);
8988     MsiRecordSetInteger(rec, 2, 2);
8989     MsiRecordSetInteger(rec, 3, 3);
8990     r = MsiViewModify(view, MSIMODIFY_MERGE, rec);
8991     todo_wine
8992     ok(r == ERROR_FUNCTION_FAILED, "got %u\n", r);
8993 
8994     MsiRecordSetInteger(rec, 1, 1);
8995     MsiRecordSetInteger(rec, 2, MSI_NULL_INTEGER);
8996     MsiRecordSetInteger(rec, 3, 2);
8997     r = MsiViewModify(view, MSIMODIFY_MERGE, rec);
8998     ok(!r, "got %u\n", r);
8999 
9000     MsiCloseHandle(rec);
9001     MsiCloseHandle(view);
9002 
9003     MsiCloseHandle(db);
9004     DeleteFileA(msifile);
9005 }
9006 
9007 static void test_viewmodify_insert(void)
9008 {
9009     MSIHANDLE view, rec, db = create_db();
9010     UINT r;
9011 
9012     r = run_query(db, 0, "CREATE TABLE `T` (`A` SHORT, `B` SHORT PRIMARY KEY `A`)");
9013     ok(!r, "got %u\n", r);
9014 
9015     r = MsiDatabaseOpenViewA(db, "SELECT * FROM `T`", &view);
9016     ok(!r, "got %u\n", r);
9017     r = MsiViewExecute(view, 0);
9018     ok(!r, "got %u\n", r);
9019 
9020     rec = MsiCreateRecord(2);
9021     MsiRecordSetInteger(rec, 1, 1);
9022     MsiRecordSetInteger(rec, 2, 2);
9023     r = MsiViewModify(view, MSIMODIFY_INSERT, rec);
9024     ok(!r, "got %u\n", r);
9025 
9026     MsiCloseHandle(rec);
9027     MsiCloseHandle(view);
9028 
9029     r = MsiDatabaseOpenViewA(db, "SELECT * FROM `T`", &view);
9030     ok(!r, "got %u\n", r);
9031     r = MsiViewExecute(view, 0);
9032     ok(!r, "got %u\n", r);
9033 
9034     r = MsiViewFetch(view, &rec);
9035     ok(!r, "got %u\n", r);
9036     check_record(rec, 2, "1", "2");
9037     MsiCloseHandle(rec);
9038 
9039     r = MsiViewFetch(view, &rec);
9040     ok(r == ERROR_NO_MORE_ITEMS, "got %u\n", r);
9041     MsiCloseHandle(view);
9042 
9043     r = MsiDatabaseOpenViewA(db, "SELECT * FROM `T`", &view);
9044     ok(!r, "got %u\n", r);
9045     r = MsiViewExecute(view, 0);
9046     ok(!r, "got %u\n", r);
9047 
9048     rec = MsiCreateRecord(2);
9049     MsiRecordSetInteger(rec, 1, 1);
9050     MsiRecordSetInteger(rec, 2, 2);
9051     r = MsiViewModify(view, MSIMODIFY_INSERT, rec);
9052     ok(r == ERROR_FUNCTION_FAILED, "got %u\n", r);
9053 
9054     MsiRecordSetInteger(rec, 2, 3);
9055     r = MsiViewModify(view, MSIMODIFY_INSERT, rec);
9056     ok(r == ERROR_FUNCTION_FAILED, "got %u\n", r);
9057 
9058     MsiRecordSetInteger(rec, 1, 3);
9059     r = MsiViewModify(view, MSIMODIFY_INSERT, rec);
9060     ok(!r, "got %u\n", r);
9061 
9062     MsiCloseHandle(rec);
9063     MsiCloseHandle(view);
9064 
9065     r = MsiDatabaseOpenViewA(db, "SELECT * FROM `T`", &view);
9066     ok(!r, "got %u\n", r);
9067     r = MsiViewExecute(view, 0);
9068     ok(!r, "got %u\n", r);
9069 
9070     r = MsiViewFetch(view, &rec);
9071     ok(!r, "got %u\n", r);
9072     check_record(rec, 2, "1", "2");
9073     MsiCloseHandle(rec);
9074 
9075     r = MsiViewFetch(view, &rec);
9076     ok(!r, "got %u\n", r);
9077     check_record(rec, 2, "3", "3");
9078     MsiCloseHandle(rec);
9079 
9080     r = MsiViewFetch(view, &rec);
9081     ok(r == ERROR_NO_MORE_ITEMS, "got %u\n", r);
9082     MsiCloseHandle(view);
9083 
9084     r = run_query(db, 0, "CREATE TABLE `U` (`A` SHORT, `B` SHORT, `C` SHORT, `D` SHORT PRIMARY KEY `A`, `B`)");
9085     ok(!r, "got %u\n", r);
9086 
9087     r = MsiDatabaseOpenViewA(db, "SELECT * FROM `U`", &view);
9088     ok(!r, "got %u\n", r);
9089     r = MsiViewExecute(view, 0);
9090     ok(!r, "got %u\n", r);
9091 
9092     rec = MsiCreateRecord(4);
9093     MsiRecordSetInteger(rec, 1, 1);
9094     MsiRecordSetInteger(rec, 2, 2);
9095     MsiRecordSetInteger(rec, 3, 3);
9096     MsiRecordSetInteger(rec, 4, 4);
9097     r = MsiViewModify(view, MSIMODIFY_INSERT, rec);
9098     ok(!r, "got %u\n", r);
9099 
9100     MsiRecordSetInteger(rec, 2, 4);
9101     r = MsiViewModify(view, MSIMODIFY_INSERT, rec);
9102     ok(!r, "got %u\n", r);
9103 
9104     MsiCloseHandle(rec);
9105     MsiCloseHandle(view);
9106 
9107     r = MsiDatabaseOpenViewA(db, "SELECT * FROM `U`", &view);
9108     ok(!r, "got %u\n", r);
9109     r = MsiViewExecute(view, 0);
9110     ok(!r, "got %u\n", r);
9111 
9112     r = MsiViewFetch(view, &rec);
9113     ok(!r, "got %u\n", r);
9114     check_record(rec, 4, "1", "2", "3", "4");
9115     MsiCloseHandle(rec);
9116 
9117     r = MsiViewFetch(view, &rec);
9118     ok(!r, "got %u\n", r);
9119     check_record(rec, 4, "1", "4", "3", "4");
9120     MsiCloseHandle(rec);
9121 
9122     r = MsiViewFetch(view, &rec);
9123     ok(r == ERROR_NO_MORE_ITEMS, "got %u\n", r);
9124     MsiCloseHandle(view);
9125 
9126     r = MsiDatabaseOpenViewA(db, "SELECT `A`,`C` FROM `U`", &view);
9127     ok(!r, "got %u\n", r);
9128     r = MsiViewExecute(view, 0);
9129     ok(!r, "got %u\n", r);
9130 
9131     rec = MsiCreateRecord(2);
9132     MsiRecordSetInteger(rec, 1, 1);
9133     MsiRecordSetInteger(rec, 2, 2);
9134     r = MsiViewModify(view, MSIMODIFY_INSERT, rec);
9135     ok(!r, "got %u\n", r);
9136 
9137     r = MsiViewModify(view, MSIMODIFY_INSERT, rec);
9138     ok(r == ERROR_FUNCTION_FAILED, "got %u\n", r);
9139 
9140     MsiCloseHandle(rec);
9141     MsiCloseHandle(view);
9142 
9143     r = MsiDatabaseOpenViewA(db, "SELECT * FROM `U` ORDER BY `B`", &view);
9144     ok(!r, "got %u\n", r);
9145     r = MsiViewExecute(view, 0);
9146     ok(!r, "got %u\n", r);
9147 
9148     r = MsiViewFetch(view, &rec);
9149     ok(!r, "got %u\n", r);
9150     check_record(rec, 4, "1", "", "2", "");
9151     MsiCloseHandle(rec);
9152 
9153     r = MsiViewFetch(view, &rec);
9154     ok(!r, "got %u\n", r);
9155     check_record(rec, 4, "1", "2", "3", "4");
9156     MsiCloseHandle(rec);
9157 
9158     r = MsiViewFetch(view, &rec);
9159     ok(!r, "got %u\n", r);
9160     check_record(rec, 4, "1", "4", "3", "4");
9161     MsiCloseHandle(rec);
9162 
9163     r = MsiViewFetch(view, &rec);
9164     ok(r == ERROR_NO_MORE_ITEMS, "got %u\n", r);
9165     MsiCloseHandle(view);
9166 
9167     MsiCloseHandle(db);
9168     DeleteFileA(msifile);
9169 }
9170 
9171 static void test_view_get_error(void)
9172 {
9173     MSIHANDLE view, rec, db = create_db();
9174     MSIDBERROR err;
9175     char buffer[5];
9176     DWORD sz;
9177     UINT r;
9178 
9179     r = run_query(db, 0, "CREATE TABLE `T` (`A` SHORT, `B` SHORT NOT NULL PRIMARY KEY `A`)");
9180     ok(!r, "got %u\n", r);
9181     r = run_query(db, 0, "INSERT INTO `T` (`A`, `B`) VALUES (1, 2)");
9182     r = run_query(db, 0, "CREATE TABLE `_Validation` ("
9183             "`Table` CHAR(32) NOT NULL, `Column` CHAR(32) NOT NULL, "
9184             "`Nullable` CHAR(4) NOT NULL, `MinValue` INT, `MaxValue` INT, "
9185             "`KeyTable` CHAR(255), `KeyColumn` SHORT, `Category` CHAR(32), "
9186             "`Set` CHAR(255), `Description` CHAR(255) PRIMARY KEY `Table`, `Column`)");
9187     ok(!r, "got %u\n", r);
9188     r = run_query(db, 0, "INSERT INTO `_Validation` (`Table`, `Column`, `Nullable`) VALUES ('T', 'A', 'N')");
9189     ok(!r, "got %u\n", r);
9190     r = run_query(db, 0, "INSERT INTO `_Validation` (`Table`, `Column`, `Nullable`) VALUES ('T', 'B', 'N')");
9191     ok(!r, "got %u\n", r);
9192 
9193     r = MsiDatabaseOpenViewA(db, "SELECT * FROM `T`", &view);
9194     ok(!r, "got %u\n", r);
9195 
9196     r = MsiViewExecute(view, 0);
9197     ok(!r, "got %u\n", r);
9198 
9199     sz = 0;
9200     err = MsiViewGetErrorA(0, NULL, &sz);
9201     ok(err == MSIDBERROR_INVALIDARG, "got %d\n", err);
9202     ok(sz == 0, "got size %lu\n", sz);
9203 
9204     err = MsiViewGetErrorA(view, NULL, NULL);
9205     ok(err == MSIDBERROR_INVALIDARG, "got %d\n", err);
9206 
9207     sz = 0;
9208     err = MsiViewGetErrorA(view, NULL, &sz);
9209     ok(err == MSIDBERROR_NOERROR, "got %d\n", err);
9210     ok(sz == 0, "got size %lu\n", sz);
9211 
9212     sz = 0;
9213     strcpy(buffer, "x");
9214     err = MsiViewGetErrorA(view, buffer, &sz);
9215     ok(err == MSIDBERROR_MOREDATA, "got %d\n", err);
9216     ok(!strcmp(buffer, "x"), "got \"%s\"\n", buffer);
9217     ok(sz == 0, "got size %lu\n", sz);
9218 
9219     sz = 1;
9220     strcpy(buffer, "x");
9221     err = MsiViewGetErrorA(view, buffer, &sz);
9222     ok(err == MSIDBERROR_NOERROR, "got %d\n", err);
9223     ok(!buffer[0], "got \"%s\"\n", buffer);
9224     ok(sz == 0, "got size %lu\n", sz);
9225 
9226     rec = MsiCreateRecord(2);
9227     MsiRecordSetInteger(rec, 1, 1);
9228     MsiRecordSetInteger(rec, 2, 2);
9229     r = MsiViewModify(view, MSIMODIFY_VALIDATE_NEW, rec);
9230     ok(r == ERROR_INVALID_DATA, "got %u\n", r);
9231 
9232     sz = 2;
9233     strcpy(buffer, "x");
9234     err = MsiViewGetErrorA(view, buffer, &sz);
9235     ok(err == MSIDBERROR_DUPLICATEKEY, "got %d\n", err);
9236     ok(!strcmp(buffer, "A"), "got \"%s\"\n", buffer);
9237     ok(sz == 1, "got size %lu\n", sz);
9238 
9239     sz = 2;
9240     strcpy(buffer, "x");
9241     err = MsiViewGetErrorA(view, buffer, &sz);
9242     todo_wine ok(err == MSIDBERROR_NOERROR, "got %d\n", err);
9243     todo_wine ok(!buffer[0], "got \"%s\"\n", buffer);
9244     todo_wine ok(sz == 0, "got size %lu\n", sz);
9245 
9246     r = MsiViewModify(view, MSIMODIFY_VALIDATE_NEW, rec);
9247     ok(r == ERROR_INVALID_DATA, "got %u\n", r);
9248 
9249     sz = 1;
9250     strcpy(buffer, "x");
9251     err = MsiViewGetErrorA(view, buffer, &sz);
9252     ok(err == MSIDBERROR_MOREDATA, "got %d\n", err);
9253     ok(!buffer[0], "got \"%s\"\n", buffer);
9254     ok(sz == 1, "got size %lu\n", sz);
9255 
9256     sz = 1;
9257     strcpy(buffer, "x");
9258     err = MsiViewGetErrorA(view, buffer, &sz);
9259     todo_wine ok(err == MSIDBERROR_NOERROR, "got %d\n", err);
9260     ok(!buffer[0], "got \"%s\"\n", buffer);
9261     todo_wine ok(sz == 0, "got size %lu\n", sz);
9262 
9263     r = MsiViewModify(view, MSIMODIFY_VALIDATE_NEW, rec);
9264     ok(r == ERROR_INVALID_DATA, "got %u\n", r);
9265 
9266     sz = 0;
9267     strcpy(buffer, "x");
9268     err = MsiViewGetErrorA(view, buffer, &sz);
9269     ok(err == MSIDBERROR_MOREDATA, "got %d\n", err);
9270     ok(!strcmp(buffer, "x"), "got \"%s\"\n", buffer);
9271     ok(sz == 1, "got size %lu\n", sz);
9272 
9273     sz = 0;
9274     strcpy(buffer, "x");
9275     err = MsiViewGetErrorA(view, buffer, &sz);
9276     ok(err == MSIDBERROR_MOREDATA, "got %d\n", err);
9277     ok(!strcmp(buffer, "x"), "got \"%s\"\n", buffer);
9278     todo_wine ok(sz == 0, "got size %lu\n", sz);
9279 
9280     MsiCloseHandle(rec);
9281     MsiCloseHandle(view);
9282     MsiCloseHandle(db);
9283     DeleteFileA(msifile);
9284 }
9285 
9286 static void test_viewfetch_wraparound(void)
9287 {
9288     MSIHANDLE db = 0, view = 0, rec = 0;
9289     UINT r, i, idset, tries;
9290     const char *query;
9291 
9292     DeleteFileA(msifile);
9293 
9294     /* just MsiOpenDatabase should not create a file */
9295     r = MsiOpenDatabaseW( msifileW, MSIDBOPEN_CREATE, &db );
9296     ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r );
9297 
9298     query = "CREATE TABLE `phone` ( "
9299             "`id` INT, `name` CHAR(32), `number` CHAR(32) "
9300             "PRIMARY KEY `id`)";
9301     r = run_query( db, 0, query );
9302     ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r );
9303 
9304     query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
9305         "VALUES('1', 'Alan', '5030581')";
9306     r = run_query( db, 0, query );
9307     ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r );
9308 
9309     query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
9310         "VALUES('2', 'Barry', '928440')";
9311     r = run_query( db, 0, query );
9312     ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r );
9313 
9314     query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
9315         "VALUES('3', 'Cindy', '2937550')";
9316     r = run_query( db, 0, query );
9317     ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r );
9318 
9319     query = "SELECT * FROM `phone`";
9320     r = MsiDatabaseOpenViewA( db, query, &view );
9321     ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r );
9322 
9323     r = MsiViewExecute( view, 0 );
9324     ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r );
9325 
9326     for (tries = 0; tries < 3; tries++)
9327     {
9328         winetest_push_context( "Wraparound attempt #%d", tries );
9329         idset = 0;
9330 
9331         for (i = 0; i < 3; i++)
9332         {
9333             winetest_push_context( "Record #%d", i );
9334 
9335             r = MsiViewFetch( view, &rec );
9336             ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r );
9337             if (r != ERROR_SUCCESS)
9338             {
9339                 winetest_pop_context();
9340                 break;
9341             }
9342 
9343             r = MsiRecordGetInteger(rec, 1);
9344             ok(r >= 1 && r <= 3, "Expected 1 <= id <= 3, got %d\n", r);
9345             if (r < sizeof(idset) * 8)
9346             {
9347                 ok(!(idset & (1 << r)), "Duplicate id %d\n", r);
9348                 idset |= 1 << r;
9349             }
9350 
9351             MsiCloseHandle(rec);
9352 
9353             winetest_pop_context();
9354         }
9355 
9356         r = MsiViewFetch(view, &rec);
9357         ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
9358 
9359         winetest_pop_context();
9360     }
9361 
9362     MsiViewClose(view);
9363     MsiCloseHandle(view);
9364     MsiCloseHandle(db);
9365     DeleteFileA(msifile);
9366 }
9367 
9368 START_TEST(db)
9369 {
9370     test_msidatabase();
9371     test_msiinsert();
9372     test_msidecomposedesc();
9373     test_msibadqueries();
9374     test_viewmodify();
9375     test_viewgetcolumninfo();
9376     test_getcolinfo();
9377     test_msiexport();
9378     test_longstrings();
9379     test_streamtable();
9380     test_binary();
9381     test_where_not_in_selected();
9382     test_where();
9383     test_msiimport();
9384     test_binary_import();
9385     test_markers();
9386     test_handle_limit();
9387     test_try_transform();
9388     test_join();
9389     test_temporary_table();
9390     test_alter();
9391     test_integers();
9392     test_update();
9393     test_special_tables();
9394     test_tables_order();
9395     test_rows_order();
9396     test_select_markers();
9397     test_viewmodify_update();
9398     test_viewmodify_assign();
9399     test_stringtable();
9400     test_viewmodify_delete();
9401     test_defaultdatabase();
9402     test_order();
9403     test_viewmodify_delete_temporary();
9404     test_deleterow();
9405     test_quotes();
9406     test_carriagereturn();
9407     test_noquotes();
9408     test_forcecodepage();
9409     test_viewmodify_refresh();
9410     test_where_viewmodify();
9411     test_storages_table();
9412     test_dbtopackage();
9413     test_droptable();
9414     test_dbmerge();
9415     test_select_with_tablenames();
9416     test_insertorder();
9417     test_columnorder();
9418     test_suminfo_import();
9419     test_createtable();
9420     test_collation();
9421     test_embedded_nulls();
9422     test_select_column_names();
9423     test_primary_keys();
9424     test_viewmodify_merge();
9425     test_viewmodify_insert();
9426     test_view_get_error();
9427     test_viewfetch_wraparound();
9428 }
9429