xref: /reactos/modules/rostests/winetests/msi/db.c (revision b36d9bd9)
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 
33 static const char *msifile = "winetest-db.msi";
34 static const char *msifile2 = "winetst2-db.msi";
35 static const char *mstfile = "winetst-db.mst";
36 static const WCHAR msifileW[] = L"winetest-db.msi";
37 static const WCHAR msifile2W[] = L"winetst2-db.msi";
38 
39 static void WINAPIV check_record_(int line, MSIHANDLE rec, UINT count, ...)
40 {
41     va_list args;
42     UINT i;
43 
44     ok_(__FILE__, line)(count == MsiRecordGetFieldCount(rec),
45             "expected %u fields, got %u\n", count, MsiRecordGetFieldCount(rec));
46 
47     va_start(args, count);
48 
49     for (i = 1; i <= count; ++i)
50     {
51         const char *expect = va_arg(args, const char *);
52         char buffer[200] = "x";
53         DWORD sz = sizeof(buffer);
54         UINT r = MsiRecordGetStringA(rec, i, buffer, &sz);
55         ok_(__FILE__, line)(r == ERROR_SUCCESS, "field %u: got unexpected error %u\n", i, r);
56         ok_(__FILE__, line)(!strcmp(buffer, expect),
57                 "field %u: expected \"%s\", got \"%s\"\n", i, expect, buffer);
58     }
59 
60     va_end(args);
61 }
62 #define check_record(rec, ...) check_record_(__LINE__, rec, __VA_ARGS__)
63 
64 static void test_msidatabase(void)
65 {
66     MSIHANDLE hdb = 0, hdb2 = 0;
67     WCHAR path[MAX_PATH];
68     DWORD len;
69     UINT res;
70 
71     DeleteFileW(msifileW);
72 
73     res = MsiOpenDatabaseW( msifileW, msifile2W, &hdb );
74     ok( res == ERROR_OPEN_FAILED, "expected failure\n");
75 
76     res = MsiOpenDatabaseW( msifileW, (LPWSTR)0xff, &hdb );
77     ok( res == ERROR_INVALID_PARAMETER, "expected failure\n");
78 
79     res = MsiCloseHandle( hdb );
80     ok( res == ERROR_SUCCESS , "Failed to close database\n" );
81 
82     /* create an empty database */
83     res = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb );
84     ok( res == ERROR_SUCCESS , "Failed to create database\n" );
85 
86     res = MsiDatabaseCommit( hdb );
87     ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
88 
89     ok( GetFileAttributesA( msifile ) != INVALID_FILE_ATTRIBUTES, "database should exist\n");
90 
91     res = MsiCloseHandle( hdb );
92     ok( res == ERROR_SUCCESS , "Failed to close database\n" );
93     res = MsiOpenDatabaseW( msifileW, msifile2W, &hdb2 );
94     ok( res == ERROR_SUCCESS , "Failed to open database\n" );
95 
96     ok( GetFileAttributesA( msifile2 ) != INVALID_FILE_ATTRIBUTES, "database should exist\n");
97 
98     res = MsiDatabaseCommit( hdb2 );
99     ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
100 
101     res = MsiCloseHandle( hdb2 );
102     ok( res == ERROR_SUCCESS , "Failed to close database\n" );
103 
104     res = MsiOpenDatabaseW( msifileW, msifile2W, &hdb2 );
105     ok( res == ERROR_SUCCESS , "Failed to open database\n" );
106 
107     res = MsiCloseHandle( hdb2 );
108     ok( res == ERROR_SUCCESS , "Failed to close database\n" );
109 
110     ok( GetFileAttributesA( msifile2 ) == INVALID_FILE_ATTRIBUTES, "uncommitted database should not exist\n");
111 
112     res = MsiOpenDatabaseW( msifileW, msifile2W, &hdb2 );
113     ok( res == ERROR_SUCCESS , "Failed to close database\n" );
114 
115     res = MsiDatabaseCommit( hdb2 );
116     ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
117 
118     res = MsiCloseHandle( hdb2 );
119     ok( res == ERROR_SUCCESS , "Failed to close database\n" );
120 
121     ok( GetFileAttributesA( msifile2 ) != INVALID_FILE_ATTRIBUTES, "committed database should exist\n");
122 
123     res = MsiOpenDatabaseW( msifileW, MSIDBOPEN_READONLY, &hdb );
124     ok( res == ERROR_SUCCESS , "Failed to open database\n" );
125 
126     res = MsiDatabaseCommit( hdb );
127     ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
128 
129     res = MsiCloseHandle( hdb );
130     ok( res == ERROR_SUCCESS , "Failed to close database\n" );
131 
132     res = MsiOpenDatabaseW( msifileW, MSIDBOPEN_DIRECT, &hdb );
133     ok( res == ERROR_SUCCESS , "Failed to open database\n" );
134 
135     res = MsiCloseHandle( hdb );
136     ok( res == ERROR_SUCCESS , "Failed to close database\n" );
137 
138     res = MsiOpenDatabaseW( msifileW, MSIDBOPEN_TRANSACT, &hdb );
139     ok( res == ERROR_SUCCESS , "Failed to open database\n" );
140 
141     res = MsiCloseHandle( hdb );
142     ok( res == ERROR_SUCCESS , "Failed to close database\n" );
143     ok( GetFileAttributesA( msifile ) != INVALID_FILE_ATTRIBUTES, "database should exist\n");
144 
145     /* MSIDBOPEN_CREATE deletes the database if MsiCommitDatabase isn't called */
146     res = MsiOpenDatabaseW( msifileW, MSIDBOPEN_CREATE, &hdb );
147     ok( res == ERROR_SUCCESS , "Failed to open database\n" );
148 
149     ok( GetFileAttributesA( msifile ) != INVALID_FILE_ATTRIBUTES, "database should exist\n");
150 
151     res = MsiCloseHandle( hdb );
152     ok( res == ERROR_SUCCESS , "Failed to close database\n" );
153 
154     ok( GetFileAttributesA( msifile ) == INVALID_FILE_ATTRIBUTES, "database should exist\n");
155 
156     res = MsiOpenDatabaseW( msifileW, MSIDBOPEN_CREATE, &hdb );
157     ok( res == ERROR_SUCCESS , "Failed to open database\n" );
158 
159     res = MsiDatabaseCommit( hdb );
160     ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
161 
162     ok( GetFileAttributesA( msifile ) != INVALID_FILE_ATTRIBUTES, "database should exist\n");
163 
164     res = MsiCloseHandle( hdb );
165     ok( res == ERROR_SUCCESS , "Failed to close database\n" );
166 
167     res = GetCurrentDirectoryW(ARRAY_SIZE(path), path);
168     ok ( res, "Got zero res.\n" );
169     lstrcatW( path, L"\\");
170     lstrcatW( path, msifileW);
171     len = lstrlenW(path);
172     path[len - 4] = 0;
173 
174     res = MsiOpenDatabaseW( path, MSIDBOPEN_READONLY, &hdb );
175     ok( res != ERROR_SUCCESS , "Got unexpected res %u.\n", res );
176 
177     lstrcpyW( path, msifileW );
178     path[lstrlenW(path) - 4] = 0;
179 
180     res = MsiOpenDatabaseW( path, MSIDBOPEN_READONLY, &hdb );
181     ok( res != ERROR_SUCCESS , "Got unexpected res %u.\n", res );
182 
183     res = DeleteFileA( msifile2 );
184     ok( res == TRUE, "Failed to delete database\n" );
185 
186     res = DeleteFileA( msifile );
187     ok( res == TRUE, "Failed to delete database\n" );
188 }
189 
190 static UINT do_query(MSIHANDLE hdb, const char *query, MSIHANDLE *phrec)
191 {
192     MSIHANDLE hview = 0;
193     UINT r, ret;
194 
195     if (phrec)
196         *phrec = 0;
197 
198     /* open a select query */
199     r = MsiDatabaseOpenViewA(hdb, query, &hview);
200     if (r != ERROR_SUCCESS)
201         return r;
202     r = MsiViewExecute(hview, 0);
203     if (r != ERROR_SUCCESS)
204         return r;
205     ret = MsiViewFetch(hview, phrec);
206     r = MsiViewClose(hview);
207     if (r != ERROR_SUCCESS)
208         return r;
209     r = MsiCloseHandle(hview);
210     if (r != ERROR_SUCCESS)
211         return r;
212     return ret;
213 }
214 
215 static UINT run_query( MSIHANDLE hdb, MSIHANDLE hrec, const char *query )
216 {
217     MSIHANDLE hview = 0;
218     UINT r;
219 
220     r = MsiDatabaseOpenViewA(hdb, query, &hview);
221     if( r != ERROR_SUCCESS )
222         return r;
223 
224     r = MsiViewExecute(hview, hrec);
225     if( r == ERROR_SUCCESS )
226         r = MsiViewClose(hview);
227     MsiCloseHandle(hview);
228     return r;
229 }
230 
231 static UINT run_queryW( MSIHANDLE hdb, MSIHANDLE hrec, const WCHAR *query )
232 {
233     MSIHANDLE hview = 0;
234     UINT r;
235 
236     r = MsiDatabaseOpenViewW(hdb, query, &hview);
237     if( r != ERROR_SUCCESS )
238         return r;
239 
240     r = MsiViewExecute(hview, hrec);
241     if( r == ERROR_SUCCESS )
242         r = MsiViewClose(hview);
243     MsiCloseHandle(hview);
244     return r;
245 }
246 
247 static UINT create_component_table( MSIHANDLE hdb )
248 {
249     UINT r = run_query( hdb, 0,
250             "CREATE TABLE `Component` ( "
251             "`Component` CHAR(72) NOT NULL, "
252             "`ComponentId` CHAR(38), "
253             "`Directory_` CHAR(72) NOT NULL, "
254             "`Attributes` SHORT NOT NULL, "
255             "`Condition` CHAR(255), "
256             "`KeyPath` CHAR(72) "
257             "PRIMARY KEY `Component`)" );
258     ok(r == ERROR_SUCCESS, "Failed to create Component table: %u\n", r);
259     return r;
260 }
261 
262 static UINT create_custom_action_table( MSIHANDLE hdb )
263 {
264     UINT r = run_query( hdb, 0,
265             "CREATE TABLE `CustomAction` ( "
266             "`Action` CHAR(72) NOT NULL, "
267             "`Type` SHORT NOT NULL, "
268             "`Source` CHAR(72), "
269             "`Target` CHAR(255) "
270             "PRIMARY KEY `Action`)" );
271     ok(r == ERROR_SUCCESS, "Failed to create CustomAction table: %u\n", r);
272     return r;
273 }
274 
275 static UINT create_directory_table( MSIHANDLE hdb )
276 {
277     UINT r = run_query( hdb, 0,
278             "CREATE TABLE `Directory` ( "
279             "`Directory` CHAR(255) NOT NULL, "
280             "`Directory_Parent` CHAR(255), "
281             "`DefaultDir` CHAR(255) NOT NULL "
282             "PRIMARY KEY `Directory`)" );
283     ok(r == ERROR_SUCCESS, "Failed to create Directory table: %u\n", r);
284     return r;
285 }
286 
287 static UINT create_feature_components_table( MSIHANDLE hdb )
288 {
289     UINT r = run_query( hdb, 0,
290             "CREATE TABLE `FeatureComponents` ( "
291             "`Feature_` CHAR(38) NOT NULL, "
292             "`Component_` CHAR(72) NOT NULL "
293             "PRIMARY KEY `Feature_`, `Component_` )" );
294     ok(r == ERROR_SUCCESS, "Failed to create FeatureComponents table: %u\n", r);
295     return r;
296 }
297 
298 static UINT create_std_dlls_table( MSIHANDLE hdb )
299 {
300     UINT r = run_query( hdb, 0,
301             "CREATE TABLE `StdDlls` ( "
302             "`File` CHAR(255) NOT NULL, "
303             "`Binary_` CHAR(72) NOT NULL "
304             "PRIMARY KEY `File` )" );
305     ok(r == ERROR_SUCCESS, "Failed to create StdDlls table: %u\n", r);
306     return r;
307 }
308 
309 static UINT create_binary_table( MSIHANDLE hdb )
310 {
311     UINT r = run_query( hdb, 0,
312            "CREATE TABLE `Binary` ( "
313             "`Name` CHAR(72) NOT NULL, "
314             "`Data` CHAR(72) NOT NULL "
315             "PRIMARY KEY `Name` )" );
316     ok(r == ERROR_SUCCESS, "Failed to create Binary table: %u\n", r);
317     return r;
318 }
319 
320 static inline UINT add_entry(const char *file, int line, const char *type, MSIHANDLE hdb, const char *values, const char *insert)
321 {
322     char *query;
323     UINT sz, r;
324 
325     sz = strlen(values) + strlen(insert) + 1;
326     query = malloc(sz);
327     sprintf(query, insert, values);
328     r = run_query(hdb, 0, query);
329     free(query);
330     ok_(file, line)(r == ERROR_SUCCESS, "failed to insert into %s table: %u\n", type, r);
331     return r;
332 }
333 
334 #define add_component_entry(hdb, values) add_entry(__FILE__, __LINE__, "Component", hdb, values, \
335                "INSERT INTO `Component`  " \
336                "(`Component`, `ComponentId`, `Directory_`, " \
337                "`Attributes`, `Condition`, `KeyPath`) VALUES( %s )")
338 
339 #define add_custom_action_entry(hdb, values) add_entry(__FILE__, __LINE__, "CustomAction", hdb, values, \
340                "INSERT INTO `CustomAction`  " \
341                "(`Action`, `Type`, `Source`, `Target`) VALUES( %s )")
342 
343 #define add_feature_components_entry(hdb, values) add_entry(__FILE__, __LINE__, "FeatureComponents", hdb, values, \
344                "INSERT INTO `FeatureComponents` " \
345                "(`Feature_`, `Component_`) VALUES( %s )")
346 
347 #define add_std_dlls_entry(hdb, values) add_entry(__FILE__, __LINE__, "StdDlls", hdb, values, \
348                "INSERT INTO `StdDlls` (`File`, `Binary_`) VALUES( %s )")
349 
350 #define add_binary_entry(hdb, values) add_entry(__FILE__, __LINE__, "Binary", hdb, values, \
351                "INSERT INTO `Binary` (`Name`, `Data`) VALUES( %s )")
352 
353 static void test_msiinsert(void)
354 {
355     MSIHANDLE hdb = 0, hview = 0, hview2 = 0, hrec = 0;
356     UINT r;
357     const char *query;
358     char buf[80];
359     DWORD sz;
360 
361     DeleteFileA(msifile);
362 
363     /* just MsiOpenDatabase should not create a file */
364     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
365     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
366 
367     /* create a table */
368     query = "CREATE TABLE `phone` ( "
369             "`id` INT, `name` CHAR(32), `number` CHAR(32) "
370             "PRIMARY KEY `id`)";
371     r = MsiDatabaseOpenViewA(hdb, query, &hview);
372     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
373     r = MsiViewExecute(hview, 0);
374     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
375     r = MsiViewClose(hview);
376     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
377     r = MsiCloseHandle(hview);
378     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
379 
380     query = "SELECT * FROM phone WHERE number = '8675309'";
381     r = MsiDatabaseOpenViewA(hdb, query, &hview2);
382     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
383     r = MsiViewExecute(hview2, 0);
384     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
385     r = MsiViewFetch(hview2, &hrec);
386     ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch produced items\n");
387 
388     /* insert a value into it */
389     query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
390         "VALUES('1', 'Abe', '8675309')";
391     r = MsiDatabaseOpenViewA(hdb, query, &hview);
392     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
393     r = MsiViewExecute(hview, 0);
394     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
395     r = MsiViewClose(hview);
396     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
397     r = MsiCloseHandle(hview);
398     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
399 
400     r = MsiViewFetch(hview2, &hrec);
401     ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch produced items\n");
402     r = MsiViewExecute(hview2, 0);
403     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
404     r = MsiViewFetch(hview2, &hrec);
405     ok(r == ERROR_SUCCESS, "MsiViewFetch failed: %u\n", r);
406 
407     r = MsiCloseHandle(hrec);
408     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
409     r = MsiViewClose(hview2);
410     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
411     r = MsiCloseHandle(hview2);
412     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
413 
414     query = "SELECT * FROM `phone` WHERE `id` = 1";
415     r = do_query(hdb, query, &hrec);
416     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
417 
418     /* check the record contains what we put in it */
419     r = MsiRecordGetFieldCount(hrec);
420     ok(r == 3, "record count wrong\n");
421 
422     r = MsiRecordIsNull(hrec, 0);
423     ok(r == FALSE, "field 0 not null\n");
424 
425     r = MsiRecordGetInteger(hrec, 1);
426     ok(r == 1, "field 1 contents wrong\n");
427     sz = sizeof buf;
428     r = MsiRecordGetStringA(hrec, 2, buf, &sz);
429     ok(r == ERROR_SUCCESS, "field 2 content fetch failed\n");
430     ok(!strcmp(buf,"Abe"), "field 2 content incorrect\n");
431     sz = sizeof buf;
432     r = MsiRecordGetStringA(hrec, 3, buf, &sz);
433     ok(r == ERROR_SUCCESS, "field 3 content fetch failed\n");
434     ok(!strcmp(buf,"8675309"), "field 3 content incorrect\n");
435 
436     r = MsiCloseHandle(hrec);
437     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
438 
439     /* open a select query */
440     hrec = 100;
441     query = "SELECT * FROM `phone` WHERE `id` >= 10";
442     r = do_query(hdb, query, &hrec);
443     ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch failed\n");
444     ok(hrec == 0, "hrec should be null\n");
445 
446     r = MsiCloseHandle(hrec);
447     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
448 
449     query = "SELECT * FROM `phone` WHERE `id` < 0";
450     r = do_query(hdb, query, &hrec);
451     ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch failed\n");
452 
453     query = "SELECT * FROM `phone` WHERE `id` <= 0";
454     r = do_query(hdb, query, &hrec);
455     ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch failed\n");
456 
457     query = "SELECT * FROM `phone` WHERE `id` <> 1";
458     r = do_query(hdb, query, &hrec);
459     ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch failed\n");
460 
461     query = "SELECT * FROM `phone` WHERE `id` > 10";
462     r = do_query(hdb, query, &hrec);
463     ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch failed\n");
464 
465     /* now try a few bad INSERT xqueries */
466     query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
467         "VALUES(?, ?)";
468     r = MsiDatabaseOpenViewA(hdb, query, &hview);
469     ok(r == ERROR_BAD_QUERY_SYNTAX, "MsiDatabaseOpenView failed\n");
470 
471     /* construct a record to insert */
472     hrec = MsiCreateRecord(4);
473     r = MsiRecordSetInteger(hrec, 1, 2);
474     ok(r == ERROR_SUCCESS, "MsiRecordSetInteger failed\n");
475     r = MsiRecordSetStringA(hrec, 2, "Adam");
476     ok(r == ERROR_SUCCESS, "MsiRecordSetString failed\n");
477     r = MsiRecordSetStringA(hrec, 3, "96905305");
478     ok(r == ERROR_SUCCESS, "MsiRecordSetString failed\n");
479 
480     /* insert another value, using a record and wildcards */
481     query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
482         "VALUES(?, ?, ?)";
483     r = MsiDatabaseOpenViewA(hdb, query, &hview);
484     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
485 
486     if (r == ERROR_SUCCESS)
487     {
488         r = MsiViewExecute(hview, hrec);
489         ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
490         r = MsiViewClose(hview);
491         ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
492         r = MsiCloseHandle(hview);
493         ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
494     }
495     r = MsiCloseHandle(hrec);
496     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
497 
498     r = MsiViewFetch(0, NULL);
499     ok(r == ERROR_INVALID_PARAMETER, "MsiViewFetch failed\n");
500 
501     r = MsiDatabaseCommit(hdb);
502     ok(r == ERROR_SUCCESS, "MsiDatabaseCommit failed\n");
503 
504     r = MsiCloseHandle(hdb);
505     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
506 
507     r = DeleteFileA(msifile);
508     ok(r == TRUE, "file didn't exist after commit\n");
509 }
510 
511 static void test_msidecomposedesc(void)
512 {
513     UINT (WINAPI *pMsiDecomposeDescriptorA)(LPCSTR, LPCSTR, LPSTR, LPSTR, DWORD *);
514     char prod[MAX_FEATURE_CHARS+1], comp[MAX_FEATURE_CHARS+1], feature[MAX_FEATURE_CHARS+1];
515     const char *desc;
516     UINT r;
517     DWORD len;
518     HMODULE hmod;
519 
520     hmod = GetModuleHandleA("msi.dll");
521     pMsiDecomposeDescriptorA = (void*)GetProcAddress(hmod, "MsiDecomposeDescriptorA");
522     if (!pMsiDecomposeDescriptorA)
523         return;
524 
525     /* test a valid feature descriptor */
526     desc = "']gAVn-}f(ZXfeAR6.jiFollowTheWhiteRabbit>3w2x^IGfe?CxI5heAvk.";
527     len = 0;
528     prod[0] = feature[0] = comp[0] = 0;
529     r = pMsiDecomposeDescriptorA(desc, prod, feature, comp, &len);
530     ok(r == ERROR_SUCCESS, "returned an error\n");
531     ok(len == strlen(desc), "length was wrong\n");
532     ok(strcmp(prod,"{90110409-6000-11D3-8CFE-0150048383C9}")==0, "product wrong\n");
533     ok(strcmp(feature,"FollowTheWhiteRabbit")==0, "feature wrong\n");
534     ok(strcmp(comp,"{A7CD68DB-EF74-49C8-FBB2-A7C463B2AC24}")==0,"component wrong\n");
535 
536     /* test an invalid feature descriptor with too many characters */
537     desc = "']gAVn-}f(ZXfeAR6.ji"
538            "ThisWillFailIfTheresMoreThanAGuidsChars>"
539            "3w2x^IGfe?CxI5heAvk.";
540     len = 0;
541     r = pMsiDecomposeDescriptorA(desc, prod, feature, comp, &len);
542     ok(r == ERROR_INVALID_PARAMETER, "returned wrong error\n");
543 
544     /* test a feature descriptor with < instead of > */
545     desc = "']gAVn-}f(ZXfeAR6.jiFollowTheWhiteRabbit<3w2x^IGfe?CxI5heAvk.";
546     len = 0;
547     prod[0] = feature[0] = 0;
548     comp[0] = 0x55;
549     r = pMsiDecomposeDescriptorA(desc, prod, feature, comp, &len);
550     ok(r == ERROR_SUCCESS, "returned an error\n");
551     ok(len == 41, "got %lu\n", len);
552     ok(!strcmp(prod,"{90110409-6000-11D3-8CFE-0150048383C9}"), "got '%s'\n", prod);
553     ok(!strcmp(feature,"FollowTheWhiteRabbit"), "got '%s'\n", feature);
554     ok(!comp[0], "got '%s'\n", comp);
555 
556     len = 0;
557     prod[0] = feature[0] = 0;
558     comp[0] = 0x55;
559     r = pMsiDecomposeDescriptorA("yh1BVN)8A$!!!!!MKKSkAlwaysInstalledIntl_1033<", prod, feature, comp, &len);
560     ok(r == ERROR_SUCCESS, "got %u\n", r);
561     ok(len == 45, "got %lu\n", len);
562     ok(!strcmp(prod, "{90150000-006E-0409-0000-0000000FF1CE}"), "got '%s'\n", prod);
563     ok(!strcmp(feature, "AlwaysInstalledIntl_1033"), "got '%s'\n", feature);
564     ok(!comp[0], "got '%s'\n", comp);
565 
566     /*
567      * Test a valid feature descriptor with the
568      * maximum number of characters and some trailing characters.
569      */
570     desc = "']gAVn-}f(ZXfeAR6.ji"
571            "ThisWillWorkIfTheresLTEThanAGuidsChars>"
572            "3w2x^IGfe?CxI5heAvk."
573            "extra";
574     len = 0;
575     r = pMsiDecomposeDescriptorA(desc, prod, feature, comp, &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(desc, prod, feature, NULL, &len);
581     ok(r == ERROR_SUCCESS, "returned wrong error\n");
582     ok(len == (strlen(desc) - strlen("extra")), "length wrong\n");
583 
584     len = 0;
585     r = pMsiDecomposeDescriptorA(desc, prod, NULL, NULL, &len);
586     ok(r == ERROR_SUCCESS, "returned wrong error\n");
587     ok(len == (strlen(desc) - strlen("extra")), "length wrong\n");
588 
589     len = 0;
590     r = pMsiDecomposeDescriptorA(desc, NULL, NULL, NULL, &len);
591     ok(r == ERROR_SUCCESS, "returned wrong error\n");
592     ok(len == (strlen(desc) - strlen("extra")), "length wrong\n");
593 
594     len = 0;
595     r = pMsiDecomposeDescriptorA(NULL, NULL, NULL, NULL, &len);
596     ok(r == ERROR_INVALID_PARAMETER, "returned wrong error\n");
597     ok(len == 0, "length wrong\n");
598 
599     r = pMsiDecomposeDescriptorA(desc, NULL, NULL, NULL, NULL);
600     ok(r == ERROR_SUCCESS, "returned wrong error\n");
601 }
602 
603 static UINT try_query_param( MSIHANDLE hdb, LPCSTR szQuery, MSIHANDLE hrec )
604 {
605     MSIHANDLE htab = 0;
606     UINT res;
607 
608     res = MsiDatabaseOpenViewA( hdb, szQuery, &htab );
609     if(res == ERROR_SUCCESS )
610     {
611         UINT r;
612 
613         r = MsiViewExecute( htab, hrec );
614         if(r != ERROR_SUCCESS )
615             res = r;
616 
617         r = MsiViewClose( htab );
618         if(r != ERROR_SUCCESS )
619             res = r;
620 
621         r = MsiCloseHandle( htab );
622         if(r != ERROR_SUCCESS )
623             res = r;
624     }
625     return res;
626 }
627 
628 static UINT try_query( MSIHANDLE hdb, LPCSTR szQuery )
629 {
630     return try_query_param( hdb, szQuery, 0 );
631 }
632 
633 static UINT try_insert_query( MSIHANDLE hdb, LPCSTR szQuery )
634 {
635     MSIHANDLE hrec = 0;
636     UINT r;
637 
638     hrec = MsiCreateRecord( 1 );
639     MsiRecordSetStringA( hrec, 1, "Hello");
640 
641     r = try_query_param( hdb, szQuery, hrec );
642 
643     MsiCloseHandle( hrec );
644     return r;
645 }
646 
647 static void test_msibadqueries(void)
648 {
649     MSIHANDLE hdb = 0;
650     UINT r;
651 
652     DeleteFileA(msifile);
653 
654     /* just MsiOpenDatabase should not create a file */
655     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
656     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
657 
658     r = MsiDatabaseCommit( hdb );
659     ok(r == ERROR_SUCCESS , "Failed to commit database\n");
660 
661     r = MsiCloseHandle( hdb );
662     ok(r == ERROR_SUCCESS , "Failed to close database\n");
663 
664     /* open it readonly */
665     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_READONLY, &hdb );
666     ok(r == ERROR_SUCCESS , "Failed to open database r/o\n");
667 
668     /* add a table to it */
669     r = try_query( hdb, "select * from _Tables");
670     ok(r == ERROR_SUCCESS , "query 1 failed\n");
671 
672     r = MsiCloseHandle( hdb );
673     ok(r == ERROR_SUCCESS , "Failed to close database r/o\n");
674 
675     /* open it read/write */
676     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_TRANSACT, &hdb );
677     ok(r == ERROR_SUCCESS , "Failed to open database r/w\n");
678 
679     /* a bunch of test queries that fail with the native MSI */
680 
681     r = try_query( hdb, "CREATE TABLE");
682     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2a return code\n");
683 
684     r = try_query( hdb, "CREATE TABLE `a`");
685     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2b return code\n");
686 
687     r = try_query( hdb, "CREATE TABLE `a` ()");
688     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2c return code\n");
689 
690     r = try_query( hdb, "CREATE TABLE `a` (`b`)");
691     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2d return code\n");
692 
693     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) )");
694     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2e return code\n");
695 
696     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL)");
697     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2f return code\n");
698 
699     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY)");
700     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2g return code\n");
701 
702     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY)");
703     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2h return code\n");
704 
705     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY)");
706     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2i return code\n");
707 
708     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY 'b')");
709     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2j return code\n");
710 
711     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY `b')");
712     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2k return code\n");
713 
714     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY `b')");
715     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2l return code\n");
716 
717     r = try_query( hdb, "CREATE TABLE `a` (`b` CHA(72) NOT NULL PRIMARY KEY `b`)");
718     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2m return code\n");
719 
720     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(-1) NOT NULL PRIMARY KEY `b`)");
721     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2n return code\n");
722 
723     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(720) NOT NULL PRIMARY KEY `b`)");
724     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2o return code\n");
725 
726     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL KEY `b`)");
727     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2p return code\n");
728 
729     r = try_query( hdb, "CREATE TABLE `a` (`` CHAR(72) NOT NULL PRIMARY KEY `b`)");
730     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2p return code\n");
731 
732     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY `b`)");
733     ok(r == ERROR_SUCCESS , "valid query 2z failed\n");
734 
735     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY `b`)");
736     ok(r == ERROR_BAD_QUERY_SYNTAX , "created same table again\n");
737 
738     r = try_query( hdb, "CREATE TABLE `aa` (`b` CHAR(72) NOT NULL, `c` "
739           "CHAR(72), `d` CHAR(255) NOT NULL LOCALIZABLE PRIMARY KEY `b`)");
740     ok(r == ERROR_SUCCESS , "query 4 failed\n");
741 
742     r = MsiDatabaseCommit( hdb );
743     ok(r == ERROR_SUCCESS , "Failed to commit database after write\n");
744 
745     r = try_query( hdb, "CREATE TABLE `blah` (`foo` CHAR(72) NOT NULL "
746                           "PRIMARY KEY `foo`)");
747     ok(r == ERROR_SUCCESS , "query 4 failed\n");
748 
749     r = try_insert_query( hdb, "insert into a  ( `b` ) VALUES ( ? )");
750     ok(r == ERROR_SUCCESS , "failed to insert record in db\n");
751 
752     r = MsiDatabaseCommit( hdb );
753     ok(r == ERROR_SUCCESS , "Failed to commit database after write\n");
754 
755     r = try_query( hdb, "CREATE TABLE `boo` (`foo` CHAR(72) NOT NULL "
756                           "PRIMARY KEY `ba`)");
757     ok(r != ERROR_SUCCESS , "query 5 succeeded\n");
758 
759     r = try_query( hdb,"CREATE TABLE `bee` (`foo` CHAR(72) NOT NULL )");
760     ok(r != ERROR_SUCCESS , "query 6 succeeded\n");
761 
762     r = try_query( hdb, "CREATE TABLE `temp` (`t` CHAR(72) NOT NULL "
763                           "PRIMARY KEY `t`)");
764     ok(r == ERROR_SUCCESS , "query 7 failed\n");
765 
766     r = try_query( hdb, "CREATE TABLE `c` (`b` CHAR NOT NULL PRIMARY KEY `b`)");
767     ok(r == ERROR_SUCCESS , "query 8 failed\n");
768 
769     r = try_query( hdb, "select * from c");
770     ok(r == ERROR_SUCCESS , "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'");
779     ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
780 
781     r = try_query( hdb, "select * from ''");
782     ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
783 
784     r = try_query( hdb, "select * from c where b = x");
785     ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
786 
787     r = try_query( hdb, "select * from c where b = \"x\"");
788     ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
789 
790     r = try_query( hdb, "select * from c where b = 'x'");
791     ok(r == ERROR_SUCCESS, "query failed\n");
792 
793     r = try_query( hdb, "select * from c where b = '\"x'");
794     ok(r == ERROR_SUCCESS, "query failed\n");
795 
796     if (0)  /* FIXME: this query causes trouble with other tests */
797     {
798         r = try_query( hdb, "select * from c where b = '\\\'x'");
799         ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
800     }
801 
802     r = try_query( hdb, "select * from 'c'");
803     ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
804 
805     r = try_query( hdb, "select `c`.`b` from `c` order by `c`.`order`");
806     ok( r == ERROR_BAD_QUERY_SYNTAX, "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_BAD_QUERY_SYNTAX, "query failed: %u\n", r );
813 
814     r = try_query( hdb, "select `c`.b from `c`");
815     ok( r == ERROR_SUCCESS, "query failed: %u\n", r );
816 
817     r = try_query( hdb, "select `c.`b` from `c`");
818     ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %u\n", r );
819 
820     r = try_query( hdb, "select c`.`b` from `c`");
821     ok( r == ERROR_SUCCESS, "query failed: %u\n", r );
822 
823     r = try_query( hdb, "select c.`b` from `c`");
824     ok( r == ERROR_SUCCESS, "query failed: %u\n", r );
825 
826     r = try_query( hdb, "select `c`.`b` from c`");
827     ok( r == ERROR_SUCCESS, "query failed: %u\n", r );
828 
829     r = try_query( hdb, "select `c`.`b` from `c");
830     ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %u\n", r );
831 
832     r = try_query( hdb, "select `c`.`b` from c");
833     ok( r == ERROR_SUCCESS, "query failed: %u\n", r );
834 
835     r = try_query( hdb, "CREATE TABLE `\5a` (`b` CHAR NOT NULL PRIMARY KEY `b`)" );
836     ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
837 
838     r = try_query( hdb, "SELECT * FROM \5a" );
839     ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
840 
841     r = try_query( hdb, "CREATE TABLE `a\5` (`b` CHAR NOT NULL PRIMARY KEY `b`)" );
842     ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
843 
844     r = try_query( hdb, "SELECT * FROM a\5" );
845     ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
846 
847     r = try_query( hdb, "CREATE TABLE `-a` (`b` CHAR NOT NULL PRIMARY KEY `b`)" );
848     ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
849 
850     r = try_query( hdb, "SELECT * FROM -a" );
851     todo_wine ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
852 
853     r = try_query( hdb, "CREATE TABLE `a-` (`b` CHAR NOT NULL PRIMARY KEY `b`)" );
854     ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
855 
856     r = try_query( hdb, "SELECT * FROM a-" );
857     ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
858 
859     r = MsiCloseHandle( hdb );
860     ok(r == ERROR_SUCCESS , "Failed to close database transact\n");
861 
862     r = DeleteFileA( msifile );
863     ok(r == TRUE, "file didn't exist after commit\n");
864 }
865 
866 static void test_viewmodify(void)
867 {
868     MSIHANDLE hdb = 0, hview = 0, hrec = 0;
869     UINT r;
870     MSIDBERROR err;
871     const char *query;
872     char buffer[0x100];
873     DWORD sz;
874 
875     DeleteFileA(msifile);
876 
877     /* just MsiOpenDatabase should not create a file */
878     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
879     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
880 
881     query = "CREATE TABLE `phone` ( "
882             "`id` INT, `name` CHAR(32), `number` CHAR(32) "
883             "PRIMARY KEY `id`)";
884     r = run_query( hdb, 0, query );
885     ok(r == ERROR_SUCCESS, "query failed\n");
886 
887     query = "CREATE TABLE `_Validation` ( "
888             "`Table` CHAR(32) NOT NULL, `Column` CHAR(32) NOT NULL, "
889             "`Nullable` CHAR(4) NOT NULL, `MinValue` INT, `MaxValue` INT, "
890             "`KeyTable` CHAR(255), `KeyColumn` SHORT, `Category` CHAR(32), "
891             "`Set` CHAR(255), `Description` CHAR(255) PRIMARY KEY `Table`, `Column`)";
892     r = run_query( hdb, 0, query );
893     ok(r == ERROR_SUCCESS, "query failed\n");
894 
895     query = "INSERT INTO `_Validation` ( `Table`, `Column`, `Nullable` ) "
896             "VALUES('phone', 'id', 'N')";
897     r = run_query( hdb, 0, query );
898     ok(r == ERROR_SUCCESS, "query failed\n");
899 
900     query = "SELECT * FROM `phone`";
901     r = MsiDatabaseOpenViewA(hdb, query, &hview);
902     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
903 
904     /* check what the error function reports without doing anything */
905     sz = sizeof(buffer);
906     strcpy(buffer, "x");
907     err = MsiViewGetErrorA( hview, buffer, &sz );
908     ok(err == MSIDBERROR_NOERROR, "got %d\n", err);
909     ok(!buffer[0], "got \"%s\"\n", buffer);
910     ok(sz == 0, "got size %lu\n", sz);
911 
912     r = MsiViewExecute(hview, 0);
913     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
914 
915     /* try some invalid records */
916     r = MsiViewModify(hview, MSIMODIFY_INSERT, 0 );
917     ok(r == ERROR_INVALID_HANDLE, "MsiViewModify failed\n");
918     r = MsiViewModify(hview, -1, 0 );
919     ok(r == ERROR_INVALID_HANDLE, "MsiViewModify failed\n");
920 
921     /* try an small record */
922     hrec = MsiCreateRecord(1);
923     r = MsiViewModify(hview, -1, hrec );
924     ok(r == ERROR_INVALID_DATA, "MsiViewModify failed\n");
925 
926     sz = sizeof(buffer);
927     strcpy(buffer, "x");
928     err = MsiViewGetErrorA( hview, buffer, &sz );
929     ok(err == MSIDBERROR_NOERROR, "got %d\n", err);
930     ok(!buffer[0], "got \"%s\"\n", buffer);
931     ok(sz == 0, "got size %lu\n", sz);
932 
933     r = MsiCloseHandle(hrec);
934     ok(r == ERROR_SUCCESS, "failed to close record\n");
935 
936     /* insert a valid record */
937     hrec = MsiCreateRecord(3);
938 
939     r = MsiRecordSetInteger(hrec, 1, 1);
940     ok(r == ERROR_SUCCESS, "failed to set integer\n");
941     r = MsiRecordSetStringA(hrec, 2, "bob");
942     ok(r == ERROR_SUCCESS, "failed to set string\n");
943     r = MsiRecordSetStringA(hrec, 3, "7654321");
944     ok(r == ERROR_SUCCESS, "failed to set string\n");
945 
946     r = MsiViewExecute(hview, 0);
947     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
948     r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec );
949     ok(r == ERROR_SUCCESS, "MsiViewModify failed\n");
950 
951     /* validate it */
952     r = MsiViewExecute(hview, 0);
953     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
954 
955     r = MsiViewModify(hview, MSIMODIFY_VALIDATE_NEW, hrec );
956     ok(r == ERROR_INVALID_DATA, "MsiViewModify failed %u\n", r);
957 
958     sz = sizeof(buffer);
959     strcpy(buffer, "x");
960     err = MsiViewGetErrorA( hview, buffer, &sz );
961     ok(err == MSIDBERROR_DUPLICATEKEY, "got %d\n", err);
962     ok(!strcmp(buffer, "id"), "got \"%s\"\n", buffer);
963     ok(sz == 2, "got size %lu\n", sz);
964 
965     /* insert the same thing again */
966     r = MsiViewExecute(hview, 0);
967     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
968 
969     /* should fail ... */
970     r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec );
971     ok(r == ERROR_FUNCTION_FAILED, "MsiViewModify failed\n");
972 
973     /* try to merge the same record */
974     r = MsiViewExecute(hview, 0);
975     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
976     r = MsiViewModify(hview, MSIMODIFY_MERGE, hrec );
977     ok(r == ERROR_SUCCESS, "MsiViewModify failed\n");
978 
979     r = MsiCloseHandle(hrec);
980     ok(r == ERROR_SUCCESS, "failed to close record\n");
981 
982     /* try merging a new record */
983     hrec = MsiCreateRecord(3);
984 
985     r = MsiRecordSetInteger(hrec, 1, 10);
986     ok(r == ERROR_SUCCESS, "failed to set integer\n");
987     r = MsiRecordSetStringA(hrec, 2, "pepe");
988     ok(r == ERROR_SUCCESS, "failed to set string\n");
989     r = MsiRecordSetStringA(hrec, 3, "7654321");
990     ok(r == ERROR_SUCCESS, "failed to set string\n");
991 
992     r = MsiViewModify(hview, MSIMODIFY_MERGE, hrec );
993     ok(r == ERROR_SUCCESS, "MsiViewModify failed\n");
994     r = MsiViewExecute(hview, 0);
995     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
996 
997     r = MsiCloseHandle(hrec);
998     ok(r == ERROR_SUCCESS, "failed to close record\n");
999 
1000     r = MsiViewClose(hview);
1001     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
1002     r = MsiCloseHandle(hview);
1003     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
1004 
1005     query = "SELECT * FROM `phone`";
1006     r = MsiDatabaseOpenViewA(hdb, query, &hview);
1007     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
1008 
1009     r = MsiViewExecute(hview, 0);
1010     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
1011 
1012     r = MsiViewFetch(hview, &hrec);
1013     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
1014     check_record(hrec, 3, "1", "bob", "7654321");
1015 
1016     /* update the view, non-primary key */
1017     r = MsiRecordSetStringA(hrec, 3, "3141592");
1018     ok(r == ERROR_SUCCESS, "MsiRecordSetString failed\n");
1019 
1020     r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
1021     ok(r == ERROR_SUCCESS, "MsiViewModify failed\n");
1022 
1023     /* do it again */
1024     r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
1025     ok(r == ERROR_SUCCESS, "MsiViewModify failed: %d\n", r);
1026 
1027     /* update the view, primary key */
1028     r = MsiRecordSetInteger(hrec, 1, 5);
1029     ok(r == ERROR_SUCCESS, "MsiRecordSetInteger failed\n");
1030 
1031     r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
1032     ok(r == ERROR_FUNCTION_FAILED, "MsiViewModify failed\n");
1033 
1034     r = MsiCloseHandle(hrec);
1035     ok(r == ERROR_SUCCESS, "failed to close record\n");
1036 
1037     r = MsiViewClose(hview);
1038     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
1039     r = MsiCloseHandle(hview);
1040     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
1041 
1042     query = "SELECT * FROM `phone`";
1043     r = MsiDatabaseOpenViewA(hdb, query, &hview);
1044     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
1045 
1046     r = MsiViewExecute(hview, 0);
1047     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
1048 
1049     r = MsiViewFetch(hview, &hrec);
1050     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
1051     check_record(hrec, 3, "1", "bob", "3141592");
1052     r = MsiCloseHandle(hrec);
1053     ok(r == ERROR_SUCCESS, "failed to close record\n");
1054 
1055     /* use a record that doesn't come from a view fetch */
1056     hrec = MsiCreateRecord(3);
1057     ok(hrec != 0, "MsiCreateRecord failed\n");
1058 
1059     r = MsiRecordSetInteger(hrec, 1, 3);
1060     ok(r == ERROR_SUCCESS, "failed to set integer\n");
1061     r = MsiRecordSetStringA(hrec, 2, "jane");
1062     ok(r == ERROR_SUCCESS, "failed to set string\n");
1063     r = MsiRecordSetStringA(hrec, 3, "112358");
1064     ok(r == ERROR_SUCCESS, "failed to set string\n");
1065 
1066     r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
1067     ok(r == ERROR_FUNCTION_FAILED, "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
1068 
1069     r = MsiCloseHandle(hrec);
1070     ok(r == ERROR_SUCCESS, "failed to close record\n");
1071 
1072     /* use a record that doesn't come from a view fetch, primary key matches */
1073     hrec = MsiCreateRecord(3);
1074     ok(hrec != 0, "MsiCreateRecord failed\n");
1075 
1076     r = MsiRecordSetInteger(hrec, 1, 1);
1077     ok(r == ERROR_SUCCESS, "failed to set integer\n");
1078     r = MsiRecordSetStringA(hrec, 2, "jane");
1079     ok(r == ERROR_SUCCESS, "failed to set string\n");
1080     r = MsiRecordSetStringA(hrec, 3, "112358");
1081     ok(r == ERROR_SUCCESS, "failed to set string\n");
1082 
1083     r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
1084     ok(r == ERROR_FUNCTION_FAILED, "MsiViewModify failed\n");
1085 
1086     r = MsiCloseHandle(hrec);
1087     ok(r == ERROR_SUCCESS, "failed to close record\n");
1088 
1089     hrec = MsiCreateRecord(3);
1090 
1091     r = MsiRecordSetInteger(hrec, 1, 2);
1092     ok(r == ERROR_SUCCESS, "failed to set integer\n");
1093     r = MsiRecordSetStringA(hrec, 2, "nick");
1094     ok(r == ERROR_SUCCESS, "failed to set string\n");
1095     r = MsiRecordSetStringA(hrec, 3, "141421");
1096     ok(r == ERROR_SUCCESS, "failed to set string\n");
1097 
1098     r = MsiViewExecute(hview, 0);
1099     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
1100     r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec );
1101     ok(r == ERROR_SUCCESS, "MsiViewModify failed\n");
1102 
1103     r = MsiCloseHandle(hrec);
1104     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
1105     r = MsiViewClose(hview);
1106     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
1107     r = MsiCloseHandle(hview);
1108     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
1109 
1110     query = "SELECT * FROM `phone` WHERE `id` = 1";
1111     r = MsiDatabaseOpenViewA(hdb, query, &hview);
1112     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
1113     r = MsiViewExecute(hview, 0);
1114     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
1115     r = MsiViewFetch(hview, &hrec);
1116     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
1117 
1118     /* change the id to match the second row */
1119     r = MsiRecordSetInteger(hrec, 1, 2);
1120     ok(r == ERROR_SUCCESS, "failed to set integer\n");
1121     r = MsiRecordSetStringA(hrec, 2, "jerry");
1122     ok(r == ERROR_SUCCESS, "failed to set string\n");
1123 
1124     r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
1125     ok(r == ERROR_FUNCTION_FAILED, "MsiViewModify failed\n");
1126 
1127     r = MsiCloseHandle(hrec);
1128     ok(r == ERROR_SUCCESS, "failed to close record\n");
1129     r = MsiViewClose(hview);
1130     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
1131     r = MsiCloseHandle(hview);
1132     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
1133 
1134     /* broader search */
1135     query = "SELECT * FROM `phone` ORDER BY `id`";
1136     r = MsiDatabaseOpenViewA(hdb, query, &hview);
1137     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
1138     r = MsiViewExecute(hview, 0);
1139     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
1140     r = MsiViewFetch(hview, &hrec);
1141     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
1142 
1143     /* change the id to match the second row */
1144     r = MsiRecordSetInteger(hrec, 1, 2);
1145     ok(r == ERROR_SUCCESS, "failed to set integer\n");
1146     r = MsiRecordSetStringA(hrec, 2, "jerry");
1147     ok(r == ERROR_SUCCESS, "failed to set string\n");
1148 
1149     r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
1150     ok(r == ERROR_FUNCTION_FAILED, "MsiViewModify failed\n");
1151 
1152     r = MsiCloseHandle(hrec);
1153     ok(r == ERROR_SUCCESS, "failed to close record\n");
1154     r = MsiViewClose(hview);
1155     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
1156     r = MsiCloseHandle(hview);
1157     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
1158 
1159     r = MsiCloseHandle( hdb );
1160     ok(r == ERROR_SUCCESS, "MsiOpenDatabase close failed\n");
1161 }
1162 
1163 static MSIHANDLE create_db(void)
1164 {
1165     MSIHANDLE hdb = 0;
1166     UINT res;
1167 
1168     DeleteFileW(msifileW);
1169 
1170     /* create an empty database */
1171     res = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb );
1172     ok( res == ERROR_SUCCESS , "Failed to create database\n" );
1173     if( res != ERROR_SUCCESS )
1174         return hdb;
1175 
1176     res = MsiDatabaseCommit( hdb );
1177     ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
1178 
1179     return hdb;
1180 }
1181 
1182 static void test_getcolinfo(void)
1183 {
1184     MSIHANDLE hdb, hview = 0, rec = 0;
1185     UINT r;
1186 
1187     /* create an empty db */
1188     hdb = create_db();
1189     ok( hdb, "failed to create db\n");
1190 
1191     /* tables should be present */
1192     r = MsiDatabaseOpenViewA(hdb, "select Name from _Tables", &hview);
1193     ok( r == ERROR_SUCCESS, "failed to open query\n");
1194 
1195     r = MsiViewExecute(hview, 0);
1196     ok( r == ERROR_SUCCESS, "failed to execute query\n");
1197 
1198     /* check that NAMES works */
1199     rec = 0;
1200     r = MsiViewGetColumnInfo( hview, MSICOLINFO_NAMES, &rec );
1201     ok( r == ERROR_SUCCESS, "failed to get names\n");
1202     check_record(rec, 1, "Name");
1203     r = MsiCloseHandle( rec );
1204     ok( r == ERROR_SUCCESS, "failed to close record handle\n");
1205 
1206     /* check that TYPES works */
1207     rec = 0;
1208     r = MsiViewGetColumnInfo( hview, MSICOLINFO_TYPES, &rec );
1209     ok( r == ERROR_SUCCESS, "failed to get names\n");
1210     check_record(rec, 1, "s64");
1211     r = MsiCloseHandle( rec );
1212     ok( r == ERROR_SUCCESS, "failed to close record handle\n");
1213 
1214     /* check that invalid values fail */
1215     rec = 0;
1216     r = MsiViewGetColumnInfo( hview, 100, &rec );
1217     ok( r == ERROR_INVALID_PARAMETER, "wrong error code\n");
1218     ok( rec == 0, "returned a record\n");
1219 
1220     r = MsiViewGetColumnInfo( hview, MSICOLINFO_TYPES, NULL );
1221     ok( r == ERROR_INVALID_PARAMETER, "wrong error code\n");
1222 
1223     r = MsiViewGetColumnInfo( 0, MSICOLINFO_TYPES, &rec );
1224     ok( r == ERROR_INVALID_HANDLE, "wrong error code\n");
1225 
1226     r = MsiViewClose(hview);
1227     ok( r == ERROR_SUCCESS, "failed to close view\n");
1228     r = MsiCloseHandle(hview);
1229     ok( r == ERROR_SUCCESS, "failed to close view handle\n");
1230     r = MsiCloseHandle(hdb);
1231     ok( r == ERROR_SUCCESS, "failed to close database\n");
1232 }
1233 
1234 static MSIHANDLE get_column_info(MSIHANDLE hdb, const char *query, MSICOLINFO type)
1235 {
1236     MSIHANDLE hview = 0, rec = 0;
1237     UINT r;
1238 
1239     r = MsiDatabaseOpenViewA(hdb, query, &hview);
1240     if( r != ERROR_SUCCESS )
1241         return r;
1242 
1243     r = MsiViewExecute(hview, 0);
1244     if( r == ERROR_SUCCESS )
1245     {
1246         MsiViewGetColumnInfo( hview, type, &rec );
1247     }
1248     MsiViewClose(hview);
1249     MsiCloseHandle(hview);
1250     return rec;
1251 }
1252 
1253 static UINT get_columns_table_type(MSIHANDLE hdb, const char *table, UINT field)
1254 {
1255     MSIHANDLE hview = 0, rec = 0;
1256     UINT r, type = 0;
1257     char query[0x100];
1258 
1259     sprintf(query, "select * from `_Columns` where  `Table` = '%s'", table );
1260 
1261     r = MsiDatabaseOpenViewA(hdb, query, &hview);
1262     if( r != ERROR_SUCCESS )
1263         return r;
1264 
1265     r = MsiViewExecute(hview, 0);
1266     if( r == ERROR_SUCCESS )
1267     {
1268         while (1)
1269         {
1270             r = MsiViewFetch( hview, &rec );
1271             if( r != ERROR_SUCCESS)
1272                 break;
1273             r = MsiRecordGetInteger( rec, 2 );
1274             if (r == field)
1275                 type = MsiRecordGetInteger( rec, 4 );
1276             MsiCloseHandle( rec );
1277         }
1278     }
1279     MsiViewClose(hview);
1280     MsiCloseHandle(hview);
1281     return type;
1282 }
1283 
1284 static void test_viewgetcolumninfo(void)
1285 {
1286     MSIHANDLE hdb = 0, rec;
1287     UINT r;
1288 
1289     hdb = create_db();
1290     ok( hdb, "failed to create db\n");
1291 
1292     r = run_query( hdb, 0,
1293             "CREATE TABLE `Properties` "
1294             "( `Property` CHAR(255), "
1295             "  `Value` CHAR(1), "
1296             "  `Intvalue` INT, "
1297             "  `Integervalue` INTEGER, "
1298             "  `Shortvalue` SHORT, "
1299             "  `Longvalue` LONG, "
1300             "  `Longcharvalue` LONGCHAR, "
1301             "  `Charvalue` CHAR, "
1302             "  `Localizablevalue` CHAR LOCALIZABLE "
1303             "  PRIMARY KEY `Property`)" );
1304     ok( r == ERROR_SUCCESS , "Failed to create table\n" );
1305 
1306     /* check the column types */
1307     rec = get_column_info( hdb, "select * from `Properties`", MSICOLINFO_TYPES );
1308     ok( rec, "failed to get column info record\n" );
1309     check_record(rec, 9, "S255", "S1", "I2", "I2", "I2", "I4", "S0", "S0", "L0");
1310     MsiCloseHandle( rec );
1311 
1312     /* check the type in _Columns */
1313     ok( 0x3dff == get_columns_table_type(hdb, "Properties", 1 ), "_columns table wrong\n");
1314     ok( 0x1d01 == get_columns_table_type(hdb, "Properties", 2 ), "_columns table wrong\n");
1315     ok( 0x1502 == get_columns_table_type(hdb, "Properties", 3 ), "_columns table wrong\n");
1316     ok( 0x1502 == get_columns_table_type(hdb, "Properties", 4 ), "_columns table wrong\n");
1317     ok( 0x1502 == get_columns_table_type(hdb, "Properties", 5 ), "_columns table wrong\n");
1318     ok( 0x1104 == get_columns_table_type(hdb, "Properties", 6 ), "_columns table wrong\n");
1319     ok( 0x1d00 == get_columns_table_type(hdb, "Properties", 7 ), "_columns table wrong\n");
1320     ok( 0x1d00 == get_columns_table_type(hdb, "Properties", 8 ), "_columns table wrong\n");
1321     ok( 0x1f00 == get_columns_table_type(hdb, "Properties", 9 ), "_columns table wrong\n");
1322 
1323     /* now try the names */
1324     rec = get_column_info( hdb, "select * from `Properties`", MSICOLINFO_NAMES );
1325     ok( rec, "failed to get column info record\n" );
1326     check_record(rec, 9, "Property", "Value", "Intvalue", "Integervalue", "Shortvalue",
1327             "Longvalue", "Longcharvalue", "Charvalue", "Localizablevalue");
1328     MsiCloseHandle( rec );
1329 
1330     r = run_query( hdb, 0,
1331             "CREATE TABLE `Binary` "
1332             "( `Name` CHAR(255), `Data` OBJECT  PRIMARY KEY `Name`)" );
1333     ok( r == ERROR_SUCCESS , "Failed to create table\n" );
1334 
1335     /* check the column types */
1336     rec = get_column_info( hdb, "select * from `Binary`", MSICOLINFO_TYPES );
1337     ok( rec, "failed to get column info record\n" );
1338     check_record(rec, 2, "S255", "V0");
1339     MsiCloseHandle( rec );
1340 
1341     /* check the type in _Columns */
1342     ok( 0x3dff == get_columns_table_type(hdb, "Binary", 1 ), "_columns table wrong\n");
1343     ok( 0x1900 == get_columns_table_type(hdb, "Binary", 2 ), "_columns table wrong\n");
1344 
1345     /* now try the names */
1346     rec = get_column_info( hdb, "select * from `Binary`", MSICOLINFO_NAMES );
1347     ok( rec, "failed to get column info record\n" );
1348     check_record(rec, 2, "Name", "Data");
1349     MsiCloseHandle( rec );
1350 
1351     r = run_query( hdb, 0,
1352             "CREATE TABLE `UIText` "
1353             "( `Key` CHAR(72) NOT NULL, `Text` CHAR(255) LOCALIZABLE PRIMARY KEY `Key`)" );
1354     ok( r == ERROR_SUCCESS , "Failed to create table\n" );
1355 
1356     ok( 0x2d48 == get_columns_table_type(hdb, "UIText", 1 ), "_columns table wrong\n");
1357     ok( 0x1fff == get_columns_table_type(hdb, "UIText", 2 ), "_columns table wrong\n");
1358 
1359     rec = get_column_info( hdb, "select * from `UIText`", MSICOLINFO_NAMES );
1360     ok( rec, "failed to get column info record\n" );
1361     check_record(rec, 2, "Key", "Text");
1362     MsiCloseHandle( rec );
1363 
1364     rec = get_column_info( hdb, "select * from `UIText`", MSICOLINFO_TYPES );
1365     ok( rec, "failed to get column info record\n" );
1366     check_record(rec, 2, "s72", "L255");
1367     MsiCloseHandle( rec );
1368 
1369     MsiCloseHandle( hdb );
1370 }
1371 
1372 static void test_msiexport(void)
1373 {
1374     MSIHANDLE hdb = 0, hview = 0;
1375     UINT r;
1376     const char *query;
1377     char path[MAX_PATH];
1378     const char file[] = "phone.txt";
1379     HANDLE handle;
1380     char buffer[0x100];
1381     DWORD length;
1382     const char expected[] =
1383         "id\tname\tnumber\r\n"
1384         "I2\tS32\tS32\r\n"
1385         "phone\tid\r\n"
1386         "1\tAbe\t8675309\r\n";
1387 
1388     DeleteFileW(msifileW);
1389 
1390     /* just MsiOpenDatabase should not create a file */
1391     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
1392     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
1393 
1394     /* create a table */
1395     query = "CREATE TABLE `phone` ( "
1396             "`id` INT, `name` CHAR(32), `number` CHAR(32) "
1397             "PRIMARY KEY `id`)";
1398     r = MsiDatabaseOpenViewA(hdb, query, &hview);
1399     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
1400     r = MsiViewExecute(hview, 0);
1401     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
1402     r = MsiViewClose(hview);
1403     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
1404     r = MsiCloseHandle(hview);
1405     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
1406 
1407     /* insert a value into it */
1408     query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
1409         "VALUES('1', 'Abe', '8675309')";
1410     r = MsiDatabaseOpenViewA(hdb, query, &hview);
1411     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
1412     r = MsiViewExecute(hview, 0);
1413     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
1414     r = MsiViewClose(hview);
1415     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
1416     r = MsiCloseHandle(hview);
1417     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
1418 
1419     GetCurrentDirectoryA(MAX_PATH, path);
1420 
1421     r = MsiDatabaseExportA(hdb, "phone", path, file);
1422     ok(r == ERROR_SUCCESS, "MsiDatabaseExport failed\n");
1423 
1424     MsiCloseHandle(hdb);
1425 
1426     lstrcatA(path, "\\");
1427     lstrcatA(path, file);
1428 
1429     /* check the data that was written */
1430     length = 0;
1431     memset(buffer, 0, sizeof buffer);
1432     handle = CreateFileA(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
1433     if (handle != INVALID_HANDLE_VALUE)
1434     {
1435         ReadFile(handle, buffer, sizeof buffer, &length, NULL);
1436         CloseHandle(handle);
1437         DeleteFileA(path);
1438     }
1439     else
1440         ok(0, "failed to open file %s\n", path);
1441 
1442     ok( length == strlen(expected), "length of data wrong\n");
1443     ok( !lstrcmpA(buffer, expected), "data doesn't match\n");
1444     DeleteFileA(msifile);
1445 }
1446 
1447 static void test_longstrings(void)
1448 {
1449     const char insert_query[] =
1450         "INSERT INTO `strings` ( `id`, `val` ) VALUES('1', 'Z')";
1451     char *str;
1452     MSIHANDLE hdb = 0, hview = 0, hrec = 0;
1453     DWORD len;
1454     UINT r;
1455     const DWORD STRING_LENGTH = 0x10005;
1456 
1457     DeleteFileW(msifileW);
1458     /* just MsiOpenDatabase should not create a file */
1459     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
1460     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
1461 
1462     /* create a table */
1463     r = try_query( hdb,
1464         "CREATE TABLE `strings` ( `id` INT, `val` CHAR(0) PRIMARY KEY `id`)");
1465     ok(r == ERROR_SUCCESS, "query failed\n");
1466 
1467     /* try to insert a very long string */
1468     str = malloc(STRING_LENGTH + sizeof insert_query);
1469     len = strchr(insert_query, 'Z') - insert_query;
1470     strcpy(str, insert_query);
1471     memset(str+len, 'Z', STRING_LENGTH);
1472     strcpy(str+len+STRING_LENGTH, insert_query+len+1);
1473     r = try_query( hdb, str );
1474     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
1475     free(str);
1476 
1477     r = MsiDatabaseCommit(hdb);
1478     ok(r == ERROR_SUCCESS, "MsiDatabaseCommit failed\n");
1479     MsiCloseHandle(hdb);
1480 
1481     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_READONLY, &hdb);
1482     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
1483 
1484     r = MsiDatabaseOpenViewA(hdb, "select * from `strings` where `id` = 1", &hview);
1485     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
1486 
1487     r = MsiViewExecute(hview, 0);
1488     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
1489 
1490     r = MsiViewFetch(hview, &hrec);
1491     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
1492 
1493     MsiViewClose(hview);
1494     MsiCloseHandle(hview);
1495 
1496     r = MsiRecordGetStringA(hrec, 2, NULL, &len);
1497     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
1498     ok(len == STRING_LENGTH, "string length wrong\n");
1499 
1500     MsiCloseHandle(hrec);
1501     MsiCloseHandle(hdb);
1502     DeleteFileA(msifile);
1503 }
1504 
1505 static void create_file_data(LPCSTR name, LPCSTR data, DWORD size)
1506 {
1507     HANDLE file;
1508     DWORD written;
1509 
1510     file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
1511     if (file == INVALID_HANDLE_VALUE)
1512         return;
1513 
1514     WriteFile(file, data, strlen(data), &written, NULL);
1515     WriteFile(file, "\n", strlen("\n"), &written, NULL);
1516 
1517     if (size)
1518     {
1519         SetFilePointer(file, size, NULL, FILE_BEGIN);
1520         SetEndOfFile(file);
1521     }
1522 
1523     CloseHandle(file);
1524 }
1525 
1526 #define create_file(name) create_file_data(name, name, 0)
1527 
1528 static void test_streamtable(void)
1529 {
1530     MSIHANDLE hdb = 0, rec, view, hsi;
1531     char file[MAX_PATH];
1532     char buf[MAX_PATH];
1533     DWORD size;
1534     UINT r;
1535 
1536     hdb = create_db();
1537     ok( hdb, "failed to create db\n");
1538 
1539     r = run_query( hdb, 0,
1540             "CREATE TABLE `Properties` "
1541             "( `Property` CHAR(255), `Value` CHAR(1)  PRIMARY KEY `Property`)" );
1542     ok( r == ERROR_SUCCESS , "Failed to create table\n" );
1543 
1544     r = run_query( hdb, 0,
1545             "INSERT INTO `Properties` "
1546             "( `Value`, `Property` ) VALUES ( 'Prop', 'value' )" );
1547     ok( r == ERROR_SUCCESS, "Failed to add to table\n" );
1548 
1549     r = MsiDatabaseCommit( hdb );
1550     ok( r == ERROR_SUCCESS , "Failed to commit database\n" );
1551 
1552     MsiCloseHandle( hdb );
1553 
1554     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_TRANSACT, &hdb );
1555     ok( r == ERROR_SUCCESS , "Failed to open database\n" );
1556 
1557     /* check the column types */
1558     rec = get_column_info( hdb, "select * from `_Streams`", MSICOLINFO_TYPES );
1559     ok( rec, "failed to get column info record\n" );
1560     check_record(rec, 2, "s62", "V0");
1561     MsiCloseHandle( rec );
1562 
1563     /* now try the names */
1564     rec = get_column_info( hdb, "select * from `_Streams`", MSICOLINFO_NAMES );
1565     ok( rec, "failed to get column info record\n" );
1566     check_record(rec, 2, "Name", "Data");
1567     MsiCloseHandle( rec );
1568 
1569     r = MsiDatabaseOpenViewA( hdb,
1570             "SELECT * FROM `_Streams` WHERE `Name` = '\5SummaryInformation'", &view );
1571     ok( r == ERROR_SUCCESS, "Failed to open database view: %u\n", r );
1572 
1573     r = MsiViewExecute( view, 0 );
1574     ok( r == ERROR_SUCCESS, "Failed to execute view: %u\n", r );
1575 
1576     r = MsiViewFetch( view, &rec );
1577     ok( r == ERROR_NO_MORE_ITEMS, "Unexpected result: %u\n", r );
1578 
1579     MsiCloseHandle( rec );
1580     MsiViewClose( view );
1581     MsiCloseHandle( view );
1582 
1583     /* create a summary information stream */
1584     r = MsiGetSummaryInformationA( hdb, NULL, 1, &hsi );
1585     ok( r == ERROR_SUCCESS, "Failed to get summary information handle: %u\n", r );
1586 
1587     r = MsiSummaryInfoSetPropertyA( hsi, PID_SECURITY, VT_I4, 2, NULL, NULL );
1588     ok( r == ERROR_SUCCESS, "Failed to set property: %u\n", r );
1589 
1590     r = MsiSummaryInfoPersist( hsi );
1591     ok( r == ERROR_SUCCESS, "Failed to save summary information: %u\n", r );
1592 
1593     MsiCloseHandle( hsi );
1594 
1595     r = MsiDatabaseOpenViewA( hdb,
1596             "SELECT * FROM `_Streams` WHERE `Name` = '\5SummaryInformation'", &view );
1597     ok( r == ERROR_SUCCESS, "Failed to open database view: %u\n", r );
1598 
1599     r = MsiViewExecute( view, 0 );
1600     ok( r == ERROR_SUCCESS, "Failed to execute view: %u\n", r );
1601 
1602     r = MsiViewFetch( view, &rec );
1603     ok( r == ERROR_SUCCESS, "Unexpected result: %u\n", r );
1604 
1605     MsiCloseHandle( rec );
1606     MsiViewClose( view );
1607     MsiCloseHandle( view );
1608 
1609     /* insert a file into the _Streams table */
1610     create_file( "test.txt" );
1611 
1612     rec = MsiCreateRecord( 2 );
1613     MsiRecordSetStringA( rec, 1, "data" );
1614 
1615     r = MsiRecordSetStreamA( rec, 2, "test.txt" );
1616     ok( r == ERROR_SUCCESS, "Failed to add stream data to the record: %d\n", r);
1617 
1618     DeleteFileA("test.txt");
1619 
1620     r = MsiDatabaseOpenViewA( hdb,
1621             "INSERT INTO `_Streams` ( `Name`, `Data` ) VALUES ( ?, ? )", &view );
1622     ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r);
1623 
1624     r = MsiViewExecute( view, rec );
1625     ok( r == ERROR_SUCCESS, "Failed to execute view: %d\n", r);
1626 
1627     MsiCloseHandle( rec );
1628     MsiViewClose( view );
1629     MsiCloseHandle( view );
1630 
1631     /* insert another one */
1632     create_file( "test1.txt" );
1633 
1634     rec = MsiCreateRecord( 2 );
1635     MsiRecordSetStringA( rec, 1, "data1" );
1636 
1637     r = MsiRecordSetStreamA( rec, 2, "test1.txt" );
1638     ok( r == ERROR_SUCCESS, "Failed to add stream data to the record: %d\n", r);
1639 
1640     DeleteFileA("test1.txt");
1641 
1642     r = MsiDatabaseOpenViewA( hdb,
1643             "INSERT INTO `_Streams` ( `Name`, `Data` ) VALUES ( ?, ? )", &view );
1644     ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r);
1645 
1646     r = MsiViewExecute( view, rec );
1647     ok( r == ERROR_SUCCESS, "Failed to execute view: %d\n", r);
1648 
1649     MsiCloseHandle( rec );
1650     MsiViewClose( view );
1651     MsiCloseHandle( view );
1652 
1653     /* try again */
1654     create_file( "test1.txt" );
1655 
1656     rec = MsiCreateRecord( 2 );
1657     MsiRecordSetStringA( rec, 1, "data1" );
1658 
1659     r = MsiRecordSetStreamA( rec, 2, "test1.txt" );
1660     ok( r == ERROR_SUCCESS, "Failed to add stream data to the record: %d\n", r );
1661 
1662     DeleteFileA( "test1.txt" );
1663 
1664     r = MsiDatabaseOpenViewA( hdb,
1665             "INSERT INTO `_Streams` ( `Name`, `Data` ) VALUES ( ?, ? )", &view );
1666     ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r );
1667 
1668     r = MsiViewExecute( view, rec );
1669     ok( r == ERROR_FUNCTION_FAILED, "got %u\n", r );
1670 
1671     MsiCloseHandle( rec );
1672     MsiViewClose( view );
1673     MsiCloseHandle( view );
1674 
1675     r = MsiDatabaseOpenViewA( hdb,
1676             "SELECT `Name`, `Data` FROM `_Streams` WHERE `Name` = 'data'", &view );
1677     ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r);
1678 
1679     r = MsiViewExecute( view, 0 );
1680     ok( r == ERROR_SUCCESS, "Failed to execute view: %d\n", r);
1681 
1682     r = MsiViewFetch( view, &rec );
1683     ok( r == ERROR_SUCCESS, "Failed to fetch record: %d\n", r);
1684 
1685     size = MAX_PATH;
1686     r = MsiRecordGetStringA( rec, 1, file, &size );
1687     ok( r == ERROR_SUCCESS, "Failed to get string: %d\n", r);
1688     ok( !lstrcmpA(file, "data"), "Expected 'data', got %s\n", file);
1689 
1690     size = MAX_PATH;
1691     memset(buf, 0, MAX_PATH);
1692     r = MsiRecordReadStream( rec, 2, buf, &size );
1693     ok( r == ERROR_SUCCESS, "Failed to get stream: %d\n", r);
1694     ok( !lstrcmpA(buf, "test.txt\n"), "Expected 'test.txt\\n', got %s\n", buf);
1695 
1696     MsiCloseHandle( rec );
1697     MsiViewClose( view );
1698     MsiCloseHandle( view );
1699 
1700     r = MsiDatabaseOpenViewA( hdb,
1701             "SELECT `Name`, `Data` FROM `_Streams` WHERE `Name` = 'data1'", &view );
1702     ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r);
1703 
1704     r = MsiViewExecute( view, 0 );
1705     ok( r == ERROR_SUCCESS, "Failed to execute view: %d\n", r);
1706 
1707     r = MsiViewFetch( view, &rec );
1708     ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1709 
1710     size = MAX_PATH;
1711     r = MsiRecordGetStringA( rec, 1, file, &size );
1712     ok( r == ERROR_SUCCESS, "Failed to get string: %d\n", r);
1713     ok( !lstrcmpA(file, "data1"), "Expected 'data1', got %s\n", file);
1714 
1715     size = MAX_PATH;
1716     memset(buf, 0, MAX_PATH);
1717     r = MsiRecordReadStream( rec, 2, buf, &size );
1718     ok( r == ERROR_SUCCESS, "Failed to get stream: %d\n", r);
1719     ok( !lstrcmpA(buf, "test1.txt\n"), "Expected 'test1.txt\\n', got %s\n", buf);
1720 
1721     MsiCloseHandle( rec );
1722     MsiViewClose( view );
1723     MsiCloseHandle( view );
1724 
1725     /* perform an update */
1726     create_file( "test2.txt" );
1727     rec = MsiCreateRecord( 1 );
1728 
1729     r = MsiRecordSetStreamA( rec, 1, "test2.txt" );
1730     ok( r == ERROR_SUCCESS, "Failed to add stream data to the record: %d\n", r);
1731 
1732     DeleteFileA("test2.txt");
1733 
1734     r = MsiDatabaseOpenViewA( hdb,
1735             "UPDATE `_Streams` SET `Data` = ? WHERE `Name` = 'data1'", &view );
1736     ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r);
1737 
1738     r = MsiViewExecute( view, rec );
1739     ok( r == ERROR_SUCCESS, "Failed to execute view: %d\n", r);
1740 
1741     MsiCloseHandle( rec );
1742     MsiViewClose( view );
1743     MsiCloseHandle( view );
1744 
1745     r = MsiDatabaseOpenViewA( hdb,
1746             "SELECT `Name`, `Data` FROM `_Streams` WHERE `Name` = 'data1'", &view );
1747     ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r);
1748 
1749     r = MsiViewExecute( view, 0 );
1750     ok( r == ERROR_SUCCESS, "Failed to execute view: %d\n", r);
1751 
1752     r = MsiViewFetch( view, &rec );
1753     ok( r == ERROR_SUCCESS, "Failed to fetch record: %d\n", r);
1754 
1755     size = MAX_PATH;
1756     r = MsiRecordGetStringA( rec, 1, file, &size );
1757     ok( r == ERROR_SUCCESS, "Failed to get string: %d\n", r);
1758     ok( !lstrcmpA(file, "data1"), "Expected 'data1', got %s\n", file);
1759 
1760     size = MAX_PATH;
1761     memset(buf, 0, MAX_PATH);
1762     r = MsiRecordReadStream( rec, 2, buf, &size );
1763     ok( r == ERROR_SUCCESS, "Failed to get stream: %d\n", r);
1764     ok( !lstrcmpA(buf, "test2.txt\n"), "Expected 'test2.txt\\n', got %s\n", buf);
1765 
1766     MsiCloseHandle( rec );
1767     MsiViewClose( view );
1768     MsiCloseHandle( view );
1769     MsiCloseHandle( hdb );
1770     DeleteFileA(msifile);
1771 
1772     /* insert a file into the _Streams table */
1773     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATEDIRECT, &hdb);
1774     ok(r == ERROR_SUCCESS, "Failed to create database\n");
1775     ok( hdb, "failed to create db\n");
1776     create_file( "test.txt" );
1777     rec = MsiCreateRecord( 2 );
1778     MsiRecordSetStringA( rec, 1, "data" );
1779     r = MsiRecordSetStreamA( rec, 2, "test.txt" );
1780     ok( r == ERROR_SUCCESS, "Failed to add stream data to the record: %d\n", r);
1781     DeleteFileA("test.txt");
1782     r = MsiDatabaseOpenViewA( hdb,
1783             "INSERT INTO `_Streams` ( `Name`, `Data` ) VALUES ( ?, ? )", &view );
1784     ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r);
1785     r = MsiViewExecute( view, rec );
1786     ok( r == ERROR_SUCCESS, "Failed to execute view: %d\n", r);
1787     MsiCloseHandle( rec );
1788     MsiViewClose( view );
1789     MsiCloseHandle( view );
1790     r = MsiDatabaseCommit( hdb );
1791     ok( r == ERROR_SUCCESS , "Failed to commit database\n" );
1792 
1793     /* open a handle to the "data" stream */
1794     r = MsiDatabaseOpenViewA( hdb,
1795             "SELECT `Name`, `Data` FROM `_Streams` WHERE `Name` = 'data'", &view );
1796     ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r);
1797     r = MsiViewExecute( view, 0 );
1798     ok( r == ERROR_SUCCESS, "Failed to execute view: %d\n", r);
1799     r = MsiViewFetch( view, &rec );
1800     ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1801     MsiViewClose( view );
1802     MsiCloseHandle( view );
1803     /* read the stream while it still exists (normal case) */
1804     size = MAX_PATH;
1805     r = MsiRecordGetStringA( rec, 1, file, &size );
1806     ok( r == ERROR_SUCCESS, "Failed to get string: %d\n", r);
1807     ok( !lstrcmpA(file, "data"), "Expected 'data', got %s\n", file);
1808     size = MAX_PATH;
1809     memset(buf, 0, MAX_PATH);
1810     r = MsiRecordReadStream( rec, 2, buf, &size );
1811     ok( r == ERROR_SUCCESS, "Failed to get stream: %d\n", r);
1812     ok( !lstrcmpA(buf, "test.txt\n"), "Expected 'test.txt\\n', got '%s' (%lu)\n", buf, size);
1813     MsiCloseHandle( rec );
1814 
1815     /* open a handle to the "data" stream (and keep it open during removal) */
1816     r = MsiDatabaseOpenViewA( hdb,
1817             "SELECT `Name`, `Data` FROM `_Streams` WHERE `Name` = 'data'", &view );
1818     ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r);
1819     r = MsiViewExecute( view, 0 );
1820     ok( r == ERROR_SUCCESS, "Failed to execute view: %d\n", r);
1821     r = MsiViewFetch( view, &rec );
1822     ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1823     MsiViewClose( view );
1824     MsiCloseHandle( view );
1825 
1826     /* remove the stream */
1827     r = MsiDatabaseOpenViewA( hdb,
1828             "DELETE FROM `_Streams` WHERE `Name` = 'data'", &view );
1829     ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r);
1830     r = MsiViewExecute( view, 0 );
1831     ok( r == ERROR_SUCCESS, "Failed to execute view: %d\n", r);
1832     MsiViewClose( view );
1833     MsiCloseHandle( view );
1834 
1835     /* attempt to read the stream that no longer exists (abnormal case) */
1836     size = MAX_PATH;
1837     r = MsiRecordGetStringA( rec, 1, file, &size );
1838     ok( r == ERROR_SUCCESS, "Failed to get string: %d\n", r);
1839     ok( !lstrcmpA(file, "data"), "Expected 'data', got %s\n", file);
1840     size = MAX_PATH;
1841     memset(buf, 0, MAX_PATH);
1842     r = MsiRecordReadStream( rec, 2, buf, &size );
1843     ok( r == ERROR_SUCCESS, "Failed to get stream: %d\n", r);
1844     todo_wine ok( size == 0, "Expected empty buffer, got %lu bytes\n", size);
1845     MsiCloseHandle( rec );
1846 
1847     MsiCloseHandle( hdb );
1848     DeleteFileA(msifile);
1849 }
1850 
1851 static void test_binary(void)
1852 {
1853     MSIHANDLE hdb = 0, rec;
1854     char file[MAX_PATH];
1855     char buf[MAX_PATH];
1856     DWORD size;
1857     LPCSTR query;
1858     UINT r;
1859 
1860     /* insert a file into the Binary table */
1861     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb );
1862     ok( r == ERROR_SUCCESS , "Failed to open database\n" );
1863 
1864     query = "CREATE TABLE `Binary` ( `Name` CHAR(72) NOT NULL, `ID` INT NOT NULL, `Data` OBJECT  PRIMARY KEY `Name`, `ID`)";
1865     r = run_query( hdb, 0, query );
1866     ok( r == ERROR_SUCCESS, "Cannot create Binary table: %d\n", r );
1867 
1868     create_file( "test.txt" );
1869     rec = MsiCreateRecord( 1 );
1870     r = MsiRecordSetStreamA( rec, 1, "test.txt" );
1871     ok( r == ERROR_SUCCESS, "Failed to add stream data to the record: %d\n", r);
1872     DeleteFileA( "test.txt" );
1873 
1874     /* try a name that exceeds maximum OLE stream name length */
1875     query = "INSERT INTO `Binary` ( `Name`, `ID`, `Data` ) VALUES ( 'encryption.dll.CB4E6205_F99A_4C51_ADD4_184506EFAB87', 10000, ? )";
1876     r = run_query( hdb, rec, query );
1877     ok( r == ERROR_SUCCESS, "Insert into Binary table failed: %d\n", r );
1878 
1879     r = MsiCloseHandle( rec );
1880     ok( r == ERROR_SUCCESS , "Failed to close record handle\n" );
1881 
1882     r = MsiDatabaseCommit( hdb );
1883     ok( r == ERROR_FUNCTION_FAILED , "got %u\n", r );
1884 
1885     r = MsiCloseHandle( hdb );
1886     ok( r == ERROR_SUCCESS , "Failed to close database\n" );
1887 
1888     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb );
1889     ok( r == ERROR_SUCCESS , "Failed to open database\n" );
1890 
1891     query = "CREATE TABLE `Binary` ( `Name` CHAR(72) NOT NULL, `ID` INT NOT NULL, `Data` OBJECT  PRIMARY KEY `Name`, `ID`)";
1892     r = run_query( hdb, 0, query );
1893     ok( r == ERROR_SUCCESS, "Cannot create Binary table: %d\n", r );
1894 
1895     create_file( "test.txt" );
1896     rec = MsiCreateRecord( 1 );
1897     r = MsiRecordSetStreamA( rec, 1, "test.txt" );
1898     ok( r == ERROR_SUCCESS, "Failed to add stream data to the record: %d\n", r );
1899     DeleteFileA( "test.txt" );
1900 
1901     query = "INSERT INTO `Binary` ( `Name`, `ID`, `Data` ) VALUES ( 'filename1', 1, ? )";
1902     r = run_query( hdb, rec, query );
1903     ok( r == ERROR_SUCCESS, "Insert into Binary table failed: %d\n", r );
1904 
1905     query = "INSERT INTO `Binary` ( `Name`, `ID`, `Data` ) VALUES ( 'filename1', 1, ? )";
1906     r = run_query( hdb, rec, query );
1907     ok( r == ERROR_FUNCTION_FAILED, "got %u\n", r );
1908 
1909     r = MsiCloseHandle( rec );
1910     ok( r == ERROR_SUCCESS , "Failed to close record handle\n" );
1911 
1912     r = MsiDatabaseCommit( hdb );
1913     ok( r == ERROR_SUCCESS , "Failed to commit database\n" );
1914 
1915     r = MsiCloseHandle( hdb );
1916     ok( r == ERROR_SUCCESS , "Failed to close database\n" );
1917 
1918     /* read file from the Stream table */
1919     r = MsiOpenDatabaseW( msifileW, MSIDBOPEN_READONLY, &hdb );
1920     ok( r == ERROR_SUCCESS , "Failed to open database\n" );
1921 
1922     query = "SELECT * FROM `_Streams`";
1923     r = do_query( hdb, query, &rec );
1924     ok( r == ERROR_SUCCESS, "SELECT query failed: %d\n", r );
1925 
1926     size = MAX_PATH;
1927     r = MsiRecordGetStringA( rec, 1, file, &size );
1928     ok( r == ERROR_SUCCESS, "Failed to get string: %d\n", r );
1929     ok( !lstrcmpA(file, "Binary.filename1.1"), "Expected 'Binary.filename1.1', got %s\n", file );
1930 
1931     size = MAX_PATH;
1932     memset( buf, 0, MAX_PATH );
1933     r = MsiRecordReadStream( rec, 2, buf, &size );
1934     ok( r == ERROR_SUCCESS, "Failed to get stream: %d\n", r );
1935     ok( !lstrcmpA(buf, "test.txt\n"), "Expected 'test.txt\\n', got %s\n", buf );
1936 
1937     r = MsiCloseHandle( rec );
1938     ok( r == ERROR_SUCCESS , "Failed to close record handle\n" );
1939 
1940     /* read file from the Binary table */
1941     query = "SELECT * FROM `Binary`";
1942     r = do_query( hdb, query, &rec );
1943     ok( r == ERROR_SUCCESS, "SELECT query failed: %d\n", r );
1944 
1945     size = MAX_PATH;
1946     r = MsiRecordGetStringA( rec, 1, file, &size );
1947     ok( r == ERROR_SUCCESS, "Failed to get string: %d\n", r );
1948     ok( !lstrcmpA(file, "filename1"), "Expected 'filename1', got %s\n", file );
1949 
1950     size = MAX_PATH;
1951     memset( buf, 0, MAX_PATH );
1952     r = MsiRecordReadStream( rec, 3, buf, &size );
1953     ok( r == ERROR_SUCCESS, "Failed to get stream: %d\n", r );
1954     ok( !lstrcmpA(buf, "test.txt\n"), "Expected 'test.txt\\n', got %s\n", buf );
1955 
1956     r = MsiCloseHandle( rec );
1957     ok( r == ERROR_SUCCESS , "Failed to close record handle\n" );
1958 
1959     r = MsiCloseHandle( hdb );
1960     ok( r == ERROR_SUCCESS , "Failed to close database\n" );
1961 
1962     DeleteFileA( msifile );
1963 }
1964 
1965 static void test_where_not_in_selected(void)
1966 {
1967     MSIHANDLE hdb = 0, rec, view;
1968     LPCSTR query;
1969     UINT r;
1970 
1971     hdb = create_db();
1972     ok( hdb, "failed to create db\n");
1973 
1974     r = run_query(hdb, 0,
1975             "CREATE TABLE `IESTable` ("
1976             "`Action` CHAR(64), "
1977             "`Condition` CHAR(64), "
1978             "`Sequence` LONG PRIMARY KEY `Sequence`)");
1979     ok( r == S_OK, "Cannot create IESTable table: %d\n", r);
1980 
1981     r = run_query(hdb, 0,
1982             "CREATE TABLE `CATable` ("
1983             "`Action` CHAR(64), "
1984             "`Type` LONG PRIMARY KEY `Type`)");
1985     ok( r == S_OK, "Cannot create CATable table: %d\n", r);
1986 
1987     r = run_query(hdb, 0, "INSERT INTO `IESTable` "
1988             "( `Action`, `Condition`, `Sequence`) "
1989             "VALUES ( 'clean', 'cond4', 4)");
1990     ok( r == S_OK, "cannot add entry to IESTable table:%d\n", r );
1991 
1992     r = run_query(hdb, 0, "INSERT INTO `IESTable` "
1993             "( `Action`, `Condition`, `Sequence`) "
1994             "VALUES ( 'depends', 'cond1', 1)");
1995     ok( r == S_OK, "cannot add entry to IESTable table:%d\n", r );
1996 
1997     r = run_query(hdb, 0, "INSERT INTO `IESTable` "
1998             "( `Action`, `Condition`, `Sequence`) "
1999             "VALUES ( 'build', 'cond2', 2)");
2000     ok( r == S_OK, "cannot add entry to IESTable table:%d\n", r );
2001 
2002     r = run_query(hdb, 0, "INSERT INTO `IESTable` "
2003             "( `Action`, `Condition`, `Sequence`) "
2004             "VALUES ( 'build2', 'cond6', 6)");
2005     ok( r == S_OK, "cannot add entry to IESTable table:%d\n", r );
2006 
2007     r = run_query(hdb, 0, "INSERT INTO `IESTable` "
2008             "( `Action`, `Condition`, `Sequence`) "
2009             "VALUES ( 'build', 'cond3', 3)");
2010     ok(r == S_OK, "cannot add entry to IESTable table:%d\n", r );
2011 
2012     r = run_query(hdb, 0, "INSERT INTO `CATable` "
2013             "( `Action`, `Type` ) "
2014             "VALUES ( 'build', 32)");
2015     ok(r == S_OK, "cannot add entry to CATable table:%d\n", r );
2016 
2017     r = run_query(hdb, 0, "INSERT INTO `CATable` "
2018             "( `Action`, `Type` ) "
2019             "VALUES ( 'depends', 64)");
2020     ok(r == S_OK, "cannot add entry to CATable table:%d\n", r );
2021 
2022     r = run_query(hdb, 0, "INSERT INTO `CATable` "
2023             "( `Action`, `Type` ) "
2024             "VALUES ( 'clean', 63)");
2025     ok(r == S_OK, "cannot add entry to CATable table:%d\n", r );
2026 
2027     r = run_query(hdb, 0, "INSERT INTO `CATable` "
2028             "( `Action`, `Type` ) "
2029             "VALUES ( 'build2', 34)");
2030     ok(r == S_OK, "cannot add entry to CATable table:%d\n", r );
2031     query = "Select IESTable.Condition from CATable, IESTable where "
2032             "CATable.Action = IESTable.Action and CATable.Type = 32";
2033     r = MsiDatabaseOpenViewA(hdb, query, &view);
2034     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
2035 
2036     r = MsiViewExecute(view, 0);
2037     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
2038 
2039     r = MsiViewFetch(view, &rec);
2040     ok( r == ERROR_SUCCESS, "failed to fetch view: %d\n", r );
2041     check_record(rec, 1, "cond2");
2042     MsiCloseHandle( rec );
2043 
2044     r = MsiViewFetch(view, &rec);
2045     ok( r == ERROR_SUCCESS, "failed to fetch view: %d\n", r );
2046     check_record(rec, 1, "cond3");
2047     MsiCloseHandle( rec );
2048 
2049     MsiViewClose(view);
2050     MsiCloseHandle(view);
2051 
2052     MsiCloseHandle( hdb );
2053     DeleteFileA(msifile);
2054 }
2055 
2056 
2057 static void test_where(void)
2058 {
2059     MSIHANDLE hdb = 0, rec, view;
2060     LPCSTR query;
2061     UINT r;
2062 
2063     hdb = create_db();
2064     ok( hdb, "failed to create db\n");
2065 
2066     r = run_query( hdb, 0,
2067             "CREATE TABLE `Media` ("
2068             "`DiskId` SHORT NOT NULL, "
2069             "`LastSequence` LONG, "
2070             "`DiskPrompt` CHAR(64) LOCALIZABLE, "
2071             "`Cabinet` CHAR(255), "
2072             "`VolumeLabel` CHAR(32), "
2073             "`Source` CHAR(72) "
2074             "PRIMARY KEY `DiskId`)" );
2075     ok( r == S_OK, "cannot create Media table: %d\n", r );
2076 
2077     r = run_query( hdb, 0, "INSERT INTO `Media` "
2078             "( `DiskId`, `LastSequence`, `DiskPrompt`, `Cabinet`, `VolumeLabel`, `Source` ) "
2079             "VALUES ( 1, 0, '', 'zero.cab', '', '' )" );
2080     ok( r == S_OK, "cannot add file to the Media table: %d\n", r );
2081 
2082     r = run_query( hdb, 0, "INSERT INTO `Media` "
2083             "( `DiskId`, `LastSequence`, `DiskPrompt`, `Cabinet`, `VolumeLabel`, `Source` ) "
2084             "VALUES ( 2, 1, '', 'one.cab', '', '' )" );
2085     ok( r == S_OK, "cannot add file to the Media table: %d\n", r );
2086 
2087     r = run_query( hdb, 0, "INSERT INTO `Media` "
2088             "( `DiskId`, `LastSequence`, `DiskPrompt`, `Cabinet`, `VolumeLabel`, `Source` ) "
2089             "VALUES ( 3, 2, '', 'two.cab', '', '' )" );
2090     ok( r == S_OK, "cannot add file to the Media table: %d\n", r );
2091 
2092     query = "SELECT * FROM `Media`";
2093     r = do_query(hdb, query, &rec);
2094     ok(r == ERROR_SUCCESS, "MsiViewFetch failed: %d\n", r);
2095     check_record(rec, 6, "1", "0", "", "zero.cab", "", "");
2096     MsiCloseHandle( rec );
2097 
2098     query = "SELECT * FROM `Media` WHERE `LastSequence` >= 1";
2099     r = do_query(hdb, query, &rec);
2100     ok(r == ERROR_SUCCESS, "MsiViewFetch failed: %d\n", r);
2101     check_record(rec, 6, "2", "1", "", "one.cab", "", "");
2102     MsiCloseHandle( rec );
2103 
2104     query = "SELECT `DiskId` FROM `Media` WHERE `LastSequence` >= 1 AND DiskId >= 0";
2105     r = MsiDatabaseOpenViewA(hdb, query, &view);
2106     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
2107 
2108     r = MsiViewExecute(view, 0);
2109     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
2110 
2111     r = MsiViewFetch(view, &rec);
2112     ok( r == ERROR_SUCCESS, "failed to fetch view: %d\n", r );
2113     check_record(rec, 1, "2");
2114     MsiCloseHandle( rec );
2115 
2116     r = MsiViewFetch(view, &rec);
2117     ok( r == ERROR_SUCCESS, "failed to fetch view: %d\n", r );
2118     check_record(rec, 1, "3");
2119     MsiCloseHandle( rec );
2120 
2121     r = MsiViewFetch(view, &rec);
2122     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
2123 
2124     MsiViewClose(view);
2125     MsiCloseHandle(view);
2126 
2127     MsiCloseHandle( rec );
2128 
2129     rec = 0;
2130     query = "SELECT * FROM `Media` WHERE `DiskPrompt` IS NULL";
2131     r = do_query(hdb, query, &rec);
2132     ok( r == ERROR_SUCCESS, "query failed: %d\n", r );
2133     MsiCloseHandle( rec );
2134 
2135     rec = 0;
2136     query = "SELECT * FROM `Media` WHERE `DiskPrompt` < 'Cabinet'";
2137     r = do_query(hdb, query, &rec);
2138     ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %d\n", r );
2139     MsiCloseHandle( rec );
2140 
2141     rec = 0;
2142     query = "SELECT * FROM `Media` WHERE `DiskPrompt` > 'Cabinet'";
2143     r = do_query(hdb, query, &rec);
2144     ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %d\n", r );
2145     MsiCloseHandle( rec );
2146 
2147     rec = 0;
2148     query = "SELECT * FROM `Media` WHERE `DiskPrompt` <> 'Cabinet'";
2149     r = do_query(hdb, query, &rec);
2150     ok( r == ERROR_SUCCESS, "query failed: %d\n", r );
2151     MsiCloseHandle( rec );
2152 
2153     rec = 0;
2154     query = "SELECT * FROM `Media` WHERE `DiskPrompt` = 'Cabinet'";
2155     r = do_query(hdb, query, &rec);
2156     ok( r == ERROR_NO_MORE_ITEMS, "query failed: %d\n", r );
2157     MsiCloseHandle( rec );
2158 
2159     rec = MsiCreateRecord(1);
2160     MsiRecordSetStringA(rec, 1, "");
2161 
2162     query = "SELECT * FROM `Media` WHERE `DiskPrompt` = ?";
2163     r = MsiDatabaseOpenViewA(hdb, query, &view);
2164     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2165     r = MsiViewExecute(view, rec);
2166     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2167 
2168     MsiCloseHandle(rec);
2169 
2170     r = MsiViewFetch(view, &rec);
2171     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2172 
2173     MsiCloseHandle(rec);
2174     MsiViewClose(view);
2175     MsiCloseHandle(view);
2176 
2177     MsiCloseHandle( hdb );
2178     DeleteFileA(msifile);
2179 }
2180 
2181 static CHAR CURR_DIR[MAX_PATH];
2182 
2183 static const CHAR test_data[] = "FirstPrimaryColumn\tSecondPrimaryColumn\tShortInt\tShortIntNullable\tLongInt\tLongIntNullable\tString\tLocalizableString\tLocalizableStringNullable\n"
2184                                 "s255\ti2\ti2\tI2\ti4\tI4\tS255\tS0\ts0\n"
2185                                 "TestTable\tFirstPrimaryColumn\n"
2186                                 "stringage\t5\t2\t\t2147483640\t-2147483640\tanother string\tlocalizable\tduh\n";
2187 
2188 static const CHAR two_primary[] = "PrimaryOne\tPrimaryTwo\n"
2189                                   "s255\ts255\n"
2190                                   "TwoPrimary\tPrimaryOne\tPrimaryTwo\n"
2191                                   "papaya\tleaf\n"
2192                                   "papaya\tflower\n";
2193 
2194 static const CHAR endlines1[] = "A\tB\tC\tD\tE\tF\r\n"
2195                                 "s72\ts72\ts72\ts72\ts72\ts72\n"
2196                                 "Table\tA\r\n"
2197                                 "a\tb\tc\td\te\tf\n"
2198                                 "g\th\ti\t\rj\tk\tl\r\n";
2199 
2200 static const CHAR endlines2[] = "A\tB\tC\tD\tE\tF\r"
2201                                 "s72\ts72\ts72\ts72\ts72\ts72\n"
2202                                 "Table2\tA\r\n"
2203                                 "a\tb\tc\td\te\tf\n"
2204                                 "g\th\ti\tj\tk\tl\r\n";
2205 
2206 static const CHAR suminfo[] = "PropertyId\tValue\n"
2207                               "i2\tl255\n"
2208                               "_SummaryInformation\tPropertyId\n"
2209                               "1\t1252\n"
2210                               "2\tInstaller Database\n"
2211                               "3\tInstaller description\n"
2212                               "4\tWineHQ\n"
2213                               "5\tInstaller\n"
2214                               "6\tInstaller comments\n"
2215                               "7\tIntel;1033,2057\n"
2216                               "9\t{12345678-1234-1234-1234-123456789012}\n"
2217                               "12\t2009/04/12 15:46:11\n"
2218                               "13\t2009/04/12 15:46:11\n"
2219                               "14\t200\n"
2220                               "15\t2\n"
2221                               "18\tVim\n"
2222                               "19\t2\n";
2223 
2224 static void write_file(const CHAR *filename, const char *data, int data_size)
2225 {
2226     DWORD size;
2227 
2228     HANDLE hf = CreateFileA(filename, GENERIC_WRITE, 0, NULL,
2229                             CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2230     WriteFile(hf, data, data_size, &size, NULL);
2231     CloseHandle(hf);
2232 }
2233 
2234 static UINT add_table_to_db(MSIHANDLE hdb, LPCSTR table_data)
2235 {
2236     UINT r;
2237 
2238     write_file("temp_file", table_data, (lstrlenA(table_data) - 1) * sizeof(char));
2239     r = MsiDatabaseImportA(hdb, CURR_DIR, "temp_file");
2240     DeleteFileA("temp_file");
2241 
2242     return r;
2243 }
2244 
2245 static void test_suminfo_import(void)
2246 {
2247     MSIHANDLE hdb, hsi, view = 0;
2248     LPCSTR query;
2249     UINT r, count, type;
2250     DWORD size;
2251     char str_value[50];
2252     INT int_value;
2253     FILETIME ft_value;
2254 
2255     GetCurrentDirectoryA(MAX_PATH, CURR_DIR);
2256 
2257     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
2258     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2259 
2260     r = add_table_to_db(hdb, suminfo);
2261     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2262 
2263     /* _SummaryInformation is not imported as a regular table... */
2264 
2265     query = "SELECT * FROM `_SummaryInformation`";
2266     r = MsiDatabaseOpenViewA(hdb, query, &view);
2267     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %u\n", r);
2268     MsiCloseHandle(view);
2269 
2270     /* ...its data is added to the special summary information stream */
2271 
2272     r = MsiGetSummaryInformationA(hdb, NULL, 0, &hsi);
2273     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2274 
2275     r = MsiSummaryInfoGetPropertyCount(hsi, &count);
2276     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2277     ok(count == 14, "Expected 14, got %u\n", count);
2278 
2279     r = MsiSummaryInfoGetPropertyA(hsi, PID_CODEPAGE, &type, &int_value, NULL, NULL, NULL);
2280     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2281     ok(type ==  VT_I2, "Expected VT_I2, got %u\n", type);
2282     ok(int_value == 1252, "Expected 1252, got %d\n", int_value);
2283 
2284     size = sizeof(str_value);
2285     r = MsiSummaryInfoGetPropertyA(hsi, PID_TITLE, &type, NULL, NULL, str_value, &size);
2286     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2287     ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
2288     ok(size == 18, "Expected 18, got %lu\n", size);
2289     ok(!strcmp(str_value, "Installer Database"),
2290        "Expected \"Installer Database\", got %s\n", str_value);
2291 
2292     size = sizeof(str_value);
2293     r = MsiSummaryInfoGetPropertyA(hsi, PID_SUBJECT, &type, NULL, NULL, str_value, &size);
2294     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2295     ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
2296     ok(!strcmp(str_value, "Installer description"),
2297        "Expected \"Installer description\", got %s\n", str_value);
2298 
2299     size = sizeof(str_value);
2300     r = MsiSummaryInfoGetPropertyA(hsi, PID_AUTHOR, &type, NULL, NULL, str_value, &size);
2301     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2302     ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
2303     ok(!strcmp(str_value, "WineHQ"),
2304        "Expected \"WineHQ\", got %s\n", str_value);
2305 
2306     size = sizeof(str_value);
2307     r = MsiSummaryInfoGetPropertyA(hsi, PID_KEYWORDS, &type, NULL, NULL, str_value, &size);
2308     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2309     ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
2310     ok(!strcmp(str_value, "Installer"),
2311        "Expected \"Installer\", got %s\n", str_value);
2312 
2313     size = sizeof(str_value);
2314     r = MsiSummaryInfoGetPropertyA(hsi, PID_COMMENTS, &type, NULL, NULL, str_value, &size);
2315     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2316     ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
2317     ok(!strcmp(str_value, "Installer comments"),
2318        "Expected \"Installer comments\", got %s\n", str_value);
2319 
2320     size = sizeof(str_value);
2321     r = MsiSummaryInfoGetPropertyA(hsi, PID_TEMPLATE, &type, NULL, NULL, str_value, &size);
2322     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2323     ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
2324     ok(!strcmp(str_value, "Intel;1033,2057"),
2325        "Expected \"Intel;1033,2057\", got %s\n", str_value);
2326 
2327     size = sizeof(str_value);
2328     r = MsiSummaryInfoGetPropertyA(hsi, PID_REVNUMBER, &type, NULL, NULL, str_value, &size);
2329     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2330     ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
2331     ok(!strcmp(str_value, "{12345678-1234-1234-1234-123456789012}"),
2332        "Expected \"{12345678-1234-1234-1234-123456789012}\", got %s\n", str_value);
2333 
2334     r = MsiSummaryInfoGetPropertyA(hsi, PID_CREATE_DTM, &type, NULL, &ft_value, NULL, NULL);
2335     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2336     ok(type == VT_FILETIME, "Expected VT_FILETIME, got %u\n", type);
2337 
2338     r = MsiSummaryInfoGetPropertyA(hsi, PID_LASTSAVE_DTM, &type, NULL, &ft_value, NULL, NULL);
2339     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2340     ok(type == VT_FILETIME, "Expected VT_FILETIME, got %u\n", type);
2341 
2342     r = MsiSummaryInfoGetPropertyA(hsi, PID_PAGECOUNT, &type, &int_value, NULL, NULL, NULL);
2343     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2344     ok(type ==  VT_I4, "Expected VT_I4, got %u\n", type);
2345     ok(int_value == 200, "Expected 200, got %d\n", int_value);
2346 
2347     r = MsiSummaryInfoGetPropertyA(hsi, PID_WORDCOUNT, &type, &int_value, NULL, NULL, NULL);
2348     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2349     ok(type ==  VT_I4, "Expected VT_I4, got %u\n", type);
2350     ok(int_value == 2, "Expected 2, got %d\n", int_value);
2351 
2352     r = MsiSummaryInfoGetPropertyA(hsi, PID_SECURITY, &type, &int_value, NULL, NULL, NULL);
2353     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2354     ok(type ==  VT_I4, "Expected VT_I4, got %u\n", type);
2355     ok(int_value == 2, "Expected 2, got %d\n", int_value);
2356 
2357     size = sizeof(str_value);
2358     r = MsiSummaryInfoGetPropertyA(hsi, PID_APPNAME, &type, NULL, NULL, str_value, &size);
2359     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2360     ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
2361     ok(!strcmp(str_value, "Vim"), "Expected \"Vim\", got %s\n", str_value);
2362 
2363     MsiCloseHandle(hsi);
2364     MsiCloseHandle(hdb);
2365     DeleteFileA(msifile);
2366 }
2367 
2368 static void test_msiimport(void)
2369 {
2370     MSIHANDLE hdb, view, rec;
2371     LPCSTR query;
2372     UINT r;
2373 
2374     GetCurrentDirectoryA(MAX_PATH, CURR_DIR);
2375 
2376     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
2377     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2378 
2379     r = MsiDatabaseImportA(hdb, CURR_DIR, NULL);
2380     ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
2381 
2382     r = MsiDatabaseImportA(hdb, CURR_DIR, "nonexistent");
2383     ok(r == ERROR_FUNCTION_FAILED, "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
2384 
2385     r = add_table_to_db(hdb, test_data);
2386     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2387 
2388     r = add_table_to_db(hdb, two_primary);
2389     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2390 
2391     r = add_table_to_db(hdb, endlines1);
2392     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2393 
2394     r = add_table_to_db(hdb, endlines2);
2395     ok(r == ERROR_FUNCTION_FAILED, "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
2396 
2397     query = "SELECT * FROM `TestTable`";
2398     r = MsiDatabaseOpenViewA(hdb, query, &view);
2399     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2400 
2401     r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec);
2402     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2403     check_record(rec, 9, "FirstPrimaryColumn", "SecondPrimaryColumn", "ShortInt",
2404             "ShortIntNullable", "LongInt", "LongIntNullable", "String",
2405             "LocalizableString", "LocalizableStringNullable");
2406     MsiCloseHandle(rec);
2407 
2408     r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
2409     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2410     check_record(rec, 9, "s255", "i2", "i2", "I2", "i4", "I4", "S255", "S0", "s0");
2411     MsiCloseHandle(rec);
2412 
2413     query = "SELECT * FROM `TestTable`";
2414     r = do_query(hdb, query, &rec);
2415     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2416     check_record(rec, 9, "stringage", "5", "2", "", "2147483640", "-2147483640",
2417             "another string", "localizable", "duh");
2418     MsiCloseHandle(rec);
2419 
2420     MsiViewClose(view);
2421     MsiCloseHandle(view);
2422 
2423     query = "SELECT * FROM `TwoPrimary`";
2424     r = MsiDatabaseOpenViewA(hdb, query, &view);
2425     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2426 
2427     r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec);
2428     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2429     check_record(rec, 2, "PrimaryOne", "PrimaryTwo");
2430     MsiCloseHandle(rec);
2431 
2432     r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
2433     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2434     check_record(rec, 2, "s255", "s255");
2435     MsiCloseHandle(rec);
2436 
2437     r = MsiViewExecute(view, 0);
2438     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2439 
2440     r = MsiViewFetch(view, &rec);
2441     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2442     check_record(rec, 2, "papaya", "leaf");
2443     MsiCloseHandle(rec);
2444 
2445     r = MsiViewFetch(view, &rec);
2446     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2447     check_record(rec, 2, "papaya", "flower");
2448     MsiCloseHandle(rec);
2449 
2450     r = MsiViewFetch(view, &rec);
2451     ok(r == ERROR_NO_MORE_ITEMS,
2452        "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
2453 
2454     r = MsiViewClose(view);
2455     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2456 
2457     MsiCloseHandle(view);
2458 
2459     query = "SELECT * FROM `Table`";
2460     r = MsiDatabaseOpenViewA(hdb, query, &view);
2461     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2462 
2463     r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec);
2464     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2465     check_record(rec, 6, "A", "B", "C", "D", "E", "F");
2466     MsiCloseHandle(rec);
2467 
2468     r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
2469     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2470     check_record(rec, 6, "s72", "s72", "s72", "s72", "s72", "s72");
2471     MsiCloseHandle(rec);
2472 
2473     MsiViewClose(view);
2474     MsiCloseHandle(view);
2475 
2476     query = "SELECT * FROM `Table`";
2477     r = MsiDatabaseOpenViewA(hdb, query, &view);
2478     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2479 
2480     r = MsiViewExecute(view, 0);
2481     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2482 
2483     r = MsiViewFetch(view, &rec);
2484     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2485     check_record(rec, 6, "a", "b", "c", "d", "e", "f");
2486     MsiCloseHandle(rec);
2487 
2488     r = MsiViewFetch(view, &rec);
2489     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2490     check_record(rec, 6, "g", "h", "i", "j", "k", "l");
2491     MsiCloseHandle(rec);
2492 
2493     r = MsiViewFetch(view, &rec);
2494     ok(r == ERROR_NO_MORE_ITEMS,
2495        "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
2496 
2497     MsiViewClose(view);
2498     MsiCloseHandle(view);
2499     MsiCloseHandle(hdb);
2500     DeleteFileA(msifile);
2501 }
2502 
2503 static const CHAR bin_import_dat[] = "Name\tData\r\n"
2504                                      "s72\tV0\r\n"
2505                                      "Binary\tName\r\n"
2506                                      "filename1\tfilename1.ibd\r\n";
2507 
2508 static void test_binary_import(void)
2509 {
2510     MSIHANDLE hdb = 0, rec;
2511     char file[MAX_PATH];
2512     char buf[MAX_PATH];
2513     char path[MAX_PATH];
2514     DWORD size;
2515     LPCSTR query;
2516     UINT r;
2517 
2518     /* create files to import */
2519     write_file("bin_import.idt", bin_import_dat,
2520           (sizeof(bin_import_dat) - 1) * sizeof(char));
2521     CreateDirectoryA("bin_import", NULL);
2522     create_file_data("bin_import/filename1.ibd", "just some words", 15);
2523 
2524     /* import files into database */
2525     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
2526     ok( r == ERROR_SUCCESS , "Failed to open database\n");
2527 
2528     GetCurrentDirectoryA(MAX_PATH, path);
2529     r = MsiDatabaseImportA(hdb, path, "bin_import.idt");
2530     ok(r == ERROR_SUCCESS , "Failed to import Binary table\n");
2531 
2532     /* read file from the Binary table */
2533     query = "SELECT * FROM `Binary`";
2534     r = do_query(hdb, query, &rec);
2535     ok(r == ERROR_SUCCESS, "SELECT query failed: %d\n", r);
2536 
2537     size = MAX_PATH;
2538     r = MsiRecordGetStringA(rec, 1, file, &size);
2539     ok(r == ERROR_SUCCESS, "Failed to get string: %d\n", r);
2540     ok(!lstrcmpA(file, "filename1"), "Expected 'filename1', got %s\n", file);
2541 
2542     size = MAX_PATH;
2543     memset(buf, 0, MAX_PATH);
2544     r = MsiRecordReadStream(rec, 2, buf, &size);
2545     ok(r == ERROR_SUCCESS, "Failed to get stream: %d\n", r);
2546     ok(!lstrcmpA(buf, "just some words"), "Expected 'just some words', got %s\n", buf);
2547 
2548     r = MsiCloseHandle(rec);
2549     ok(r == ERROR_SUCCESS , "Failed to close record handle\n");
2550 
2551     r = MsiCloseHandle(hdb);
2552     ok(r == ERROR_SUCCESS , "Failed to close database\n");
2553 
2554     DeleteFileA("bin_import/filename1.ibd");
2555     RemoveDirectoryA("bin_import");
2556     DeleteFileA("bin_import.idt");
2557 }
2558 
2559 static void test_markers(void)
2560 {
2561     MSIHANDLE hdb, rec;
2562     LPCSTR query;
2563     UINT r;
2564 
2565     hdb = create_db();
2566     ok( hdb, "failed to create db\n");
2567 
2568     rec = MsiCreateRecord(3);
2569     MsiRecordSetStringA(rec, 1, "Table");
2570     MsiRecordSetStringA(rec, 2, "Apples");
2571     MsiRecordSetStringA(rec, 3, "Oranges");
2572 
2573     /* try a legit create */
2574     query = "CREATE TABLE `Table` ( `One` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`)";
2575     r = run_query(hdb, 0, query);
2576     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2577     MsiCloseHandle(rec);
2578 
2579     /* try table name as marker */
2580     rec = MsiCreateRecord(1);
2581     MsiRecordSetStringA(rec, 1, "Fable");
2582     query = "CREATE TABLE `?` ( `One` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`)";
2583     r = run_query(hdb, rec, query);
2584     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2585 
2586     /* verify that we just created a table called '?', not 'Fable' */
2587     r = try_query(hdb, "SELECT * from `Fable`");
2588     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2589 
2590     r = try_query(hdb, "SELECT * from `?`");
2591     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2592 
2593     /* try table name as marker without backticks */
2594     MsiRecordSetStringA(rec, 1, "Mable");
2595     query = "CREATE TABLE ? ( `One` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`)";
2596     r = run_query(hdb, rec, query);
2597     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2598 
2599     /* try one column name as marker */
2600     MsiRecordSetStringA(rec, 1, "One");
2601     query = "CREATE TABLE `Mable` ( `?` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`)";
2602     r = run_query(hdb, rec, query);
2603     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2604     MsiCloseHandle(rec);
2605 
2606     /* try column names as markers */
2607     rec = MsiCreateRecord(2);
2608     MsiRecordSetStringA(rec, 1, "One");
2609     MsiRecordSetStringA(rec, 2, "Two");
2610     query = "CREATE TABLE `Mable` ( `?` SHORT NOT NULL, `?` CHAR(255) PRIMARY KEY `One`)";
2611     r = run_query(hdb, rec, query);
2612     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2613     MsiCloseHandle(rec);
2614 
2615     /* try names with backticks */
2616     rec = MsiCreateRecord(3);
2617     MsiRecordSetStringA(rec, 1, "One");
2618     MsiRecordSetStringA(rec, 2, "Two");
2619     MsiRecordSetStringA(rec, 3, "One");
2620     query = "CREATE TABLE `Mable` ( `?` SHORT NOT NULL, `?` CHAR(255) PRIMARY KEY `?`)";
2621     r = run_query(hdb, rec, query);
2622     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2623 
2624     /* try names with backticks, minus definitions */
2625     query = "CREATE TABLE `Mable` ( `?`, `?` PRIMARY KEY `?`)";
2626     r = run_query(hdb, rec, query);
2627     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2628 
2629     /* try names without backticks */
2630     query = "CREATE TABLE `Mable` ( ? SHORT NOT NULL, ? CHAR(255) PRIMARY KEY ?)";
2631     r = run_query(hdb, rec, query);
2632     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2633     MsiCloseHandle(rec);
2634 
2635     /* try one long marker */
2636     rec = MsiCreateRecord(1);
2637     MsiRecordSetStringA(rec, 1, "`One` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`");
2638     query = "CREATE TABLE `Mable` ( ? )";
2639     r = run_query(hdb, rec, query);
2640     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2641     MsiCloseHandle(rec);
2642 
2643     /* try all names as markers */
2644     rec = MsiCreateRecord(4);
2645     MsiRecordSetStringA(rec, 1, "Mable");
2646     MsiRecordSetStringA(rec, 2, "One");
2647     MsiRecordSetStringA(rec, 3, "Two");
2648     MsiRecordSetStringA(rec, 4, "One");
2649     query = "CREATE TABLE `?` ( `?` SHORT NOT NULL, `?` CHAR(255) PRIMARY KEY `?`)";
2650     r = run_query(hdb, rec, query);
2651     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2652     MsiCloseHandle(rec);
2653 
2654     /* try a legit insert */
2655     query = "INSERT INTO `Table` ( `One`, `Two` ) VALUES ( 5, 'hello' )";
2656     r = run_query(hdb, 0, query);
2657     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2658 
2659     r = try_query(hdb, "SELECT * from `Table`");
2660     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2661 
2662     /* try values as markers */
2663     rec = MsiCreateRecord(2);
2664     MsiRecordSetInteger(rec, 1, 4);
2665     MsiRecordSetStringA(rec, 2, "hi");
2666     query = "INSERT INTO `Table` ( `One`, `Two` ) VALUES ( ?, '?' )";
2667     r = run_query(hdb, rec, query);
2668     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2669     MsiCloseHandle(rec);
2670 
2671     /* try column names and values as markers */
2672     rec = MsiCreateRecord(4);
2673     MsiRecordSetStringA(rec, 1, "One");
2674     MsiRecordSetStringA(rec, 2, "Two");
2675     MsiRecordSetInteger(rec, 3, 5);
2676     MsiRecordSetStringA(rec, 4, "hi");
2677     query = "INSERT INTO `Table` ( `?`, `?` ) VALUES ( ?, '?' )";
2678     r = run_query(hdb, rec, query);
2679     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2680     MsiCloseHandle(rec);
2681 
2682     /* try column names as markers */
2683     rec = MsiCreateRecord(2);
2684     MsiRecordSetStringA(rec, 1, "One");
2685     MsiRecordSetStringA(rec, 2, "Two");
2686     query = "INSERT INTO `Table` ( `?`, `?` ) VALUES ( 3, 'yellow' )";
2687     r = run_query(hdb, rec, query);
2688     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2689     MsiCloseHandle(rec);
2690 
2691     /* try table name as a marker */
2692     rec = MsiCreateRecord(1);
2693     MsiRecordSetStringA(rec, 1, "Table");
2694     query = "INSERT INTO `?` ( `One`, `Two` ) VALUES ( 2, 'green' )";
2695     r = run_query(hdb, rec, query);
2696     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2697     MsiCloseHandle(rec);
2698 
2699     /* try table name and values as markers */
2700     rec = MsiCreateRecord(3);
2701     MsiRecordSetStringA(rec, 1, "Table");
2702     MsiRecordSetInteger(rec, 2, 10);
2703     MsiRecordSetStringA(rec, 3, "haha");
2704     query = "INSERT INTO `?` ( `One`, `Two` ) VALUES ( ?, '?' )";
2705     r = run_query(hdb, rec, query);
2706     ok(r == ERROR_FUNCTION_FAILED, "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
2707     MsiCloseHandle(rec);
2708 
2709     /* try all markers */
2710     rec = MsiCreateRecord(5);
2711     MsiRecordSetStringA(rec, 1, "Table");
2712     MsiRecordSetStringA(rec, 1, "One");
2713     MsiRecordSetStringA(rec, 1, "Two");
2714     MsiRecordSetInteger(rec, 2, 10);
2715     MsiRecordSetStringA(rec, 3, "haha");
2716     query = "INSERT INTO `?` ( `?`, `?` ) VALUES ( ?, '?' )";
2717     r = run_query(hdb, rec, query);
2718     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2719     MsiCloseHandle(rec);
2720 
2721     /* insert an integer as a string */
2722     rec = MsiCreateRecord(2);
2723     MsiRecordSetStringA(rec, 1, "11");
2724     MsiRecordSetStringA(rec, 2, "hi");
2725     query = "INSERT INTO `Table` ( `One`, `Two` ) VALUES ( ?, '?' )";
2726     r = run_query(hdb, rec, query);
2727     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2728     MsiCloseHandle(rec);
2729 
2730     /* leave off the '' for the string */
2731     rec = MsiCreateRecord(2);
2732     MsiRecordSetInteger(rec, 1, 12);
2733     MsiRecordSetStringA(rec, 2, "hi");
2734     query = "INSERT INTO `Table` ( `One`, `Two` ) VALUES ( ?, ? )";
2735     r = run_query(hdb, rec, query);
2736     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2737     MsiCloseHandle(rec);
2738 
2739     MsiCloseHandle(hdb);
2740     DeleteFileA(msifile);
2741 }
2742 
2743 #define MY_NVIEWS 4000    /* Largest installer I've seen uses < 2000 */
2744 static void test_handle_limit(void)
2745 {
2746     int i;
2747     MSIHANDLE hdb;
2748     MSIHANDLE hviews[MY_NVIEWS];
2749     UINT r;
2750 
2751     /* create an empty db */
2752     hdb = create_db();
2753     ok( hdb, "failed to create db\n");
2754 
2755     memset(hviews, 0, sizeof(hviews));
2756 
2757     for (i=0; i<MY_NVIEWS; i++) {
2758         static char szQueryBuf[256] = "SELECT * from `_Tables`";
2759         hviews[i] = 0xdeadbeeb;
2760         r = MsiDatabaseOpenViewA(hdb, szQueryBuf, &hviews[i]);
2761         if( r != ERROR_SUCCESS || hviews[i] == 0xdeadbeeb ||
2762             hviews[i] == 0 || (i && (hviews[i] == hviews[i-1])))
2763             break;
2764     }
2765 
2766     ok( i == MY_NVIEWS, "problem opening views\n");
2767 
2768     for (i=0; i<MY_NVIEWS; i++) {
2769         if (hviews[i] != 0 && hviews[i] != 0xdeadbeeb) {
2770             MsiViewClose(hviews[i]);
2771             r = MsiCloseHandle(hviews[i]);
2772             if (r != ERROR_SUCCESS)
2773                 break;
2774         }
2775     }
2776 
2777     ok( i == MY_NVIEWS, "problem closing views\n");
2778 
2779     r = MsiCloseHandle(hdb);
2780     ok( r == ERROR_SUCCESS, "failed to close database\n");
2781 }
2782 
2783 static void generate_transform(void)
2784 {
2785     MSIHANDLE hdb1, hdb2, hrec;
2786     LPCSTR query;
2787     UINT r;
2788 
2789     /* start with two identical databases */
2790     CopyFileA(msifile2, msifile, FALSE);
2791 
2792     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_TRANSACT, &hdb1 );
2793     ok( r == ERROR_SUCCESS , "Failed to create database\n" );
2794 
2795     r = MsiDatabaseCommit( hdb1 );
2796     ok( r == ERROR_SUCCESS , "Failed to commit database\n" );
2797 
2798     r = MsiOpenDatabaseW(msifile2W, MSIDBOPEN_READONLY, &hdb2 );
2799     ok( r == ERROR_SUCCESS , "Failed to create database\n" );
2800 
2801     /* the transform between two identical database should be empty */
2802     r = MsiDatabaseGenerateTransformA(hdb1, hdb2, NULL, 0, 0);
2803     todo_wine {
2804     ok( r == ERROR_NO_DATA, "return code %d, should be ERROR_NO_DATA\n", r );
2805     }
2806 
2807     query = "CREATE TABLE `AAR` ( `BAR` SHORT NOT NULL, `CAR` CHAR(255) PRIMARY KEY `CAR`)";
2808     r = run_query(hdb1, 0, query);
2809     ok(r == ERROR_SUCCESS, "failed to add table\n");
2810 
2811     query = "INSERT INTO `AAR` ( `BAR`, `CAR` ) VALUES ( 1, 'vw' )";
2812     r = run_query(hdb1, 0, query);
2813     ok(r == ERROR_SUCCESS, "failed to add row 1\n");
2814 
2815     query = "INSERT INTO `AAR` ( `BAR`, `CAR` ) VALUES ( 2, 'bmw' )";
2816     r = run_query(hdb1, 0, query);
2817     ok(r == ERROR_SUCCESS, "failed to add row 2\n");
2818 
2819     query = "UPDATE `MOO` SET `OOO` = 'c' WHERE `NOO` = 1";
2820     r = run_query(hdb1, 0, query);
2821     ok(r == ERROR_SUCCESS, "failed to modify row\n");
2822 
2823     query = "DELETE FROM `MOO` WHERE `NOO` = 3";
2824     r = run_query(hdb1, 0, query);
2825     ok(r == ERROR_SUCCESS, "failed to delete row\n");
2826 
2827     hrec = MsiCreateRecord(2);
2828     r = MsiRecordSetInteger(hrec, 1, 1);
2829     ok(r == ERROR_SUCCESS, "failed to set integer\n");
2830 
2831     write_file("testdata.bin", "naengmyon", 9);
2832     r = MsiRecordSetStreamA(hrec, 2, "testdata.bin");
2833     ok(r == ERROR_SUCCESS, "failed to set stream\n");
2834 
2835     query = "INSERT INTO `BINARY` ( `ID`, `BLOB` ) VALUES ( ?, ? )";
2836     r = run_query(hdb1, hrec, query);
2837     ok(r == ERROR_SUCCESS, "failed to add row with blob\n");
2838 
2839     MsiCloseHandle(hrec);
2840 
2841     query = "ALTER TABLE `MOO` ADD `COW` INTEGER";
2842     r = run_query(hdb1, 0, query);
2843     ok(r == ERROR_SUCCESS, "failed to add column\n");
2844 
2845     query = "ALTER TABLE `MOO` ADD `PIG` INTEGER";
2846     r = run_query(hdb1, 0, query);
2847     ok(r == ERROR_SUCCESS, "failed to add column\n");
2848 
2849     query = "UPDATE `MOO` SET `PIG` = 5 WHERE `NOO` = 1";
2850     r = run_query(hdb1, 0, query);
2851     ok(r == ERROR_SUCCESS, "failed to modify row\n");
2852 
2853     query = "CREATE TABLE `Property` ( `Property` CHAR(72) NOT NULL, "
2854             "`Value` CHAR(0) PRIMARY KEY `Property`)";
2855     r = run_query(hdb1, 0, query);
2856     ok(r == ERROR_SUCCESS, "failed to add property table\n");
2857 
2858     query = "INSERT INTO `Property` ( `Property`, `Value` ) VALUES ( 'prop', 'val' )";
2859     r = run_query(hdb1, 0, query);
2860     ok(r == ERROR_SUCCESS, "failed to add property\n");
2861 
2862     /* database needs to be committed */
2863     MsiDatabaseCommit(hdb1);
2864 
2865     r = MsiDatabaseGenerateTransformA(hdb1, hdb2, mstfile, 0, 0);
2866     ok( r == ERROR_SUCCESS, "return code %d, should be ERROR_SUCCESS\n", r );
2867 
2868     MsiCloseHandle( hdb1 );
2869     MsiCloseHandle( hdb2 );
2870 
2871     DeleteFileA("testdata.bin");
2872 }
2873 
2874 /* data for generating a transform */
2875 
2876 /* tables transform names - encoded as they would be in an msi database file */
2877 static const WCHAR name1[] = { 0x4840, 0x3a8a, 0x481b, 0 }; /* AAR */
2878 static const WCHAR name2[] = { 0x4840, 0x3b3f, 0x43f2, 0x4438, 0x45b1, 0 }; /* _Columns */
2879 static const WCHAR name3[] = { 0x4840, 0x3f7f, 0x4164, 0x422f, 0x4836, 0 }; /* _Tables */
2880 static const WCHAR name4[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0 }; /* _StringData */
2881 static const WCHAR name5[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0 }; /* _StringPool */
2882 static const WCHAR name6[] = { 0x4840, 0x3e16, 0x4818, 0}; /* MOO */
2883 static const WCHAR name7[] = { 0x4840, 0x3c8b, 0x3a97, 0x409b, 0 }; /* BINARY */
2884 static const WCHAR name8[] = { 0x3c8b, 0x3a97, 0x409b, 0x387e, 0 }; /* BINARY.1 */
2885 static const WCHAR name9[] = { 0x4840, 0x4559, 0x44f2, 0x4568, 0x4737, 0 }; /* Property */
2886 
2887 /* data in each table */
2888 static const WCHAR data1[] = { /* AAR */
2889     0x0201, 0x0008, 0x8001,  /* 0x0201 = add row (1), two shorts */
2890     0x0201, 0x0009, 0x8002,
2891 };
2892 static const WCHAR data2[] = { /* _Columns */
2893     0x0401, 0x0001, 0x8003, 0x0002, 0x9502,
2894     0x0401, 0x0001, 0x8004, 0x0003, 0x9502,
2895     0x0401, 0x0005, 0x0000, 0x0006, 0xbdff,  /* 0x0401 = add row (1), 4 shorts */
2896     0x0401, 0x0005, 0x0000, 0x0007, 0x8502,
2897     0x0401, 0x000a, 0x0000, 0x000a, 0xad48,
2898     0x0401, 0x000a, 0x0000, 0x000b, 0x9d00,
2899 };
2900 static const WCHAR data3[] = { /* _Tables */
2901     0x0101, 0x0005, /* 0x0101 = add row (1), 1 short */
2902     0x0101, 0x000a,
2903 };
2904 static const char data4[] = /* _StringData */
2905     "MOOCOWPIGcAARCARBARvwbmwPropertyValuepropval";  /* all the strings squashed together */
2906 static const WCHAR data5[] = { /* _StringPool */
2907 /*  len, refs */
2908     0,   0,    /* string 0 ''    */
2909     3,   2,    /* string 1 'MOO' */
2910     3,   1,    /* string 2 'COW' */
2911     3,   1,    /* string 3 'PIG' */
2912     1,   1,    /* string 4 'c'   */
2913     3,   3,    /* string 5 'AAR' */
2914     3,   1,    /* string 6 'CAR' */
2915     3,   1,    /* string 7 'BAR' */
2916     2,   1,    /* string 8 'vw'  */
2917     3,   1,    /* string 9 'bmw' */
2918     8,   4,    /* string 10 'Property' */
2919     5,   1,    /* string 11 'Value' */
2920     4,   1,    /* string 12 'prop' */
2921     3,   1,    /* string 13 'val' */
2922 };
2923 /* update row, 0x0002 is a bitmask of present column data, keys are excluded */
2924 static const WCHAR data6[] = { /* MOO */
2925     0x000a, 0x8001, 0x0004, 0x8005, /* update row */
2926     0x0000, 0x8003,         /* delete row */
2927 };
2928 
2929 static const WCHAR data7[] = { /* BINARY */
2930     0x0201, 0x8001, 0x0001,
2931 };
2932 
2933 static const char data8[] =  /* stream data for the BINARY table */
2934     "naengmyon";
2935 
2936 static const WCHAR data9[] = { /* Property */
2937     0x0201, 0x000c, 0x000d,
2938 };
2939 
2940 static const struct {
2941     LPCWSTR name;
2942     const void *data;
2943     DWORD size;
2944 } table_transform_data[] =
2945 {
2946     { name1, data1, sizeof data1 },
2947     { name2, data2, sizeof data2 },
2948     { name3, data3, sizeof data3 },
2949     { name4, data4, sizeof data4 - 1 },
2950     { name5, data5, sizeof data5 },
2951     { name6, data6, sizeof data6 },
2952     { name7, data7, sizeof data7 },
2953     { name8, data8, sizeof data8 - 1 },
2954     { name9, data9, sizeof data9 },
2955 };
2956 
2957 static void generate_transform_manual(void)
2958 {
2959     IStorage *stg = NULL;
2960     IStream *stm;
2961     WCHAR name[0x20];
2962     HRESULT r;
2963     DWORD i, count;
2964     const DWORD mode = STGM_CREATE|STGM_READWRITE|STGM_DIRECT|STGM_SHARE_EXCLUSIVE;
2965 
2966     const CLSID CLSID_MsiTransform = { 0xc1082,0,0,{0xc0,0,0,0,0,0,0,0x46}};
2967 
2968     MultiByteToWideChar(CP_ACP, 0, mstfile, -1, name, 0x20);
2969 
2970     r = StgCreateDocfile(name, mode, 0, &stg);
2971     ok(r == S_OK, "failed to create storage\n");
2972     if (!stg)
2973         return;
2974 
2975     r = IStorage_SetClass( stg, &CLSID_MsiTransform );
2976     ok(r == S_OK, "failed to set storage type\n");
2977 
2978     for (i=0; i<ARRAY_SIZE(table_transform_data); i++)
2979     {
2980         r = IStorage_CreateStream( stg, table_transform_data[i].name,
2981                             STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stm );
2982         if (FAILED(r))
2983         {
2984             ok(0, "failed to create stream %#lx\n", r);
2985             continue;
2986         }
2987 
2988         r = IStream_Write( stm, table_transform_data[i].data,
2989                           table_transform_data[i].size, &count );
2990         if (FAILED(r) || count != table_transform_data[i].size)
2991             ok(0, "failed to write stream\n");
2992         IStream_Release(stm);
2993     }
2994 
2995     IStorage_Release(stg);
2996 }
2997 
2998 static UINT set_summary_info(MSIHANDLE hdb)
2999 {
3000     UINT res;
3001     MSIHANDLE suminfo;
3002 
3003     /* build summary info */
3004     res = MsiGetSummaryInformationA(hdb, NULL, 7, &suminfo);
3005     ok( res == ERROR_SUCCESS , "Failed to open summaryinfo\n" );
3006 
3007     res = MsiSummaryInfoSetPropertyA(suminfo,2, VT_LPSTR, 0,NULL,
3008                         "Installation Database");
3009     ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
3010 
3011     res = MsiSummaryInfoSetPropertyA(suminfo,3, VT_LPSTR, 0,NULL,
3012                         "Installation Database");
3013     ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
3014 
3015     res = MsiSummaryInfoSetPropertyA(suminfo,4, VT_LPSTR, 0,NULL,
3016                         "Wine Hackers");
3017     ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
3018 
3019     res = MsiSummaryInfoSetPropertyA(suminfo,7, VT_LPSTR, 0,NULL,
3020                     ";1033,2057");
3021     ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
3022 
3023     res = MsiSummaryInfoSetPropertyA(suminfo,9, VT_LPSTR, 0,NULL,
3024                     "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}");
3025     ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
3026 
3027     res = MsiSummaryInfoSetPropertyA(suminfo, 14, VT_I4, 100, NULL, NULL);
3028     ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
3029 
3030     res = MsiSummaryInfoSetPropertyA(suminfo, 15, VT_I4, 0, NULL, NULL);
3031     ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
3032 
3033     res = MsiSummaryInfoPersist(suminfo);
3034     ok( res == ERROR_SUCCESS , "Failed to make summary info persist\n" );
3035 
3036     res = MsiCloseHandle( suminfo);
3037     ok( res == ERROR_SUCCESS , "Failed to close suminfo\n" );
3038 
3039     return res;
3040 }
3041 
3042 static MSIHANDLE create_package_db(const WCHAR *filename)
3043 {
3044     MSIHANDLE hdb = 0;
3045     UINT res;
3046 
3047     DeleteFileW(msifileW);
3048 
3049     /* create an empty database */
3050     res = MsiOpenDatabaseW(filename, MSIDBOPEN_CREATE, &hdb );
3051     ok( res == ERROR_SUCCESS , "Failed to create database\n" );
3052     if( res != ERROR_SUCCESS )
3053         return hdb;
3054 
3055     res = MsiDatabaseCommit( hdb );
3056     ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
3057 
3058     res = set_summary_info(hdb);
3059     ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
3060 
3061     create_directory_table(hdb);
3062 
3063     return hdb;
3064 }
3065 
3066 static UINT package_from_db(MSIHANDLE hdb, MSIHANDLE *handle)
3067 {
3068     UINT res;
3069     CHAR szPackage[12];
3070     MSIHANDLE hPackage;
3071 
3072     sprintf(szPackage, "#%lu", hdb);
3073     res = MsiOpenPackageA(szPackage, &hPackage);
3074     if (res != ERROR_SUCCESS)
3075         return res;
3076 
3077     res = MsiCloseHandle(hdb);
3078     if (res != ERROR_SUCCESS)
3079     {
3080         MsiCloseHandle(hPackage);
3081         return res;
3082     }
3083 
3084     *handle = hPackage;
3085     return ERROR_SUCCESS;
3086 }
3087 
3088 static void test_try_transform(void)
3089 {
3090     static const struct {
3091         const char *table;
3092         const char *column;
3093         const char *row;
3094         const char *data;
3095         const char *current;
3096     } transform_view[] = {
3097         { "MOO", "OOO", "1", "c", "a" },
3098         { "MOO", "COW", "", "5378", "3" },
3099         { "MOO", "PIG", "", "5378", "4" },
3100         { "MOO", "PIG", "1", "5", "" },
3101         { "MOO", "DELETE", "3", "", "" },
3102         { "BINARY", "BLOB", "1", "BINARY.1", "" },
3103         { "BINARY", "INSERT", "1", "", "" },
3104         { "AAR", "CREATE", "", "", "" },
3105         { "AAR", "CAR", "", "15871", "1" },
3106         { "AAR", "BAR", "", "1282", "2" },
3107         { "AAR", "BAR", "vw", "1", "" },
3108         { "AAR", "BAR", "bmw", "2", "" },
3109         { "AAR", "INSERT", "vw", "", "" },
3110         { "AAR", "INSERT", "bmw", "", "" },
3111         { "Property", "CREATE", "", "", "" },
3112         { "Property", "Property", "", "11592", "1" },
3113         { "Property", "Value", "", "7424", "2" },
3114         { "Property", "Value", "prop", "val", "" },
3115         { "Property", "INSERT", "prop", "", "" }
3116     };
3117 
3118     MSIHANDLE hdb, hview, hrec, hpkg = 0;
3119     LPCSTR query;
3120     UINT r;
3121     DWORD sz;
3122     char buffer[MAX_PATH];
3123     int i, matched;
3124 
3125     DeleteFileA(msifile);
3126     DeleteFileA(mstfile);
3127 
3128     /* create the database */
3129     hdb = create_package_db(msifileW);
3130     ok(hdb, "Failed to create package db\n");
3131 
3132     query = "CREATE TABLE `MOO` ( `NOO` SHORT NOT NULL, `OOO` CHAR(255) PRIMARY KEY `NOO`)";
3133     r = run_query(hdb, 0, query);
3134     ok(r == ERROR_SUCCESS, "failed to add table\n");
3135 
3136     query = "INSERT INTO `MOO` ( `NOO`, `OOO` ) VALUES ( 1, 'a' )";
3137     r = run_query(hdb, 0, query);
3138     ok(r == ERROR_SUCCESS, "failed to add row\n");
3139 
3140     query = "INSERT INTO `MOO` ( `NOO`, `OOO` ) VALUES ( 2, 'b' )";
3141     r = run_query(hdb, 0, query);
3142     ok(r == ERROR_SUCCESS, "failed to add row\n");
3143 
3144     query = "INSERT INTO `MOO` ( `NOO`, `OOO` ) VALUES ( 3, 'c' )";
3145     r = run_query(hdb, 0, query);
3146     ok(r == ERROR_SUCCESS, "failed to add row\n");
3147 
3148     query = "CREATE TABLE `BINARY` ( `ID` SHORT NOT NULL, `BLOB` OBJECT PRIMARY KEY `ID`)";
3149     r = run_query(hdb, 0, query);
3150     ok(r == ERROR_SUCCESS, "failed to add table\n");
3151 
3152     hrec = MsiCreateRecord(2);
3153     r = MsiRecordSetInteger(hrec, 1, 2);
3154     ok(r == ERROR_SUCCESS, "failed to set integer\n");
3155 
3156     write_file("testdata.bin", "lamyon", 6);
3157     r = MsiRecordSetStreamA(hrec, 2, "testdata.bin");
3158     ok(r == ERROR_SUCCESS, "failed to set stream\n");
3159 
3160     query = "INSERT INTO `BINARY` ( `ID`, `BLOB` ) VALUES ( ?, ? )";
3161     r = run_query(hdb, hrec, query);
3162     ok(r == ERROR_SUCCESS, "failed to add row with blob\n");
3163 
3164     MsiCloseHandle(hrec);
3165 
3166     r = MsiDatabaseCommit( hdb );
3167     ok( r == ERROR_SUCCESS , "Failed to commit database\n" );
3168 
3169     MsiCloseHandle( hdb );
3170     DeleteFileA("testdata.bin");
3171 
3172     /*
3173      * Both these generate an equivalent transform,
3174      *  but the first doesn't work in Wine yet
3175      *  because MsiDatabaseGenerateTransform is unimplemented.
3176      */
3177     if (0)
3178         generate_transform();
3179     else
3180         generate_transform_manual();
3181 
3182     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_DIRECT, &hdb );
3183     ok( r == ERROR_SUCCESS , "Failed to create database\n" );
3184 
3185     r = MsiDatabaseApplyTransformA(hdb, mstfile, MSITRANSFORM_ERROR_VIEWTRANSFORM);
3186     ok(r == ERROR_SUCCESS, "return code %d, should be ERROR_SUCCESS\n", r);
3187 
3188     query = "select * from `_TransformView`";
3189     r = MsiDatabaseOpenViewA(hdb, query, &hview);
3190     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
3191     r = MsiViewExecute(hview, 0);
3192     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
3193 
3194     r = MsiViewGetColumnInfo(hview, MSICOLINFO_NAMES, &hrec);
3195     ok(r == ERROR_SUCCESS, "error\n");
3196     check_record(hrec, 5, "Table", "Column", "Row", "Data", "Current");
3197     MsiCloseHandle(hrec);
3198 
3199     r = MsiViewGetColumnInfo(hview, MSICOLINFO_TYPES, &hrec);
3200     ok(r == ERROR_SUCCESS, "error\n");
3201     check_record(hrec, 5, "g0", "g0", "G0", "G0", "G0");
3202     MsiCloseHandle(hrec);
3203 
3204     matched = 0;
3205     while (MsiViewFetch(hview, &hrec) == ERROR_SUCCESS)
3206     {
3207         char data[5][256];
3208 
3209         for (i = 1; i <= 5; i++) {
3210             sz = ARRAY_SIZE(data[0]);
3211             r = MsiRecordGetStringA(hrec, i, data[i-1], &sz);
3212             ok(r == ERROR_SUCCESS, "%d) MsiRecordGetStringA failed %d\n", i, r);
3213         }
3214 
3215         for (i = 0; i < ARRAY_SIZE(transform_view); i++)
3216         {
3217             if (strcmp(data[0], transform_view[i].table) ||
3218                     strcmp(data[1], transform_view[i].column) ||
3219                     strcmp(data[2], transform_view[i].row))
3220                 continue;
3221 
3222             matched++;
3223             ok(!strcmp(data[3], transform_view[i].data), "%d) data[3] = %s\n", i, data[3]);
3224             ok(!strcmp(data[4], transform_view[i].current), "%d) data[4] = %s\n", i, data[4]);
3225             break;
3226         }
3227         ok(i != ARRAY_SIZE(transform_view), "invalid row: %s, %s, %s\n",
3228                 wine_dbgstr_a(data[0]), wine_dbgstr_a(data[1]), wine_dbgstr_a(data[2]));
3229         MsiCloseHandle(hrec);
3230     }
3231     ok(matched == ARRAY_SIZE(transform_view), "matched = %d\n", matched);
3232 
3233     r = MsiViewClose(hview);
3234     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
3235     r = MsiCloseHandle(hview);
3236     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
3237 
3238     query = "ALTER TABLE `_TransformView` FREE";
3239     r = run_query( hdb, 0, query );
3240     ok( r == ERROR_SUCCESS, "cannot free _TransformView table: %d\n", r );
3241     r = run_query( hdb, 0, query );
3242     ok( r == ERROR_BAD_QUERY_SYNTAX, "_TransformView table still exist: %d\n", r );
3243 
3244     r = MsiDatabaseApplyTransformA( hdb, mstfile, 0 );
3245     ok( r == ERROR_SUCCESS, "return code %d, should be ERROR_SUCCESS\n", r );
3246 
3247     r = MsiDatabaseCommit( hdb );
3248     ok( r == ERROR_SUCCESS , "Failed to commit database\n" );
3249 
3250     /* check new values */
3251     hrec = 0;
3252     query = "select `BAR`,`CAR` from `AAR` where `BAR` = 1 AND `CAR` = 'vw'";
3253     r = do_query(hdb, query, &hrec);
3254     ok(r == ERROR_SUCCESS, "select query failed\n");
3255     MsiCloseHandle(hrec);
3256 
3257     query = "select `BAR`,`CAR` from `AAR` where `BAR` = 2 AND `CAR` = 'bmw'";
3258     hrec = 0;
3259     r = do_query(hdb, query, &hrec);
3260     ok(r == ERROR_SUCCESS, "select query failed\n");
3261     MsiCloseHandle(hrec);
3262 
3263     /* check updated values */
3264     hrec = 0;
3265     query = "select `NOO`,`OOO` from `MOO` where `NOO` = 1 AND `OOO` = 'c'";
3266     r = do_query(hdb, query, &hrec);
3267     ok(r == ERROR_SUCCESS, "select query failed\n");
3268     MsiCloseHandle(hrec);
3269 
3270     /* check unchanged value */
3271     hrec = 0;
3272     query = "select `NOO`,`OOO` from `MOO` where `NOO` = 2 AND `OOO` = 'b'";
3273     r = do_query(hdb, query, &hrec);
3274     ok(r == ERROR_SUCCESS, "select query failed\n");
3275     MsiCloseHandle(hrec);
3276 
3277     /* check deleted value */
3278     hrec = 0;
3279     query = "select * from `MOO` where `NOO` = 3";
3280     r = do_query(hdb, query, &hrec);
3281     ok(r == ERROR_NO_MORE_ITEMS, "select query failed\n");
3282     if (hrec) MsiCloseHandle(hrec);
3283 
3284     /* check added stream */
3285     hrec = 0;
3286     query = "select `BLOB` from `BINARY` where `ID` = 1";
3287     r = do_query(hdb, query, &hrec);
3288     ok(r == ERROR_SUCCESS, "select query failed\n");
3289 
3290     /* check the contents of the stream */
3291     sz = sizeof buffer;
3292     r = MsiRecordReadStream( hrec, 1, buffer, &sz );
3293     ok(r == ERROR_SUCCESS, "read stream failed\n");
3294     ok(!memcmp(buffer, "naengmyon", 9), "stream data was wrong\n");
3295     ok(sz == 9, "stream data was wrong size\n");
3296     if (hrec) MsiCloseHandle(hrec);
3297 
3298     /* check the validity of the table with a deleted row */
3299     hrec = 0;
3300     query = "select * from `MOO`";
3301     r = MsiDatabaseOpenViewA(hdb, query, &hview);
3302     ok(r == ERROR_SUCCESS, "open view failed\n");
3303 
3304     r = MsiViewExecute(hview, 0);
3305     ok(r == ERROR_SUCCESS, "view execute failed\n");
3306 
3307     r = MsiViewFetch(hview, &hrec);
3308     ok(r == ERROR_SUCCESS, "view fetch failed\n");
3309     check_record(hrec, 4, "1", "c", "", "5");
3310     MsiCloseHandle(hrec);
3311 
3312     r = MsiViewFetch(hview, &hrec);
3313     ok(r == ERROR_SUCCESS, "view fetch failed\n");
3314     check_record(hrec, 4, "2", "b", "", "");
3315     MsiCloseHandle(hrec);
3316 
3317     r = MsiViewFetch(hview, &hrec);
3318     ok(r == ERROR_NO_MORE_ITEMS, "view fetch succeeded\n");
3319 
3320     MsiCloseHandle(hrec);
3321     MsiViewClose(hview);
3322     MsiCloseHandle(hview);
3323 
3324     /* check that the property was added */
3325     r = package_from_db(hdb, &hpkg);
3326     if (r == ERROR_INSTALL_PACKAGE_REJECTED)
3327     {
3328         skip("Not enough rights to perform tests\n");
3329         goto error;
3330     }
3331     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
3332 
3333     sz = MAX_PATH;
3334     r = MsiGetPropertyA(hpkg, "prop", buffer, &sz);
3335     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3336     ok(!lstrcmpA(buffer, "val"), "Expected val, got %s\n", buffer);
3337 
3338     MsiCloseHandle(hpkg);
3339 
3340 error:
3341     MsiCloseHandle(hdb);
3342     DeleteFileA(msifile);
3343     DeleteFileA(mstfile);
3344 }
3345 
3346 static const char *join_res_first[][2] =
3347 {
3348     { "alveolar", "procerus" },
3349     { "septum", "procerus" },
3350     { "septum", "nasalis" },
3351     { "ramus", "nasalis" },
3352     { "malar", "mentalis" },
3353 };
3354 
3355 static const char *join_res_second[][2] =
3356 {
3357     { "nasal", "septum" },
3358     { "mandible", "ramus" },
3359 };
3360 
3361 static const char *join_res_third[][2] =
3362 {
3363     { "msvcp.dll", "abcdefgh" },
3364     { "msvcr.dll", "ijklmnop" },
3365 };
3366 
3367 static const char *join_res_fourth[][2] =
3368 {
3369     { "msvcp.dll.01234", "single.dll.31415" },
3370 };
3371 
3372 static const char *join_res_fifth[][2] =
3373 {
3374     { "malar", "procerus" },
3375 };
3376 
3377 static const char *join_res_sixth[][2] =
3378 {
3379     { "malar", "procerus" },
3380     { "malar", "procerus" },
3381     { "malar", "nasalis" },
3382     { "malar", "nasalis" },
3383     { "malar", "nasalis" },
3384     { "malar", "mentalis" },
3385 };
3386 
3387 static const char *join_res_seventh[][2] =
3388 {
3389     { "malar", "nasalis" },
3390     { "malar", "nasalis" },
3391     { "malar", "nasalis" },
3392 };
3393 
3394 static const char *join_res_eighth[][4] =
3395 {
3396     { "msvcp.dll", "msvcp.dll.01234", "msvcp.dll.01234", "abcdefgh" },
3397     { "msvcr.dll", "msvcr.dll.56789", "msvcp.dll.01234", "abcdefgh" },
3398     { "msvcp.dll", "msvcp.dll.01234", "msvcr.dll.56789", "ijklmnop" },
3399     { "msvcr.dll", "msvcr.dll.56789", "msvcr.dll.56789", "ijklmnop" },
3400     { "msvcp.dll", "msvcp.dll.01234", "single.dll.31415", "msvcp.dll" },
3401     { "msvcr.dll", "msvcr.dll.56789", "single.dll.31415", "msvcp.dll" },
3402 };
3403 
3404 static const char *join_res_ninth[][6] =
3405 {
3406     { "1", "2", "3", "4", "7", "8" },
3407     { "1", "2", "5", "6", "7", "8" },
3408     { "1", "2", "3", "4", "9", "10" },
3409     { "1", "2", "5", "6", "9", "10" },
3410     { "1", "2", "3", "4", "11", "12" },
3411     { "1", "2", "5", "6", "11", "12" },
3412 };
3413 
3414 static void test_join(void)
3415 {
3416     MSIHANDLE hdb, hview, hrec;
3417     LPCSTR query;
3418     UINT r;
3419     DWORD i;
3420 
3421     hdb = create_db();
3422     ok( hdb, "failed to create db\n");
3423 
3424     create_component_table( hdb );
3425     add_component_entry( hdb, "'zygomatic', 'malar', 'INSTALLDIR', 0, '', ''" );
3426     add_component_entry( hdb, "'maxilla', 'alveolar', 'INSTALLDIR', 0, '', ''" );
3427     add_component_entry( hdb, "'nasal', 'septum', 'INSTALLDIR', 0, '', ''" );
3428     add_component_entry( hdb, "'mandible', 'ramus', 'INSTALLDIR', 0, '', ''" );
3429 
3430     create_feature_components_table( hdb );
3431     add_feature_components_entry( hdb, "'procerus', 'maxilla'" );
3432     add_feature_components_entry( hdb, "'procerus', 'nasal'" );
3433     add_feature_components_entry( hdb, "'nasalis', 'nasal'" );
3434     add_feature_components_entry( hdb, "'nasalis', 'mandible'" );
3435     add_feature_components_entry( hdb, "'nasalis', 'notacomponent'" );
3436     add_feature_components_entry( hdb, "'mentalis', 'zygomatic'" );
3437 
3438     create_std_dlls_table( hdb );
3439     add_std_dlls_entry( hdb, "'msvcp.dll', 'msvcp.dll.01234'" );
3440     add_std_dlls_entry( hdb, "'msvcr.dll', 'msvcr.dll.56789'" );
3441 
3442     create_binary_table( hdb );
3443     add_binary_entry( hdb, "'msvcp.dll.01234', 'abcdefgh'" );
3444     add_binary_entry( hdb, "'msvcr.dll.56789', 'ijklmnop'" );
3445     add_binary_entry( hdb, "'single.dll.31415', 'msvcp.dll'" );
3446 
3447     query = "CREATE TABLE `One` (`A` SHORT, `B` SHORT PRIMARY KEY `A`)";
3448     r = run_query( hdb, 0, query);
3449     ok(r == ERROR_SUCCESS, "cannot create table: %d\n", r );
3450 
3451     query = "CREATE TABLE `Two` (`C` SHORT, `D` SHORT PRIMARY KEY `C`)";
3452     r = run_query( hdb, 0, query);
3453     ok(r == ERROR_SUCCESS, "cannot create table: %d\n", r );
3454 
3455     query = "CREATE TABLE `Three` (`E` SHORT, `F` SHORT PRIMARY KEY `E`)";
3456     r = run_query( hdb, 0, query);
3457     ok(r == ERROR_SUCCESS, "cannot create table: %d\n", r );
3458 
3459     query = "INSERT INTO `One` (`A`, `B`) VALUES (1, 2)";
3460     r = run_query( hdb, 0, query);
3461     ok(r == ERROR_SUCCESS, "cannot insert into table: %d\n", r );
3462 
3463     query = "INSERT INTO `Two` (`C`, `D`) VALUES (3, 4)";
3464     r = run_query( hdb, 0, query);
3465     ok(r == ERROR_SUCCESS, "cannot insert into table: %d\n", r );
3466 
3467     query = "INSERT INTO `Two` (`C`, `D`) VALUES (5, 6)";
3468     r = run_query( hdb, 0, query);
3469     ok(r == ERROR_SUCCESS, "cannot insert into table: %d\n", r );
3470 
3471     query = "INSERT INTO `Three` (`E`, `F`) VALUES (7, 8)";
3472     r = run_query( hdb, 0, query);
3473     ok(r == ERROR_SUCCESS, "cannot insert into table: %d\n", r );
3474 
3475     query = "INSERT INTO `Three` (`E`, `F`) VALUES (9, 10)";
3476     r = run_query( hdb, 0, query);
3477     ok(r == ERROR_SUCCESS, "cannot insert into table: %d\n", r );
3478 
3479     query = "INSERT INTO `Three` (`E`, `F`) VALUES (11, 12)";
3480     r = run_query( hdb, 0, query);
3481     ok(r == ERROR_SUCCESS, "cannot insert into table: %d\n", r );
3482 
3483     query = "CREATE TABLE `Four` (`G` SHORT, `H` SHORT PRIMARY KEY `G`)";
3484     r = run_query( hdb, 0, query);
3485     ok(r == ERROR_SUCCESS, "cannot create table: %d\n", r );
3486 
3487     query = "CREATE TABLE `Five` (`I` SHORT, `J` SHORT PRIMARY KEY `I`)";
3488     r = run_query( hdb, 0, query);
3489     ok(r == ERROR_SUCCESS, "cannot create table: %d\n", r );
3490 
3491     query = "INSERT INTO `Five` (`I`, `J`) VALUES (13, 14)";
3492     r = run_query( hdb, 0, query);
3493     ok(r == ERROR_SUCCESS, "cannot insert into table: %d\n", r );
3494 
3495     query = "INSERT INTO `Five` (`I`, `J`) VALUES (15, 16)";
3496     r = run_query( hdb, 0, query);
3497     ok(r == ERROR_SUCCESS, "cannot insert into table: %d\n", r );
3498 
3499     query = "SELECT `Component`.`ComponentId`, `FeatureComponents`.`Feature_` "
3500             "FROM `Component`, `FeatureComponents` "
3501             "WHERE `Component`.`Component` = `FeatureComponents`.`Component_` "
3502             "ORDER BY `Feature_`";
3503     r = MsiDatabaseOpenViewA(hdb, query, &hview);
3504     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3505 
3506     r = MsiViewExecute(hview, 0);
3507     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3508 
3509     i = 0;
3510     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3511     {
3512         check_record(hrec, 2, join_res_first[i][0], join_res_first[i][1]);
3513         i++;
3514         MsiCloseHandle(hrec);
3515     }
3516     ok( i == 5, "Expected 5 rows, got %lu\n", i );
3517     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3518 
3519     MsiViewClose(hview);
3520     MsiCloseHandle(hview);
3521 
3522     /* try a join without a WHERE condition */
3523     query = "SELECT `Component`.`ComponentId`, `FeatureComponents`.`Feature_` "
3524             "FROM `Component`, `FeatureComponents` ";
3525     r = MsiDatabaseOpenViewA(hdb, query, &hview);
3526     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3527 
3528     r = MsiViewExecute(hview, 0);
3529     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3530 
3531     i = 0;
3532     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3533     {
3534         i++;
3535         MsiCloseHandle(hrec);
3536     }
3537     ok( i == 24, "Expected 24 rows, got %lu\n", i );
3538 
3539     MsiViewClose(hview);
3540     MsiCloseHandle(hview);
3541 
3542     query = "SELECT DISTINCT Component, ComponentId FROM FeatureComponents, Component "
3543             "WHERE FeatureComponents.Component_=Component.Component "
3544             "AND (Feature_='nasalis') ORDER BY Feature_";
3545     r = MsiDatabaseOpenViewA(hdb, query, &hview);
3546     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3547 
3548     r = MsiViewExecute(hview, 0);
3549     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3550 
3551     i = 0;
3552     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3553     {
3554         check_record(hrec, 2, join_res_second[i][0], join_res_second[i][1]);
3555         i++;
3556         MsiCloseHandle(hrec);
3557     }
3558 
3559     ok( i == 2, "Expected 2 rows, got %lu\n", i );
3560     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3561 
3562     MsiViewClose(hview);
3563     MsiCloseHandle(hview);
3564 
3565     query = "SELECT `StdDlls`.`File`, `Binary`.`Data` "
3566             "FROM `StdDlls`, `Binary` "
3567             "WHERE `StdDlls`.`Binary_` = `Binary`.`Name` "
3568             "ORDER BY `File`";
3569     r = MsiDatabaseOpenViewA(hdb, query, &hview);
3570     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3571 
3572     r = MsiViewExecute(hview, 0);
3573     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3574 
3575     i = 0;
3576     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3577     {
3578         check_record(hrec, 2, join_res_third[i][0], join_res_third[i][1]);
3579         i++;
3580         MsiCloseHandle(hrec);
3581     }
3582     ok( i == 2, "Expected 2 rows, got %lu\n", i );
3583     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3584 
3585     MsiViewClose(hview);
3586     MsiCloseHandle(hview);
3587 
3588     query = "SELECT `StdDlls`.`Binary_`, `Binary`.`Name` "
3589             "FROM `StdDlls`, `Binary` "
3590             "WHERE `StdDlls`.`File` = `Binary`.`Data` "
3591             "ORDER BY `Name`";
3592     r = MsiDatabaseOpenViewA(hdb, query, &hview);
3593     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3594 
3595     r = MsiViewExecute(hview, 0);
3596     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3597 
3598     i = 0;
3599     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3600     {
3601         check_record(hrec, 2, join_res_fourth[i][0], join_res_fourth[i][1]);
3602         i++;
3603         MsiCloseHandle(hrec);
3604     }
3605     ok( i == 1, "Expected 1 rows, got %lu\n", i );
3606     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3607 
3608     MsiViewClose(hview);
3609     MsiCloseHandle(hview);
3610 
3611     query = "SELECT `Component`.`ComponentId`, `FeatureComponents`.`Feature_` "
3612             "FROM `Component`, `FeatureComponents` "
3613             "WHERE `Component`.`Component` = 'zygomatic' "
3614             "AND `FeatureComponents`.`Component_` = 'maxilla' "
3615             "ORDER BY `Feature_`";
3616     r = MsiDatabaseOpenViewA(hdb, query, &hview);
3617     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3618 
3619     r = MsiViewExecute(hview, 0);
3620     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3621 
3622     i = 0;
3623     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3624     {
3625         check_record(hrec, 2, join_res_fifth[i][0], join_res_fifth[i][1]);
3626         i++;
3627         MsiCloseHandle(hrec);
3628     }
3629     ok( i == 1, "Expected 1 rows, got %lu\n", i );
3630     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3631 
3632     MsiViewClose(hview);
3633     MsiCloseHandle(hview);
3634 
3635     query = "SELECT `Component`.`ComponentId`, `FeatureComponents`.`Feature_` "
3636             "FROM `Component`, `FeatureComponents` "
3637             "WHERE `Component` = 'zygomatic' "
3638             "ORDER BY `Feature_`";
3639     r = MsiDatabaseOpenViewA(hdb, query, &hview);
3640     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3641 
3642     r = MsiViewExecute(hview, 0);
3643     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3644 
3645     i = 0;
3646     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3647     {
3648         check_record(hrec, 2, join_res_sixth[i][0], join_res_sixth[i][1]);
3649         i++;
3650         MsiCloseHandle(hrec);
3651     }
3652     ok( i == 6, "Expected 6 rows, got %lu\n", i );
3653     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3654 
3655     MsiViewClose(hview);
3656     MsiCloseHandle(hview);
3657 
3658     query = "SELECT `Component`.`ComponentId`, `FeatureComponents`.`Feature_` "
3659             "FROM `Component`, `FeatureComponents` "
3660             "WHERE `Component` = 'zygomatic' "
3661             "AND `Feature_` = 'nasalis' "
3662             "ORDER BY `Feature_`";
3663     r = MsiDatabaseOpenViewA(hdb, query, &hview);
3664     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3665 
3666     r = MsiViewExecute(hview, 0);
3667     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3668 
3669     i = 0;
3670     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3671     {
3672         check_record(hrec, 2, join_res_seventh[i][0], join_res_seventh[i][1]);
3673         i++;
3674         MsiCloseHandle(hrec);
3675     }
3676     ok( i == 3, "Expected 3 rows, got %lu\n", i );
3677     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3678 
3679     MsiViewClose(hview);
3680     MsiCloseHandle(hview);
3681 
3682     query = "SELECT `StdDlls`.`File`, `Binary`.`Data` "
3683             "FROM `StdDlls`, `Binary` ";
3684     r = MsiDatabaseOpenViewA(hdb, query, &hview);
3685     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3686 
3687     r = MsiViewExecute(hview, 0);
3688     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3689 
3690     i = 0;
3691     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3692     {
3693         check_record(hrec, 2, join_res_eighth[i][0], join_res_eighth[i][3]);
3694         i++;
3695         MsiCloseHandle(hrec);
3696     }
3697     ok( i == 6, "Expected 6 rows, got %lu\n", i );
3698     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3699 
3700     MsiViewClose(hview);
3701     MsiCloseHandle(hview);
3702 
3703     query = "SELECT * FROM `StdDlls`, `Binary` ";
3704     r = MsiDatabaseOpenViewA(hdb, query, &hview);
3705     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3706 
3707     r = MsiViewExecute(hview, 0);
3708     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3709 
3710     i = 0;
3711     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3712     {
3713         check_record(hrec, 4, join_res_eighth[i][0], join_res_eighth[i][1],
3714                 join_res_eighth[i][2], join_res_eighth[i][3]);
3715         i++;
3716         MsiCloseHandle(hrec);
3717     }
3718     ok( i == 6, "Expected 6 rows, got %lu\n", i );
3719     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3720 
3721     MsiViewClose(hview);
3722     MsiCloseHandle(hview);
3723 
3724     query = "SELECT * FROM `One`, `Two`, `Three` ";
3725     r = MsiDatabaseOpenViewA(hdb, query, &hview);
3726     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3727 
3728     r = MsiViewExecute(hview, 0);
3729     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3730 
3731     i = 0;
3732     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3733     {
3734         check_record(hrec, 6, join_res_ninth[i][0], join_res_ninth[i][1],
3735                 join_res_ninth[i][2], join_res_ninth[i][3],
3736                 join_res_ninth[i][4], join_res_ninth[i][5]);
3737         i++;
3738         MsiCloseHandle(hrec);
3739     }
3740     ok( i == 6, "Expected 6 rows, got %lu\n", i );
3741     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3742 
3743     MsiViewClose(hview);
3744     MsiCloseHandle(hview);
3745 
3746     query = "SELECT * FROM `Four`, `Five`";
3747     r = MsiDatabaseOpenViewA(hdb, query, &hview);
3748     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3749 
3750     r = MsiViewExecute(hview, 0);
3751     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3752 
3753     r = MsiViewFetch(hview, &hrec);
3754     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
3755 
3756     MsiViewClose(hview);
3757     MsiCloseHandle(hview);
3758 
3759     query = "SELECT * FROM `Nonexistent`, `One`";
3760     r = MsiDatabaseOpenViewA(hdb, query, &hview);
3761     ok( r == ERROR_BAD_QUERY_SYNTAX,
3762         "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r );
3763 
3764     /* try updating a row in a join table */
3765     query = "SELECT `Component`.`ComponentId`, `FeatureComponents`.`Feature_` "
3766             "FROM `Component`, `FeatureComponents` "
3767             "WHERE `Component`.`Component` = `FeatureComponents`.`Component_` "
3768             "ORDER BY `Feature_`";
3769     r = MsiDatabaseOpenViewA(hdb, query, &hview);
3770     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3771 
3772     r = MsiViewExecute(hview, 0);
3773     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3774 
3775     r = MsiViewFetch(hview, &hrec);
3776     ok( r == ERROR_SUCCESS, "failed to fetch view: %d\n", r );
3777     check_record(hrec, 2, "alveolar", "procerus");
3778 
3779     r = MsiRecordSetStringA( hrec, 1, "fascia" );
3780     ok( r == ERROR_SUCCESS, "failed to set string: %d\n", r );
3781     r = MsiRecordSetStringA( hrec, 2, "pterygoid" );
3782     ok( r == ERROR_SUCCESS, "failed to set string: %d\n", r );
3783 
3784     r = MsiViewModify(hview, MSIMODIFY_REFRESH, hrec);
3785     ok( r == ERROR_SUCCESS, "failed to refresh row: %d\n", r );
3786     check_record(hrec, 2, "alveolar", "procerus");
3787 
3788     r = MsiRecordSetStringA( hrec, 1, "epicranius" );
3789     ok( r == ERROR_SUCCESS, "failed to set string: %d\n", r );
3790 
3791     r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
3792     ok( r == ERROR_SUCCESS, "failed to update row: %d\n", r );
3793 
3794     /* primary key cannot be updated */
3795     r = MsiRecordSetStringA( hrec, 2, "epicranius" );
3796     ok( r == ERROR_SUCCESS, "failed to set string: %d\n", r );
3797 
3798     r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
3799     ok( r == ERROR_FUNCTION_FAILED, "failed to update row: %d\n", r );
3800 
3801     /* all other operations are invalid for joins */
3802     r = MsiViewModify(hview, MSIMODIFY_SEEK, hrec);
3803     ok( r == ERROR_FUNCTION_FAILED, "unexpected result: %d\n", r );
3804 
3805     r = MsiViewModify(hview, MSIMODIFY_ASSIGN, hrec);
3806     ok( r == ERROR_FUNCTION_FAILED, "unexpected result: %d\n", r );
3807 
3808     r = MsiViewModify(hview, MSIMODIFY_REPLACE, hrec);
3809     ok( r == ERROR_FUNCTION_FAILED, "unexpected result: %d\n", r );
3810 
3811     r = MsiViewModify(hview, MSIMODIFY_MERGE, hrec);
3812     ok( r == ERROR_FUNCTION_FAILED, "unexpected result: %d\n", r );
3813 
3814     r = MsiViewModify(hview, MSIMODIFY_DELETE, hrec);
3815     ok( r == ERROR_FUNCTION_FAILED, "unexpected result: %d\n", r );
3816 
3817     r = MsiViewModify(hview, MSIMODIFY_VALIDATE, hrec);
3818     ok( r == ERROR_FUNCTION_FAILED, "unexpected result: %d\n", r );
3819 
3820     r = MsiViewModify(hview, MSIMODIFY_VALIDATE_DELETE, hrec);
3821     ok( r == ERROR_FUNCTION_FAILED, "unexpected result: %d\n", r );
3822 
3823     MsiRecordSetStringA(hrec, 2, "epicranius");
3824     r = MsiViewModify(hview, MSIMODIFY_INSERT, hrec);
3825     ok( r == ERROR_FUNCTION_FAILED, "unexpected result: %d\n", r );
3826 
3827     r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec);
3828     ok( r == ERROR_FUNCTION_FAILED, "unexpected result: %d\n", r );
3829 
3830     r = MsiViewModify(hview, MSIMODIFY_VALIDATE_NEW, hrec);
3831     ok( r == ERROR_FUNCTION_FAILED, "unexpected result: %d\n", r );
3832 
3833     r = MsiViewModify(hview, MSIMODIFY_VALIDATE_FIELD, hrec);
3834     ok( r == ERROR_FUNCTION_FAILED, "unexpected result: %d\n", r );
3835 
3836     MsiCloseHandle(hrec);
3837     MsiViewClose(hview);
3838     MsiCloseHandle(hview);
3839 
3840     r = MsiDatabaseOpenViewA(hdb, query, &hview);
3841     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
3842 
3843     r = MsiViewExecute(hview, 0);
3844     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
3845 
3846     r = MsiViewFetch(hview, &hrec);
3847     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
3848     check_record(hrec, 2, "epicranius", "procerus");
3849     MsiCloseHandle(hrec);
3850 
3851     MsiViewClose(hview);
3852     MsiCloseHandle(hview);
3853 
3854     MsiCloseHandle(hdb);
3855     DeleteFileA(msifile);
3856 }
3857 
3858 static void test_temporary_table(void)
3859 {
3860     MSICONDITION cond;
3861     MSIHANDLE hdb = 0, view = 0, rec;
3862     const char *query;
3863     UINT r;
3864 
3865     cond = MsiDatabaseIsTablePersistentA(0, NULL);
3866     ok( cond == MSICONDITION_ERROR, "wrong return condition\n");
3867 
3868     hdb = create_db();
3869     ok( hdb, "failed to create db\n");
3870 
3871     cond = MsiDatabaseIsTablePersistentA(hdb, NULL);
3872     ok( cond == MSICONDITION_ERROR, "wrong return condition\n");
3873 
3874     cond = MsiDatabaseIsTablePersistentA(hdb, "_Tables");
3875     ok( cond == MSICONDITION_NONE, "wrong return condition\n");
3876 
3877     cond = MsiDatabaseIsTablePersistentA(hdb, "_Columns");
3878     ok( cond == MSICONDITION_NONE, "wrong return condition\n");
3879 
3880     cond = MsiDatabaseIsTablePersistentA(hdb, "_Storages");
3881     ok( cond == MSICONDITION_NONE, "wrong return condition\n");
3882 
3883     cond = MsiDatabaseIsTablePersistentA(hdb, "_Streams");
3884     ok( cond == MSICONDITION_NONE, "wrong return condition\n");
3885 
3886     query = "CREATE TABLE `P` ( `B` SHORT NOT NULL, `C` CHAR(255) PRIMARY KEY `C`)";
3887     r = run_query(hdb, 0, query);
3888     ok(r == ERROR_SUCCESS, "failed to add table\n");
3889 
3890     cond = MsiDatabaseIsTablePersistentA(hdb, "P");
3891     ok( cond == MSICONDITION_TRUE, "wrong return condition\n");
3892 
3893     query = "CREATE TABLE `P2` ( `B` SHORT NOT NULL, `C` CHAR(255) PRIMARY KEY `C`) HOLD";
3894     r = run_query(hdb, 0, query);
3895     ok(r == ERROR_SUCCESS, "failed to add table\n");
3896 
3897     cond = MsiDatabaseIsTablePersistentA(hdb, "P2");
3898     ok( cond == MSICONDITION_TRUE, "wrong return condition\n");
3899 
3900     query = "CREATE TABLE `T` ( `B` SHORT NOT NULL TEMPORARY, `C` CHAR(255) TEMPORARY PRIMARY KEY `C`) HOLD";
3901     r = run_query(hdb, 0, query);
3902     ok(r == ERROR_SUCCESS, "failed to add table\n");
3903 
3904     cond = MsiDatabaseIsTablePersistentA(hdb, "T");
3905     ok( cond == MSICONDITION_FALSE, "wrong return condition\n");
3906 
3907     query = "CREATE TABLE `T2` ( `B` SHORT NOT NULL TEMPORARY, `C` CHAR(255) TEMPORARY PRIMARY KEY `C`)";
3908     r = run_query(hdb, 0, query);
3909     ok(r == ERROR_SUCCESS, "failed to add table\n");
3910 
3911     query = "SELECT * FROM `T2`";
3912     r = MsiDatabaseOpenViewA(hdb, query, &view);
3913     ok(r == ERROR_BAD_QUERY_SYNTAX,
3914        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
3915 
3916     cond = MsiDatabaseIsTablePersistentA(hdb, "T2");
3917     ok( cond == MSICONDITION_NONE, "wrong return condition\n");
3918 
3919     query = "CREATE TABLE `T3` ( `B` SHORT NOT NULL TEMPORARY, `C` CHAR(255) PRIMARY KEY `C`)";
3920     r = run_query(hdb, 0, query);
3921     ok(r == ERROR_SUCCESS, "failed to add table\n");
3922 
3923     cond = MsiDatabaseIsTablePersistentA(hdb, "T3");
3924     ok( cond == MSICONDITION_TRUE, "wrong return condition\n");
3925 
3926     query = "CREATE TABLE `T4` ( `B` SHORT NOT NULL, `C` CHAR(255) TEMPORARY PRIMARY KEY `C`)";
3927     r = run_query(hdb, 0, query);
3928     ok(r == ERROR_FUNCTION_FAILED, "failed to add table\n");
3929 
3930     cond = MsiDatabaseIsTablePersistentA(hdb, "T4");
3931     ok( cond == MSICONDITION_NONE, "wrong return condition\n");
3932 
3933     query = "CREATE TABLE `T5` ( `B` SHORT NOT NULL TEMP, `C` CHAR(255) TEMP PRIMARY KEY `C`) HOLD";
3934     r = run_query(hdb, 0, query);
3935     ok(r == ERROR_BAD_QUERY_SYNTAX, "failed to add table\n");
3936 
3937     query = "select * from `T`";
3938     r = MsiDatabaseOpenViewA(hdb, query, &view);
3939     ok(r == ERROR_SUCCESS, "failed to query table\n");
3940     r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
3941     ok(r == ERROR_SUCCESS, "failed to get column info\n");
3942     check_record(rec, 2, "G255", "j2");
3943     MsiCloseHandle( rec );
3944 
3945     MsiViewClose( view );
3946     MsiCloseHandle( view );
3947 
3948     /* query the table data */
3949     rec = 0;
3950     r = do_query(hdb, "select * from `_Tables` where `Name` = 'T'", &rec);
3951     ok( r == ERROR_SUCCESS, "temporary table exists in _Tables\n");
3952     MsiCloseHandle( rec );
3953 
3954     /* query the column data */
3955     rec = 0;
3956     r = do_query(hdb, "select * from `_Columns` where `Table` = 'T' AND `Name` = 'B'", &rec);
3957     ok( r == ERROR_NO_MORE_ITEMS, "temporary table exists in _Columns\n");
3958     if (rec) MsiCloseHandle( rec );
3959 
3960     r = do_query(hdb, "select * from `_Columns` where `Table` = 'T' AND `Name` = 'C'", &rec);
3961     ok( r == ERROR_NO_MORE_ITEMS, "temporary table exists in _Columns\n");
3962     if (rec) MsiCloseHandle( rec );
3963 
3964     MsiCloseHandle( hdb );
3965     DeleteFileA(msifile);
3966 }
3967 
3968 static void test_alter(void)
3969 {
3970     MSICONDITION cond;
3971     MSIHANDLE hdb = 0, rec;
3972     const char *query;
3973     UINT r;
3974 
3975     hdb = create_db();
3976     ok( hdb, "failed to create db\n");
3977 
3978     query = "CREATE TABLE `T` ( `B` SHORT NOT NULL TEMPORARY, `C` CHAR(255) TEMPORARY PRIMARY KEY `C`)";
3979     r = run_query(hdb, 0, query);
3980     ok(r == ERROR_SUCCESS, "failed to add table\n");
3981 
3982     query = "SELECT * FROM `T`";
3983     r = run_query(hdb, 0, query);
3984     ok(r == ERROR_BAD_QUERY_SYNTAX, "expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
3985 
3986     query = "CREATE TABLE `T` ( `B` SHORT NOT NULL TEMPORARY, `C` CHAR(255) TEMPORARY PRIMARY KEY `C`) HOLD";
3987     r = run_query(hdb, 0, query);
3988     ok(r == ERROR_SUCCESS, "failed to add table\n");
3989 
3990     query = "SELECT * FROM `T`";
3991     r = run_query(hdb, 0, query);
3992     ok(r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", r);
3993 
3994     cond = MsiDatabaseIsTablePersistentA(hdb, "T");
3995     ok( cond == MSICONDITION_FALSE, "wrong return condition\n");
3996 
3997     query = "ALTER TABLE `T` HOLD";
3998     r = run_query(hdb, 0, query);
3999     ok(r == ERROR_SUCCESS, "failed to hold table %d\n", r);
4000 
4001     query = "ALTER TABLE `T` FREE";
4002     r = run_query(hdb, 0, query);
4003     ok(r == ERROR_SUCCESS, "failed to free table\n");
4004 
4005     query = "ALTER TABLE `T` FREE";
4006     r = run_query(hdb, 0, query);
4007     ok(r == ERROR_SUCCESS, "failed to free table\n");
4008 
4009     query = "ALTER TABLE `T` FREE";
4010     r = run_query(hdb, 0, query);
4011     ok(r == ERROR_BAD_QUERY_SYNTAX, "failed to free table\n");
4012 
4013     query = "ALTER TABLE `T` HOLD";
4014     r = run_query(hdb, 0, query);
4015     ok(r == ERROR_BAD_QUERY_SYNTAX, "failed to hold table %d\n", r);
4016 
4017     /* table T is removed */
4018     query = "SELECT * FROM `T`";
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     /* create the table again */
4023     query = "CREATE TABLE `U` ( `A` INTEGER, `B` INTEGER PRIMARY KEY `B`)";
4024     r = run_query(hdb, 0, query);
4025     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4026 
4027     /* up the ref count */
4028     query = "ALTER TABLE `U` HOLD";
4029     r = run_query(hdb, 0, query);
4030     ok(r == ERROR_SUCCESS, "failed to free table\n");
4031 
4032     /* add column, no data type */
4033     query = "ALTER TABLE `U` ADD `C`";
4034     r = run_query(hdb, 0, query);
4035     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
4036 
4037     query = "ALTER TABLE `U` ADD `C` INTEGER";
4038     r = run_query(hdb, 0, query);
4039     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4040 
4041     query = "SELECT * FROM `_Columns` WHERE `Table` = 'U' AND `Name` = 'C'";
4042     r = do_query(hdb, query, &rec);
4043     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4044 
4045     /* add column C again */
4046     query = "ALTER TABLE `U` ADD `C` INTEGER";
4047     r = run_query(hdb, 0, query);
4048     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
4049 
4050     query = "ALTER TABLE `U` ADD `D` INTEGER TEMPORARY";
4051     r = run_query(hdb, 0, query);
4052     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4053 
4054     query = "INSERT INTO `U` ( `A`, `B`, `C`, `D` ) VALUES ( 1, 2, 3, 4 )";
4055     r = run_query(hdb, 0, query);
4056     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4057 
4058     query = "ALTER TABLE `U` ADD `D` INTEGER TEMPORARY HOLD";
4059     r = run_query(hdb, 0, query);
4060     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
4061 
4062     query = "SELECT * FROM `_Columns` WHERE `Table` = 'U' AND `Name` = 'D'";
4063     r = do_query(hdb, query, &rec);
4064     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
4065 
4066     query = "INSERT INTO `U` ( `A`, `B`, `C`, `D` ) VALUES ( 5, 6, 7, 8 )";
4067     r = run_query(hdb, 0, query);
4068     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4069 
4070     query = "SELECT * FROM `U` WHERE `D` = 8";
4071     r = run_query(hdb, 0, query);
4072     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4073 
4074     query = "ALTER TABLE `U` ADD `D` INTEGER TEMPORARY FREE";
4075     r = run_query(hdb, 0, query);
4076     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
4077 
4078     query = "ALTER COLUMN `D` FREE";
4079     r = run_query(hdb, 0, query);
4080     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
4081 
4082     /* drop the ref count */
4083     query = "ALTER TABLE `U` FREE";
4084     r = run_query(hdb, 0, query);
4085     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4086 
4087     /* table is not empty */
4088     query = "SELECT * FROM `U`";
4089     r = run_query(hdb, 0, query);
4090     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4091 
4092     /* column D is removed */
4093     query = "SELECT * FROM `U` WHERE `D` = 8";
4094     r = run_query(hdb, 0, query);
4095     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
4096 
4097     query = "INSERT INTO `U` ( `A`, `B`, `C`, `D` ) VALUES ( 9, 10, 11, 12 )";
4098     r = run_query(hdb, 0, query);
4099     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
4100 
4101     /* add the column again */
4102     query = "ALTER TABLE `U` ADD `E` INTEGER TEMPORARY HOLD";
4103     r = run_query(hdb, 0, query);
4104     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4105 
4106     /* up the ref count */
4107     query = "ALTER TABLE `U` HOLD";
4108     r = run_query(hdb, 0, query);
4109     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4110 
4111     query = "INSERT INTO `U` ( `A`, `B`, `C`, `E` ) VALUES ( 13, 14, 15, 16 )";
4112     r = run_query(hdb, 0, query);
4113     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4114 
4115     query = "SELECT * FROM `U` WHERE `E` = 16";
4116     r = run_query(hdb, 0, query);
4117     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4118 
4119     /* drop the ref count */
4120     query = "ALTER TABLE `U` FREE";
4121     r = run_query(hdb, 0, query);
4122     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4123 
4124     query = "INSERT INTO `U` ( `A`, `B`, `C`, `E` ) VALUES ( 17, 18, 19, 20 )";
4125     r = run_query(hdb, 0, query);
4126     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4127 
4128     query = "SELECT * FROM `U` WHERE `E` = 20";
4129     r = run_query(hdb, 0, query);
4130     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4131 
4132     /* drop the ref count */
4133     query = "ALTER TABLE `U` FREE";
4134     r = run_query(hdb, 0, query);
4135     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4136 
4137     /* table still exists */
4138     query = "SELECT * FROM `U`";
4139     r = run_query(hdb, 0, query);
4140     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4141 
4142     /* col E is removed */
4143     query = "SELECT * FROM `U` WHERE `E` = 20";
4144     r = run_query(hdb, 0, query);
4145     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
4146 
4147     query = "INSERT INTO `U` ( `A`, `B`, `C`, `E` ) VALUES ( 20, 21, 22, 23 )";
4148     r = run_query(hdb, 0, query);
4149     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
4150 
4151     /* drop the ref count once more */
4152     query = "ALTER TABLE `U` FREE";
4153     r = run_query(hdb, 0, query);
4154     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4155 
4156     /* table still exists */
4157     query = "SELECT * FROM `U`";
4158     r = run_query(hdb, 0, query);
4159     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4160 
4161     MsiCloseHandle( hdb );
4162     DeleteFileA(msifile);
4163 }
4164 
4165 static void test_integers(void)
4166 {
4167     MSIHANDLE hdb = 0, view = 0, rec = 0;
4168     DWORD i;
4169     const char *query;
4170     UINT r;
4171 
4172     /* just MsiOpenDatabase should not create a file */
4173     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
4174     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
4175 
4176     /* create a table */
4177     query = "CREATE TABLE `integers` ( "
4178             "`one` SHORT, `two` INT, `three` INTEGER, `four` LONG, "
4179             "`five` SHORT NOT NULL, `six` INT NOT NULL, "
4180             "`seven` INTEGER NOT NULL, `eight` LONG NOT NULL "
4181             "PRIMARY KEY `one`)";
4182     r = MsiDatabaseOpenViewA(hdb, query, &view);
4183     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
4184     r = MsiViewExecute(view, 0);
4185     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
4186     r = MsiViewClose(view);
4187     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4188     r = MsiCloseHandle(view);
4189     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4190 
4191     query = "SELECT * FROM `integers`";
4192     r = MsiDatabaseOpenViewA(hdb, query, &view);
4193     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4194 
4195     r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec);
4196     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4197     check_record(rec, 8, "one", "two", "three", "four", "five", "six", "seven", "eight");
4198     MsiCloseHandle(rec);
4199 
4200     r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
4201     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4202     check_record(rec, 8, "I2", "I2", "I2", "I4", "i2", "i2", "i2", "i4");
4203     MsiCloseHandle(rec);
4204 
4205     MsiViewClose(view);
4206     MsiCloseHandle(view);
4207 
4208     /* insert values into it, NULL where NOT NULL is specified */
4209     query = "INSERT INTO `integers` ( `one`, `two`, `three`, `four`, `five`, `six`, `seven`, `eight` )"
4210         "VALUES('', '', '', '', '', '', '', '')";
4211     r = MsiDatabaseOpenViewA(hdb, query, &view);
4212     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4213     r = MsiViewExecute(view, 0);
4214     ok(r == ERROR_FUNCTION_FAILED, "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
4215 
4216     MsiViewClose(view);
4217     MsiCloseHandle(view);
4218 
4219     query = "SELECT * FROM `integers`";
4220     r = do_query(hdb, query, &rec);
4221     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
4222 
4223     r = MsiRecordGetFieldCount(rec);
4224     ok(r == -1, "record count wrong: %d\n", r);
4225 
4226     MsiCloseHandle(rec);
4227 
4228     /* insert legitimate values into it */
4229     query = "INSERT INTO `integers` ( `one`, `two`, `three`, `four`, `five`, `six`, `seven`, `eight` )"
4230         "VALUES('', '2', '', '4', '5', '6', '7', '8')";
4231     r = MsiDatabaseOpenViewA(hdb, query, &view);
4232     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4233     r = MsiViewExecute(view, 0);
4234     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4235 
4236     query = "SELECT * FROM `integers`";
4237     r = do_query(hdb, query, &rec);
4238     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4239 
4240     r = MsiRecordGetFieldCount(rec);
4241     ok(r == 8, "record count wrong: %d\n", r);
4242 
4243     i = MsiRecordGetInteger(rec, 1);
4244     ok(i == MSI_NULL_INTEGER, "Expected MSI_NULL_INTEGER, got %lu\n", i);
4245     i = MsiRecordGetInteger(rec, 3);
4246     ok(i == MSI_NULL_INTEGER, "Expected MSI_NULL_INTEGER, got %lu\n", i);
4247     i = MsiRecordGetInteger(rec, 2);
4248     ok(i == 2, "Expected 2, got %lu\n", i);
4249     i = MsiRecordGetInteger(rec, 4);
4250     ok(i == 4, "Expected 4, got %lu\n", i);
4251     i = MsiRecordGetInteger(rec, 5);
4252     ok(i == 5, "Expected 5, got %lu\n", i);
4253     i = MsiRecordGetInteger(rec, 6);
4254     ok(i == 6, "Expected 6, got %lu\n", i);
4255     i = MsiRecordGetInteger(rec, 7);
4256     ok(i == 7, "Expected 7, got %lu\n", i);
4257     i = MsiRecordGetInteger(rec, 8);
4258     ok(i == 8, "Expected 8, got %lu\n", i);
4259 
4260     MsiCloseHandle(rec);
4261     MsiViewClose(view);
4262     MsiCloseHandle(view);
4263 
4264     r = MsiDatabaseCommit(hdb);
4265     ok(r == ERROR_SUCCESS, "MsiDatabaseCommit failed\n");
4266 
4267     r = MsiCloseHandle(hdb);
4268     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4269 
4270     r = DeleteFileA(msifile);
4271     ok(r == TRUE, "file didn't exist after commit\n");
4272 }
4273 
4274 static void test_update(void)
4275 {
4276     MSIHANDLE hdb = 0, view = 0, rec = 0;
4277     const char *query;
4278     UINT r;
4279 
4280     /* just MsiOpenDatabase should not create a file */
4281     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
4282     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
4283 
4284     /* create the Control table */
4285     query = "CREATE TABLE `Control` ( "
4286         "`Dialog_` CHAR(72) NOT NULL, `Control` CHAR(50) NOT NULL, `Type` SHORT NOT NULL, "
4287         "`X` SHORT NOT NULL, `Y` SHORT NOT NULL, `Width` SHORT NOT NULL, `Height` SHORT NOT NULL,"
4288         "`Attributes` LONG, `Property` CHAR(50), `Text` CHAR(0) LOCALIZABLE, "
4289         "`Control_Next` CHAR(50), `Help` CHAR(50) LOCALIZABLE PRIMARY KEY `Dialog_`, `Control`)";
4290     r = MsiDatabaseOpenViewA(hdb, query, &view);
4291     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
4292     r = MsiViewExecute(view, 0);
4293     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
4294     r = MsiViewClose(view);
4295     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4296     r = MsiCloseHandle(view);
4297     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4298 
4299     /* add a control */
4300     query = "INSERT INTO `Control` ( "
4301         "`Dialog_`, `Control`, `Type`, `X`, `Y`, `Width`, `Height`, "
4302         "`Property`, `Text`, `Control_Next`, `Help` )"
4303         "VALUES('ErrorDialog', 'ErrorText', '1', '5', '5', '5', '5', '', '', '', '')";
4304     r = MsiDatabaseOpenViewA(hdb, query, &view);
4305     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4306     r = MsiViewExecute(view, 0);
4307     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4308     r = MsiViewClose(view);
4309     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4310     r = MsiCloseHandle(view);
4311     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4312 
4313     /* add a second control */
4314     query = "INSERT INTO `Control` ( "
4315         "`Dialog_`, `Control`, `Type`, `X`, `Y`, `Width`, `Height`, "
4316         "`Property`, `Text`, `Control_Next`, `Help` )"
4317         "VALUES('ErrorDialog', 'Button', '1', '5', '5', '5', '5', '', '', '', '')";
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     /* add a third control */
4328     query = "INSERT INTO `Control` ( "
4329         "`Dialog_`, `Control`, `Type`, `X`, `Y`, `Width`, `Height`, "
4330         "`Property`, `Text`, `Control_Next`, `Help` )"
4331         "VALUES('AnotherDialog', 'ErrorText', '1', '5', '5', '5', '5', '', '', '', '')";
4332     r = MsiDatabaseOpenViewA(hdb, query, &view);
4333     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4334     r = MsiViewExecute(view, 0);
4335     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4336     r = MsiViewClose(view);
4337     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4338     r = MsiCloseHandle(view);
4339     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4340 
4341     /* bad table */
4342     query = "UPDATE `NotATable` SET `Text` = 'this is text' WHERE `Dialog_` = 'ErrorDialog'";
4343     r = MsiDatabaseOpenViewA(hdb, query, &view);
4344     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
4345 
4346     /* bad set column */
4347     query = "UPDATE `Control` SET `NotAColumn` = 'this is text' WHERE `Dialog_` = 'ErrorDialog'";
4348     r = MsiDatabaseOpenViewA(hdb, query, &view);
4349     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
4350 
4351     /* bad where condition */
4352     query = "UPDATE `Control` SET `Text` = 'this is text' WHERE `NotAColumn` = 'ErrorDialog'";
4353     r = MsiDatabaseOpenViewA(hdb, query, &view);
4354     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
4355 
4356     /* just the dialog_ specified */
4357     query = "UPDATE `Control` SET `Text` = 'this is text' WHERE `Dialog_` = 'ErrorDialog'";
4358     r = MsiDatabaseOpenViewA(hdb, query, &view);
4359     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4360     r = MsiViewExecute(view, 0);
4361     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4362     r = MsiViewClose(view);
4363     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4364     r = MsiCloseHandle(view);
4365     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4366 
4367     /* check the modified text */
4368     query = "SELECT `Text` FROM `Control` WHERE `Control` = 'ErrorText'";
4369     r = MsiDatabaseOpenViewA(hdb, query, &view);
4370     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4371     r = MsiViewExecute(view, 0);
4372     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4373 
4374     r = MsiViewFetch(view, &rec);
4375     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4376     check_record(rec, 1, "this is text");
4377     MsiCloseHandle(rec);
4378 
4379     r = MsiViewFetch(view, &rec);
4380     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4381     check_record(rec, 1, "");
4382     MsiCloseHandle(rec);
4383 
4384     r = MsiViewFetch(view, &rec);
4385     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
4386 
4387     r = MsiViewClose(view);
4388     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4389     r = MsiCloseHandle(view);
4390     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4391 
4392     /* dialog_ and control specified */
4393     query = "UPDATE `Control` SET `Text` = 'this is text' WHERE `Dialog_` = 'ErrorDialog' AND `Control` = 'ErrorText'";
4394     r = MsiDatabaseOpenViewA(hdb, query, &view);
4395     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4396     r = MsiViewExecute(view, 0);
4397     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4398     r = MsiViewClose(view);
4399     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4400     r = MsiCloseHandle(view);
4401     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4402 
4403     /* check the modified text */
4404     query = "SELECT `Text` FROM `Control` WHERE `Control` = 'ErrorText'";
4405     r = MsiDatabaseOpenViewA(hdb, query, &view);
4406     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4407     r = MsiViewExecute(view, 0);
4408     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4409 
4410     r = MsiViewFetch(view, &rec);
4411     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4412     check_record(rec, 1, "this is text");
4413     MsiCloseHandle(rec);
4414 
4415     r = MsiViewFetch(view, &rec);
4416     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4417     check_record(rec, 1, "");
4418     MsiCloseHandle(rec);
4419 
4420     r = MsiViewFetch(view, &rec);
4421     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
4422 
4423     r = MsiViewClose(view);
4424     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4425     r = MsiCloseHandle(view);
4426     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4427 
4428     /* no where condition */
4429     query = "UPDATE `Control` SET `Text` = 'this is text'";
4430     r = MsiDatabaseOpenViewA(hdb, query, &view);
4431     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4432     r = MsiViewExecute(view, 0);
4433     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4434     r = MsiViewClose(view);
4435     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4436     r = MsiCloseHandle(view);
4437     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4438 
4439     /* check the modified text */
4440     query = "SELECT `Text` FROM `Control`";
4441     r = MsiDatabaseOpenViewA(hdb, query, &view);
4442     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4443     r = MsiViewExecute(view, 0);
4444     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4445 
4446     r = MsiViewFetch(view, &rec);
4447     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4448     check_record(rec, 1, "this is text");
4449     MsiCloseHandle(rec);
4450 
4451     r = MsiViewFetch(view, &rec);
4452     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4453     check_record(rec, 1, "this is text");
4454     MsiCloseHandle(rec);
4455 
4456     r = MsiViewFetch(view, &rec);
4457     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4458     check_record(rec, 1, "this is text");
4459     MsiCloseHandle(rec);
4460 
4461     r = MsiViewFetch(view, &rec);
4462     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
4463 
4464     r = MsiViewClose(view);
4465     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4466     r = MsiCloseHandle(view);
4467     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4468 
4469     query = "CREATE TABLE `Apple` ( `Banana` CHAR(72) NOT NULL, "
4470         "`Orange` CHAR(72),  `Pear` INT PRIMARY KEY `Banana`)";
4471     r = run_query(hdb, 0, query);
4472     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4473 
4474     query = "INSERT INTO `Apple` ( `Banana`, `Orange`, `Pear` )"
4475         "VALUES('one', 'two', 3)";
4476     r = run_query(hdb, 0, query);
4477     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4478 
4479     query = "INSERT INTO `Apple` ( `Banana`, `Orange`, `Pear` )"
4480         "VALUES('three', 'four', 5)";
4481     r = run_query(hdb, 0, query);
4482     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4483 
4484     query = "INSERT INTO `Apple` ( `Banana`, `Orange`, `Pear` )"
4485         "VALUES('six', 'two', 7)";
4486     r = run_query(hdb, 0, query);
4487     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4488 
4489     rec = MsiCreateRecord(2);
4490     MsiRecordSetInteger(rec, 1, 8);
4491     MsiRecordSetStringA(rec, 2, "two");
4492 
4493     query = "UPDATE `Apple` SET `Pear` = ? WHERE `Orange` = ?";
4494     r = run_query(hdb, rec, query);
4495     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4496 
4497     MsiCloseHandle(rec);
4498 
4499     query = "SELECT `Pear` FROM `Apple` ORDER BY `Orange`";
4500     r = MsiDatabaseOpenViewA(hdb, query, &view);
4501     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4502     r = MsiViewExecute(view, 0);
4503     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4504 
4505     r = MsiViewFetch(view, &rec);
4506     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4507 
4508     r = MsiRecordGetInteger(rec, 1);
4509     ok(r == 8, "Expected 8, got %d\n", r);
4510 
4511     MsiCloseHandle(rec);
4512 
4513     r = MsiViewFetch(view, &rec);
4514     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4515 
4516     r = MsiRecordGetInteger(rec, 1);
4517     ok(r == 8, "Expected 8, got %d\n", r);
4518 
4519     MsiCloseHandle(rec);
4520 
4521     r = MsiViewFetch(view, &rec);
4522     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4523 
4524     r = MsiRecordGetInteger(rec, 1);
4525     ok(r == 5, "Expected 5, got %d\n", r);
4526 
4527     MsiCloseHandle(rec);
4528 
4529     r = MsiViewFetch(view, &rec);
4530     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
4531 
4532     MsiViewClose(view);
4533     MsiCloseHandle(view);
4534 
4535     r = MsiDatabaseCommit(hdb);
4536     ok(r == ERROR_SUCCESS, "MsiDatabaseCommit failed\n");
4537     r = MsiCloseHandle(hdb);
4538     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4539 
4540     DeleteFileA(msifile);
4541 }
4542 
4543 static void test_special_tables(void)
4544 {
4545     const char *query;
4546     MSIHANDLE hdb = 0;
4547     UINT r;
4548 
4549     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
4550     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
4551 
4552     query = "CREATE TABLE `_Properties` ( "
4553         "`foo` INT NOT NULL, `bar` INT LOCALIZABLE PRIMARY KEY `foo`)";
4554     r = run_query(hdb, 0, query);
4555     ok(r == ERROR_SUCCESS, "failed to create table\n");
4556 
4557     query = "CREATE TABLE `_Storages` ( "
4558         "`foo` INT NOT NULL, `bar` INT LOCALIZABLE PRIMARY KEY `foo`)";
4559     r = run_query(hdb, 0, query);
4560     ok(r == ERROR_BAD_QUERY_SYNTAX, "created _Streams table\n");
4561 
4562     query = "CREATE TABLE `_Streams` ( "
4563         "`foo` INT NOT NULL, `bar` INT LOCALIZABLE PRIMARY KEY `foo`)";
4564     r = run_query(hdb, 0, query);
4565     ok(r == ERROR_BAD_QUERY_SYNTAX, "created _Streams table\n");
4566 
4567     query = "CREATE TABLE `_Tables` ( "
4568         "`foo` INT NOT NULL, `bar` INT LOCALIZABLE PRIMARY KEY `foo`)";
4569     r = run_query(hdb, 0, query);
4570     ok(r == ERROR_BAD_QUERY_SYNTAX, "created _Tables table\n");
4571 
4572     query = "CREATE TABLE `_Columns` ( "
4573         "`foo` INT NOT NULL, `bar` INT LOCALIZABLE PRIMARY KEY `foo`)";
4574     r = run_query(hdb, 0, query);
4575     ok(r == ERROR_BAD_QUERY_SYNTAX, "created _Columns table\n");
4576 
4577     r = MsiCloseHandle(hdb);
4578     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4579 }
4580 
4581 static void test_tables_order(void)
4582 {
4583     const char *query;
4584     MSIHANDLE hdb = 0, hview = 0, hrec = 0;
4585     UINT r;
4586 
4587     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
4588     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
4589 
4590     query = "CREATE TABLE `foo` ( "
4591         "`baz` INT NOT NULL PRIMARY KEY `baz`)";
4592     r = run_query(hdb, 0, query);
4593     ok(r == ERROR_SUCCESS, "failed to create table\n");
4594 
4595     query = "CREATE TABLE `bar` ( "
4596         "`foo` INT NOT NULL PRIMARY KEY `foo`)";
4597     r = run_query(hdb, 0, query);
4598     ok(r == ERROR_SUCCESS, "failed to create table\n");
4599 
4600     query = "CREATE TABLE `baz` ( "
4601         "`bar` INT NOT NULL, "
4602         "`baz` INT NOT NULL, "
4603         "`foo` INT NOT NULL PRIMARY KEY `bar`)";
4604     r = run_query(hdb, 0, query);
4605     ok(r == ERROR_SUCCESS, "failed to create table\n");
4606 
4607     /* The names of the tables in the _Tables table must
4608        be in the same order as these names are created in
4609        the strings table. */
4610     query = "SELECT `Name` FROM `_Tables`";
4611     r = MsiDatabaseOpenViewA(hdb, query, &hview);
4612     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
4613     r = MsiViewExecute(hview, 0);
4614     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
4615 
4616     r = MsiViewFetch(hview, &hrec);
4617     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4618     check_record(hrec, 1, "foo");
4619     r = MsiCloseHandle(hrec);
4620     ok(r == ERROR_SUCCESS, "failed to close record\n");
4621 
4622     r = MsiViewFetch(hview, &hrec);
4623     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4624     check_record(hrec, 1, "baz");
4625     r = MsiCloseHandle(hrec);
4626     ok(r == ERROR_SUCCESS, "failed to close record\n");
4627 
4628     r = MsiViewFetch(hview, &hrec);
4629     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4630     check_record(hrec, 1, "bar");
4631     r = MsiCloseHandle(hrec);
4632     ok(r == ERROR_SUCCESS, "failed to close record\n");
4633 
4634     r = MsiViewClose(hview);
4635     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4636     r = MsiCloseHandle(hview);
4637     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4638 
4639     /* The names of the tables in the _Columns table must
4640        be in the same order as these names are created in
4641        the strings table. */
4642     query = "SELECT `Table`, `Number`, `Name` FROM `_Columns`";
4643     r = MsiDatabaseOpenViewA(hdb, query, &hview);
4644     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
4645     r = MsiViewExecute(hview, 0);
4646     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
4647 
4648     r = MsiViewFetch(hview, &hrec);
4649     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4650     check_record(hrec, 3, "foo", "1", "baz");
4651     r = MsiCloseHandle(hrec);
4652     ok(r == ERROR_SUCCESS, "failed to close record\n");
4653 
4654     r = MsiViewFetch(hview, &hrec);
4655     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4656     check_record(hrec, 3, "baz", "1", "bar");
4657     r = MsiCloseHandle(hrec);
4658     ok(r == ERROR_SUCCESS, "failed to close record\n");
4659 
4660     r = MsiViewFetch(hview, &hrec);
4661     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4662     check_record(hrec, 3, "baz", "2", "baz");
4663     r = MsiCloseHandle(hrec);
4664     ok(r == ERROR_SUCCESS, "failed to close record\n");
4665 
4666     r = MsiViewFetch(hview, &hrec);
4667     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4668     check_record(hrec, 3, "baz", "3", "foo");
4669     r = MsiCloseHandle(hrec);
4670     ok(r == ERROR_SUCCESS, "failed to close record\n");
4671 
4672     r = MsiViewFetch(hview, &hrec);
4673     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4674     check_record(hrec, 3, "bar", "1", "foo");
4675     r = MsiCloseHandle(hrec);
4676     ok(r == ERROR_SUCCESS, "failed to close record\n");
4677 
4678     r = MsiViewClose(hview);
4679     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4680     r = MsiCloseHandle(hview);
4681     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4682 
4683     r = MsiCloseHandle(hdb);
4684     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4685 
4686     DeleteFileA(msifile);
4687 }
4688 
4689 static void test_rows_order(void)
4690 {
4691     const char *query;
4692     MSIHANDLE hdb = 0, hview = 0, hrec = 0;
4693     UINT r;
4694 
4695     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
4696     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
4697 
4698     query = "CREATE TABLE `foo` ( "
4699         "`bar` LONGCHAR NOT NULL PRIMARY KEY `bar`)";
4700     r = run_query(hdb, 0, query);
4701     ok(r == ERROR_SUCCESS, "failed to create table\n");
4702 
4703     r = run_query(hdb, 0, "INSERT INTO `foo` "
4704             "( `bar` ) VALUES ( 'A' )");
4705     ok(r == ERROR_SUCCESS, "cannot add value to table\n");
4706 
4707     r = run_query(hdb, 0, "INSERT INTO `foo` "
4708             "( `bar` ) VALUES ( 'B' )");
4709     ok(r == ERROR_SUCCESS, "cannot add value to table\n");
4710 
4711     r = run_query(hdb, 0, "INSERT INTO `foo` "
4712             "( `bar` ) VALUES ( 'C' )");
4713     ok(r == ERROR_SUCCESS, "cannot add value to table\n");
4714 
4715     r = run_query(hdb, 0, "INSERT INTO `foo` "
4716             "( `bar` ) VALUES ( 'D' )");
4717     ok(r == ERROR_SUCCESS, "cannot add value to table\n");
4718 
4719     r = run_query(hdb, 0, "INSERT INTO `foo` "
4720             "( `bar` ) VALUES ( 'E' )");
4721     ok(r == ERROR_SUCCESS, "cannot add value to table\n");
4722 
4723     r = run_query(hdb, 0, "INSERT INTO `foo` "
4724             "( `bar` ) VALUES ( 'F' )");
4725     ok(r == ERROR_SUCCESS, "cannot add value to table\n");
4726 
4727     query = "CREATE TABLE `bar` ( "
4728         "`foo` LONGCHAR NOT NULL, "
4729         "`baz` LONGCHAR NOT NULL "
4730         "PRIMARY KEY `foo` )";
4731     r = run_query(hdb, 0, query);
4732     ok(r == ERROR_SUCCESS, "failed to create table\n");
4733 
4734     r = run_query(hdb, 0, "INSERT INTO `bar` "
4735             "( `foo`, `baz` ) VALUES ( 'C', 'E' )");
4736     ok(r == ERROR_SUCCESS, "cannot add value to table\n");
4737 
4738     r = run_query(hdb, 0, "INSERT INTO `bar` "
4739             "( `foo`, `baz` ) VALUES ( 'F', 'A' )");
4740     ok(r == ERROR_SUCCESS, "cannot add value to table\n");
4741 
4742     r = run_query(hdb, 0, "INSERT INTO `bar` "
4743             "( `foo`, `baz` ) VALUES ( 'A', 'B' )");
4744     ok(r == ERROR_SUCCESS, "cannot add value to table\n");
4745 
4746     r = run_query(hdb, 0, "INSERT INTO `bar` "
4747             "( `foo`, `baz` ) VALUES ( 'D', 'E' )");
4748     ok(r == ERROR_SUCCESS, "cannot add value to table\n");
4749 
4750     /* The rows of the table must be ordered by the column values of
4751        each row. For strings, the column value is the string id
4752        in the string table.  */
4753 
4754     query = "SELECT * FROM `bar`";
4755     r = MsiDatabaseOpenViewA(hdb, query, &hview);
4756     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
4757     r = MsiViewExecute(hview, 0);
4758     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
4759 
4760     r = MsiViewFetch(hview, &hrec);
4761     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4762     check_record(hrec, 2, "A", "B");
4763     r = MsiCloseHandle(hrec);
4764     ok(r == ERROR_SUCCESS, "failed to close record\n");
4765 
4766     r = MsiViewFetch(hview, &hrec);
4767     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4768     check_record(hrec, 2, "C", "E");
4769     r = MsiCloseHandle(hrec);
4770     ok(r == ERROR_SUCCESS, "failed to close record\n");
4771 
4772     r = MsiViewFetch(hview, &hrec);
4773     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4774     check_record(hrec, 2, "D", "E");
4775     r = MsiCloseHandle(hrec);
4776     ok(r == ERROR_SUCCESS, "failed to close record\n");
4777 
4778     r = MsiViewFetch(hview, &hrec);
4779     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4780     check_record(hrec, 2, "F", "A");
4781     r = MsiCloseHandle(hrec);
4782     ok(r == ERROR_SUCCESS, "failed to close record\n");
4783 
4784     r = MsiViewClose(hview);
4785     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4786     r = MsiCloseHandle(hview);
4787     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4788 
4789     r = MsiCloseHandle(hdb);
4790     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4791 
4792     DeleteFileA(msifile);
4793 }
4794 
4795 static void test_collation(void)
4796 {
4797     const char *query;
4798     MSIHANDLE hdb = 0, hview = 0, hrec = 0;
4799     UINT r;
4800     char buffer[100];
4801     WCHAR bufferW[100];
4802     DWORD sz;
4803 
4804     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
4805     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
4806 
4807     query = "CREATE TABLE `bar` ( "
4808         "`foo` LONGCHAR NOT NULL, "
4809         "`baz` LONGCHAR NOT NULL "
4810         "PRIMARY KEY `foo` )";
4811     r = run_query(hdb, 0, query);
4812     ok(r == ERROR_SUCCESS, "failed to create table\n");
4813 
4814     r = run_query(hdb, 0, query);
4815     ok(r == ERROR_BAD_QUERY_SYNTAX, "wrong error %u\n", r);
4816 
4817     r = run_query(hdb, 0, "INSERT INTO `bar` "
4818             "( `foo`, `baz` ) VALUES ( '\2', 'A' )");
4819     ok(r == ERROR_SUCCESS, "cannot add value to table %u\n", r);
4820 
4821     r = run_query(hdb, 0, "INSERT INTO `bar` "
4822             "( `foo`, `baz` ) VALUES ( '\1', 'B' )");
4823     ok(r == ERROR_SUCCESS, "cannot add value to table %u\n", r);
4824 
4825     r = run_queryW(hdb, 0, L"INSERT INTO `bar` (`foo`,`baz`) VALUES ('a\x30a','C')");
4826     ok(r == ERROR_SUCCESS, "cannot add value to table %u\n", r);
4827 
4828     r = run_queryW(hdb, 0, L"INSERT INTO `bar` (`foo`,`baz`) VALUES ('\xe5','D')");
4829     ok(r == ERROR_SUCCESS, "cannot add value to table %u\n", r);
4830 
4831     r = run_queryW(hdb, 0, L"CREATE TABLE `baz` ( `a\x30a` LONGCHAR NOT NULL, `\xe5` LONGCHAR NOT NULL PRIMARY KEY `a\x30a`)");
4832     ok(r == ERROR_SUCCESS, "cannot create table %u\n", r);
4833 
4834     r = run_queryW(hdb, 0, L"CREATE TABLE `a\x30a` ( `foo` LONGCHAR NOT NULL PRIMARY KEY `foo`)");
4835     ok(r == ERROR_SUCCESS, "cannot create table %u\n", r);
4836 
4837     r = run_queryW(hdb, 0, L"CREATE TABLE `\xe5` ( `foo` LONGCHAR NOT NULL PRIMARY KEY `foo`)");
4838     ok(r == ERROR_SUCCESS, "cannot create table %u\n", r);
4839 
4840     query = "SELECT * FROM `bar`";
4841     r = MsiDatabaseOpenViewA(hdb, query, &hview);
4842     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
4843     r = MsiViewExecute(hview, 0);
4844     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
4845 
4846     r = MsiViewFetch(hview, &hrec);
4847     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4848     sz = sizeof(buffer);
4849     r = MsiRecordGetStringA(hrec, 1, buffer, &sz);
4850     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4851     ok(!lstrcmpA(buffer, "\2"), "Expected \\2, got '%s'\n", buffer);
4852     sz = sizeof(buffer);
4853     r = MsiRecordGetStringA(hrec, 2, buffer, &sz);
4854     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4855     ok(!lstrcmpA(buffer, "A"), "Expected A, got '%s'\n", buffer);
4856     MsiCloseHandle(hrec);
4857 
4858     r = MsiViewFetch(hview, &hrec);
4859     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4860     sz = sizeof(buffer);
4861     r = MsiRecordGetStringA(hrec, 1, buffer, &sz);
4862     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4863     ok(!lstrcmpA(buffer, "\1"), "Expected \\1, got '%s'\n", buffer);
4864     sz = sizeof(buffer);
4865     r = MsiRecordGetStringA(hrec, 2, buffer, &sz);
4866     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4867     ok(!lstrcmpA(buffer, "B"), "Expected B, got '%s'\n", buffer);
4868     MsiCloseHandle(hrec);
4869 
4870     r = MsiViewFetch(hview, &hrec);
4871     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4872     sz = ARRAY_SIZE(bufferW);
4873     r = MsiRecordGetStringW(hrec, 1, bufferW, &sz);
4874     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4875     ok(!memcmp(bufferW, L"a\x30a", sizeof(L"a\x30a")),
4876        "Expected %s, got %s\n", wine_dbgstr_w(L"a\x30a"), wine_dbgstr_w(bufferW));
4877     sz = ARRAY_SIZE(bufferW);
4878     r = MsiRecordGetStringW(hrec, 2, bufferW, &sz);
4879     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4880     ok(!lstrcmpW(bufferW, L"C"), "Expected C, got %s\n", wine_dbgstr_w(bufferW));
4881     MsiCloseHandle(hrec);
4882 
4883     r = MsiViewFetch(hview, &hrec);
4884     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4885     sz = ARRAY_SIZE(bufferW);
4886     r = MsiRecordGetStringW(hrec, 1, bufferW, &sz);
4887     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4888     ok(!memcmp(bufferW, L"\xe5", sizeof(L"\xe5")),
4889        "Expected %s, got %s\n", wine_dbgstr_w(L"\xe5"), wine_dbgstr_w(bufferW));
4890     sz = ARRAY_SIZE(bufferW);
4891     r = MsiRecordGetStringW(hrec, 2, bufferW, &sz);
4892     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4893     ok(!lstrcmpW(bufferW, L"D"), "Expected D, got %s\n", wine_dbgstr_w(bufferW));
4894     MsiCloseHandle(hrec);
4895 
4896     r = MsiViewClose(hview);
4897     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4898     r = MsiCloseHandle(hview);
4899     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4900 
4901     r = MsiDatabaseOpenViewW(hdb, L"SELECT * FROM `bar` WHERE `foo` ='\xe5'", &hview);
4902     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
4903     r = MsiViewExecute(hview, 0);
4904     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
4905 
4906     r = MsiViewFetch(hview, &hrec);
4907     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4908     sz = ARRAY_SIZE(bufferW);
4909     r = MsiRecordGetStringW(hrec, 1, bufferW, &sz);
4910     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4911     ok(!memcmp(bufferW, L"\xe5", sizeof(L"\xe5")),
4912        "Expected %s, got %s\n", wine_dbgstr_w(L"\xe5"), wine_dbgstr_w(bufferW));
4913     sz = ARRAY_SIZE(bufferW);
4914     r = MsiRecordGetStringW(hrec, 2, bufferW, &sz);
4915     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4916     ok(!lstrcmpW(bufferW, L"D"), "Expected D, got %s\n", wine_dbgstr_w(bufferW));
4917     MsiCloseHandle(hrec);
4918 
4919     r = MsiViewFetch(hview, &hrec);
4920     ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch failed\n");
4921 
4922     r = MsiViewClose(hview);
4923     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4924     r = MsiCloseHandle(hview);
4925     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4926 
4927     r = MsiCloseHandle(hdb);
4928     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4929 
4930     DeleteFileA(msifile);
4931 }
4932 
4933 static void test_select_markers(void)
4934 {
4935     MSIHANDLE hdb = 0, rec, view, res;
4936     LPCSTR query;
4937     UINT r;
4938 
4939     hdb = create_db();
4940     ok( hdb, "failed to create db\n");
4941 
4942     r = run_query(hdb, 0,
4943             "CREATE TABLE `Table` (`One` CHAR(72), `Two` CHAR(72), `Three` SHORT PRIMARY KEY `One`, `Two`, `Three`)");
4944     ok(r == S_OK, "cannot create table: %d\n", r);
4945 
4946     r = run_query(hdb, 0, "INSERT INTO `Table` "
4947             "( `One`, `Two`, `Three` ) VALUES ( 'apple', 'one', 1 )");
4948     ok(r == S_OK, "cannot add file to the Media table: %d\n", r);
4949 
4950     r = run_query(hdb, 0, "INSERT INTO `Table` "
4951             "( `One`, `Two`, `Three` ) VALUES ( 'apple', 'two', 1 )");
4952     ok(r == S_OK, "cannot add file to the Media table: %d\n", r);
4953 
4954     r = run_query(hdb, 0, "INSERT INTO `Table` "
4955             "( `One`, `Two`, `Three` ) VALUES ( 'apple', 'two', 2 )");
4956     ok(r == S_OK, "cannot add file to the Media table: %d\n", r);
4957 
4958     r = run_query(hdb, 0, "INSERT INTO `Table` "
4959             "( `One`, `Two`, `Three` ) VALUES ( 'banana', 'three', 3 )");
4960     ok(r == S_OK, "cannot add file to the Media table: %d\n", r);
4961 
4962     rec = MsiCreateRecord(2);
4963     MsiRecordSetStringA(rec, 1, "apple");
4964     MsiRecordSetStringA(rec, 2, "two");
4965 
4966     query = "SELECT * FROM `Table` WHERE `One`=? AND `Two`=? ORDER BY `Three`";
4967     r = MsiDatabaseOpenViewA(hdb, query, &view);
4968     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4969 
4970     r = MsiViewExecute(view, rec);
4971     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4972 
4973     r = MsiViewFetch(view, &res);
4974     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4975     check_record(res, 3, "apple", "two", "1");
4976     MsiCloseHandle(res);
4977 
4978     r = MsiViewFetch(view, &res);
4979     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4980     check_record(res, 3, "apple", "two", "2");
4981     MsiCloseHandle(res);
4982 
4983     r = MsiViewFetch(view, &res);
4984     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
4985 
4986     MsiCloseHandle(rec);
4987     MsiViewClose(view);
4988     MsiCloseHandle(view);
4989 
4990     rec = MsiCreateRecord(2);
4991     MsiRecordSetStringA(rec, 1, "one");
4992     MsiRecordSetInteger(rec, 2, 1);
4993 
4994     query = "SELECT * FROM `Table` WHERE `Two`<>? AND `Three`>? ORDER BY `Three`";
4995     r = MsiDatabaseOpenViewA(hdb, query, &view);
4996     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4997     r = MsiViewExecute(view, rec);
4998     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4999 
5000     r = MsiViewFetch(view, &res);
5001     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5002     check_record(res, 3, "apple", "two", "2");
5003     MsiCloseHandle(res);
5004 
5005     r = MsiViewFetch(view, &res);
5006     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5007     check_record(res, 3, "banana", "three", "3");
5008     MsiCloseHandle(res);
5009 
5010     r = MsiViewFetch(view, &res);
5011     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5012 
5013     MsiCloseHandle(rec);
5014     MsiViewClose(view);
5015     MsiCloseHandle(view);
5016     MsiCloseHandle(hdb);
5017     DeleteFileA(msifile);
5018 }
5019 
5020 static void test_viewmodify_update(void)
5021 {
5022     MSIHANDLE hdb = 0, hview = 0, hrec = 0;
5023     UINT i, test_max, offset, count;
5024     const char *query;
5025     UINT r;
5026 
5027     DeleteFileA(msifile);
5028 
5029     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
5030     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
5031 
5032     query = "CREATE TABLE `table` (`A` INT, `B` INT PRIMARY KEY `A`)";
5033     r = run_query( hdb, 0, query );
5034     ok(r == ERROR_SUCCESS, "query failed\n");
5035 
5036     query = "INSERT INTO `table` (`A`, `B`) VALUES (1, 2)";
5037     r = run_query( hdb, 0, query );
5038     ok(r == ERROR_SUCCESS, "query failed\n");
5039 
5040     query = "INSERT INTO `table` (`A`, `B`) VALUES (3, 4)";
5041     r = run_query( hdb, 0, query );
5042     ok(r == ERROR_SUCCESS, "query failed\n");
5043 
5044     query = "INSERT INTO `table` (`A`, `B`) VALUES (5, 6)";
5045     r = run_query( hdb, 0, query );
5046     ok(r == ERROR_SUCCESS, "query failed\n");
5047 
5048     query = "SELECT `B` FROM `table`";
5049     r = MsiDatabaseOpenViewA(hdb, query, &hview);
5050     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
5051     r = MsiViewExecute(hview, 0);
5052     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
5053     r = MsiViewFetch(hview, &hrec);
5054     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
5055 
5056     r = MsiRecordSetInteger(hrec, 1, 0);
5057     ok(r == ERROR_SUCCESS, "failed to set integer\n");
5058 
5059     r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
5060     ok(r == ERROR_SUCCESS, "MsiViewModify failed: %d\n", r);
5061 
5062     r = MsiCloseHandle(hrec);
5063     ok(r == ERROR_SUCCESS, "failed to close record\n");
5064 
5065     r = MsiViewClose(hview);
5066     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
5067     r = MsiCloseHandle(hview);
5068     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
5069 
5070     query = "SELECT * FROM `table`";
5071     r = MsiDatabaseOpenViewA(hdb, query, &hview);
5072     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
5073     r = MsiViewExecute(hview, 0);
5074     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
5075     r = MsiViewFetch(hview, &hrec);
5076     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
5077 
5078     r = MsiRecordGetInteger(hrec, 1);
5079     ok(r == 1, "Expected 1, got %d\n", r);
5080     r = MsiRecordGetInteger(hrec, 2);
5081     ok(r == 0, "Expected 0, got %d\n", r);
5082 
5083     r = MsiCloseHandle(hrec);
5084     ok(r == ERROR_SUCCESS, "failed to close record\n");
5085 
5086     r = MsiViewFetch(hview, &hrec);
5087     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
5088 
5089     r = MsiRecordGetInteger(hrec, 1);
5090     ok(r == 3, "Expected 3, got %d\n", r);
5091     r = MsiRecordGetInteger(hrec, 2);
5092     ok(r == 4, "Expected 4, got %d\n", r);
5093 
5094     r = MsiCloseHandle(hrec);
5095     ok(r == ERROR_SUCCESS, "failed to close record\n");
5096 
5097     r = MsiViewFetch(hview, &hrec);
5098     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
5099 
5100     r = MsiRecordGetInteger(hrec, 1);
5101     ok(r == 5, "Expected 5, got %d\n", r);
5102     r = MsiRecordGetInteger(hrec, 2);
5103     ok(r == 6, "Expected 6, got %d\n", r);
5104 
5105     r = MsiCloseHandle(hrec);
5106     ok(r == ERROR_SUCCESS, "failed to close record\n");
5107 
5108     r = MsiViewFetch(hview, &hrec);
5109     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5110 
5111     r = MsiViewClose(hview);
5112     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
5113     r = MsiCloseHandle(hview);
5114     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
5115 
5116     /* loop through all elements */
5117     query = "SELECT `B` FROM `table`";
5118     r = MsiDatabaseOpenViewA(hdb, query, &hview);
5119     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
5120     r = MsiViewExecute(hview, 0);
5121     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
5122 
5123     while (TRUE)
5124     {
5125         r = MsiViewFetch(hview, &hrec);
5126         if (r != ERROR_SUCCESS)
5127             break;
5128 
5129         r = MsiRecordSetInteger(hrec, 1, 0);
5130         ok(r == ERROR_SUCCESS, "failed to set integer\n");
5131 
5132         r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
5133         ok(r == ERROR_SUCCESS, "MsiViewModify failed: %d\n", r);
5134 
5135         r = MsiCloseHandle(hrec);
5136         ok(r == ERROR_SUCCESS, "failed to close record\n");
5137     }
5138 
5139     r = MsiViewClose(hview);
5140     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
5141     r = MsiCloseHandle(hview);
5142     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
5143 
5144     query = "SELECT * FROM `table`";
5145     r = MsiDatabaseOpenViewA(hdb, query, &hview);
5146     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
5147     r = MsiViewExecute(hview, 0);
5148     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
5149     r = MsiViewFetch(hview, &hrec);
5150     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
5151 
5152     r = MsiRecordGetInteger(hrec, 1);
5153     ok(r == 1, "Expected 1, got %d\n", r);
5154     r = MsiRecordGetInteger(hrec, 2);
5155     ok(r == 0, "Expected 0, got %d\n", r);
5156 
5157     r = MsiCloseHandle(hrec);
5158     ok(r == ERROR_SUCCESS, "failed to close record\n");
5159 
5160     r = MsiViewFetch(hview, &hrec);
5161     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
5162 
5163     r = MsiRecordGetInteger(hrec, 1);
5164     ok(r == 3, "Expected 3, got %d\n", r);
5165     r = MsiRecordGetInteger(hrec, 2);
5166     ok(r == 0, "Expected 0, got %d\n", r);
5167 
5168     r = MsiCloseHandle(hrec);
5169     ok(r == ERROR_SUCCESS, "failed to close record\n");
5170 
5171     r = MsiViewFetch(hview, &hrec);
5172     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
5173 
5174     r = MsiRecordGetInteger(hrec, 1);
5175     ok(r == 5, "Expected 5, got %d\n", r);
5176     r = MsiRecordGetInteger(hrec, 2);
5177     ok(r == 0, "Expected 0, got %d\n", r);
5178 
5179     r = MsiCloseHandle(hrec);
5180     ok(r == ERROR_SUCCESS, "failed to close record\n");
5181 
5182     r = MsiViewFetch(hview, &hrec);
5183     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5184 
5185     r = MsiViewClose(hview);
5186     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
5187     r = MsiCloseHandle(hview);
5188     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
5189 
5190     query = "CREATE TABLE `table2` (`A` INT, `B` INT PRIMARY KEY `A`)";
5191     r = run_query( hdb, 0, query );
5192     ok(r == ERROR_SUCCESS, "query failed\n");
5193 
5194     query = "INSERT INTO `table2` (`A`, `B`) VALUES (?, ?)";
5195     r = MsiDatabaseOpenViewA( hdb, query, &hview );
5196     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
5197 
5198     test_max = 100;
5199     offset = 1234;
5200     for(i = 0; i < test_max; i++)
5201     {
5202 
5203         hrec = MsiCreateRecord( 2 );
5204         MsiRecordSetInteger( hrec, 1, test_max - i );
5205         MsiRecordSetInteger( hrec, 2, i );
5206 
5207         r = MsiViewExecute( hview, hrec );
5208         ok(r == ERROR_SUCCESS, "Got %d\n", r);
5209 
5210         r = MsiCloseHandle( hrec );
5211         ok(r == ERROR_SUCCESS, "Got %d\n", r);
5212     }
5213 
5214     r = MsiViewClose( hview );
5215     ok(r == ERROR_SUCCESS, "Got %d\n", r);
5216     r = MsiCloseHandle( hview );
5217     ok(r == ERROR_SUCCESS, "Got %d\n", r);
5218 
5219     /* Update. */
5220     query = "SELECT * FROM `table2` ORDER BY `B`";
5221     r = MsiDatabaseOpenViewA( hdb, query, &hview);
5222     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
5223     r = MsiViewExecute( hview, 0 );
5224     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
5225 
5226     count = 0;
5227     while (MsiViewFetch( hview, &hrec ) == ERROR_SUCCESS)
5228     {
5229         UINT b = MsiRecordGetInteger( hrec, 2 );
5230 
5231         r = MsiRecordSetInteger( hrec, 2, b + offset);
5232         ok(r == ERROR_SUCCESS, "Got %d\n", r);
5233 
5234         r = MsiViewModify( hview, MSIMODIFY_UPDATE, hrec );
5235         ok(r == ERROR_SUCCESS, "Got %d\n", r);
5236 
5237         r = MsiCloseHandle(hrec);
5238         ok(r == ERROR_SUCCESS, "failed to close record\n");
5239         count++;
5240     }
5241     ok(count == test_max, "Got count %d\n", count);
5242 
5243     r = MsiViewClose(hview);
5244     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
5245     r = MsiCloseHandle(hview);
5246     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
5247 
5248     /* Recheck. */
5249     query = "SELECT * FROM `table2` ORDER BY `B`";
5250     r = MsiDatabaseOpenViewA( hdb, query, &hview);
5251     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
5252     r = MsiViewExecute( hview, 0 );
5253     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
5254 
5255     count = 0;
5256     while (MsiViewFetch( hview, &hrec ) == ERROR_SUCCESS)
5257     {
5258         UINT a = MsiRecordGetInteger( hrec, 1 );
5259         UINT b = MsiRecordGetInteger( hrec, 2 );
5260         ok( ( test_max - a + offset) == b, "Got (%d, %d), expected (%d, %d)\n",
5261             a, b, test_max - a + offset, b);
5262 
5263         r = MsiCloseHandle(hrec);
5264         ok(r == ERROR_SUCCESS, "failed to close record\n");
5265         count++;
5266     }
5267     ok(count == test_max, "Got count %d\n", count);
5268 
5269     r = MsiViewClose(hview);
5270     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
5271     r = MsiCloseHandle(hview);
5272     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
5273 
5274     r = MsiCloseHandle( hdb );
5275     ok(r == ERROR_SUCCESS, "MsiOpenDatabase close failed\n");
5276 }
5277 
5278 static void test_viewmodify_assign(void)
5279 {
5280     MSIHANDLE hdb = 0, hview = 0, hrec = 0;
5281     const char *query;
5282     UINT r;
5283 
5284     /* setup database */
5285     DeleteFileA(msifile);
5286 
5287     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
5288     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
5289 
5290     query = "CREATE TABLE `table` (`A` INT, `B` INT PRIMARY KEY `A`)";
5291     r = run_query( hdb, 0, query );
5292     ok(r == ERROR_SUCCESS, "query failed\n");
5293 
5294     /* assign to view, new primary key */
5295     query = "SELECT * FROM `table`";
5296     r = MsiDatabaseOpenViewA(hdb, query, &hview);
5297     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
5298     r = MsiViewExecute(hview, 0);
5299     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
5300 
5301     hrec = MsiCreateRecord(2);
5302     ok(hrec != 0, "MsiCreateRecord failed\n");
5303 
5304     r = MsiRecordSetInteger(hrec, 1, 1);
5305     ok(r == ERROR_SUCCESS, "failed to set integer\n");
5306     r = MsiRecordSetInteger(hrec, 2, 2);
5307     ok(r == ERROR_SUCCESS, "failed to set integer\n");
5308 
5309     r = MsiViewModify(hview, MSIMODIFY_ASSIGN, hrec);
5310     ok(r == ERROR_SUCCESS, "MsiViewModify failed: %d\n", r);
5311 
5312     r = MsiCloseHandle(hrec);
5313     ok(r == ERROR_SUCCESS, "failed to close record\n");
5314 
5315     r = MsiViewClose(hview);
5316     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
5317     r = MsiCloseHandle(hview);
5318     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
5319 
5320     query = "SELECT * FROM `table`";
5321     r = MsiDatabaseOpenViewA(hdb, query, &hview);
5322     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
5323     r = MsiViewExecute(hview, 0);
5324     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
5325     r = MsiViewFetch(hview, &hrec);
5326     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
5327     check_record(hrec, 2, "1", "2");
5328     r = MsiCloseHandle(hrec);
5329     ok(r == ERROR_SUCCESS, "failed to close record\n");
5330 
5331     r = MsiViewFetch(hview, &hrec);
5332     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5333 
5334     r = MsiViewClose(hview);
5335     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
5336     r = MsiCloseHandle(hview);
5337     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
5338 
5339     /* assign to view, primary key matches */
5340     query = "SELECT * FROM `table`";
5341     r = MsiDatabaseOpenViewA(hdb, query, &hview);
5342     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
5343     r = MsiViewExecute(hview, 0);
5344     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
5345 
5346     hrec = MsiCreateRecord(2);
5347     ok(hrec != 0, "MsiCreateRecord failed\n");
5348 
5349     r = MsiRecordSetInteger(hrec, 1, 1);
5350     ok(r == ERROR_SUCCESS, "failed to set integer\n");
5351     r = MsiRecordSetInteger(hrec, 2, 4);
5352     ok(r == ERROR_SUCCESS, "failed to set integer\n");
5353 
5354     r = MsiViewModify(hview, MSIMODIFY_ASSIGN, hrec);
5355     ok(r == ERROR_SUCCESS, "MsiViewModify failed: %d\n", r);
5356 
5357     r = MsiCloseHandle(hrec);
5358     ok(r == ERROR_SUCCESS, "failed to close record\n");
5359 
5360     r = MsiViewClose(hview);
5361     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
5362     r = MsiCloseHandle(hview);
5363     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
5364 
5365     query = "SELECT * FROM `table`";
5366     r = MsiDatabaseOpenViewA(hdb, query, &hview);
5367     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
5368     r = MsiViewExecute(hview, 0);
5369     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
5370     r = MsiViewFetch(hview, &hrec);
5371     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
5372     check_record(hrec, 2, "1", "4");
5373     r = MsiCloseHandle(hrec);
5374     ok(r == ERROR_SUCCESS, "failed to close record\n");
5375 
5376     r = MsiViewFetch(hview, &hrec);
5377     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5378 
5379     r = MsiViewClose(hview);
5380     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
5381     r = MsiCloseHandle(hview);
5382     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
5383 
5384     r = run_query(hdb, 0, "CREATE TABLE `table2` (`A` INT, `B` INT, `C` INT, `D` INT PRIMARY KEY `A`,`B`)");
5385     ok(!r, "got %u\n", r);
5386 
5387     r = MsiDatabaseOpenViewA(hdb, "SELECT * FROM `table2`", &hview);
5388     ok(!r, "got %u\n", r);
5389     r = MsiViewExecute(hview, 0);
5390     ok(!r, "got %u\n", r);
5391 
5392     hrec = MsiCreateRecord(4);
5393     MsiRecordSetInteger(hrec, 1, 1);
5394     MsiRecordSetInteger(hrec, 2, 2);
5395     MsiRecordSetInteger(hrec, 3, 3);
5396     MsiRecordSetInteger(hrec, 4, 4);
5397     r = MsiViewModify(hview, MSIMODIFY_ASSIGN, hrec);
5398     ok(!r, "got %u\n", r);
5399     MsiCloseHandle(hrec);
5400 
5401     MsiCloseHandle(hview);
5402 
5403     r = MsiDatabaseOpenViewA(hdb, "SELECT * FROM `table2`", &hview);
5404     ok(!r, "got %u\n", r);
5405     r = MsiViewExecute(hview, 0);
5406     ok(!r, "got %u\n", r);
5407 
5408     r = MsiViewFetch(hview, &hrec);
5409     ok(!r, "got %u\n", r);
5410     check_record(hrec, 4, "1", "2", "3", "4");
5411     MsiCloseHandle(hrec);
5412 
5413     r = MsiViewFetch(hview, &hrec);
5414     ok(r == ERROR_NO_MORE_ITEMS, "got %u\n", r);
5415     MsiCloseHandle(hview);
5416 
5417     r = MsiDatabaseOpenViewA(hdb, "SELECT * FROM `table2`", &hview);
5418     ok(!r, "got %u\n", r);
5419     r = MsiViewExecute(hview, 0);
5420     ok(!r, "got %u\n", r);
5421 
5422     hrec = MsiCreateRecord(4);
5423     MsiRecordSetInteger(hrec, 1, 1);
5424     MsiRecordSetInteger(hrec, 2, 4);
5425     MsiRecordSetInteger(hrec, 3, 3);
5426     MsiRecordSetInteger(hrec, 4, 3);
5427     r = MsiViewModify(hview, MSIMODIFY_ASSIGN, hrec);
5428     ok(!r, "got %u\n", r);
5429     MsiCloseHandle(hrec);
5430 
5431     MsiCloseHandle(hview);
5432 
5433     r = MsiDatabaseOpenViewA(hdb, "SELECT * FROM `table2`", &hview);
5434     ok(!r, "got %u\n", r);
5435     r = MsiViewExecute(hview, 0);
5436     ok(!r, "got %u\n", r);
5437 
5438     r = MsiViewFetch(hview, &hrec);
5439     ok(!r, "got %u\n", r);
5440     check_record(hrec, 4, "1", "2", "3", "4");
5441     MsiCloseHandle(hrec);
5442 
5443     r = MsiViewFetch(hview, &hrec);
5444     ok(!r, "got %u\n", r);
5445     check_record(hrec, 4, "1", "4", "3", "3");
5446     MsiCloseHandle(hrec);
5447 
5448     r = MsiViewFetch(hview, &hrec);
5449     ok(r == ERROR_NO_MORE_ITEMS, "got %u\n", r);
5450     MsiCloseHandle(hview);
5451 
5452     r = MsiDatabaseOpenViewA(hdb, "SELECT `B`, `C` FROM `table2`", &hview);
5453     ok(!r, "got %u\n", r);
5454     r = MsiViewExecute(hview, 0);
5455     ok(!r, "got %u\n", r);
5456 
5457     hrec = MsiCreateRecord(2);
5458     MsiRecordSetInteger(hrec, 1, 2);
5459     MsiRecordSetInteger(hrec, 2, 4);
5460     r = MsiViewModify(hview, MSIMODIFY_ASSIGN, hrec);
5461     ok(!r, "got %u\n", r);
5462     MsiRecordSetInteger(hrec, 1, 3);
5463     r = MsiViewModify(hview, MSIMODIFY_ASSIGN, hrec);
5464     ok(!r, "got %u\n", r);
5465     MsiCloseHandle(hrec);
5466 
5467     MsiCloseHandle(hview);
5468 
5469     r = MsiDatabaseOpenViewA(hdb, "SELECT * FROM `table2` ORDER BY `A`", &hview);
5470     ok(!r, "got %u\n", r);
5471     r = MsiViewExecute(hview, 0);
5472     ok(!r, "got %u\n", r);
5473 
5474     r = MsiViewFetch(hview, &hrec);
5475     ok(!r, "got %u\n", r);
5476     check_record(hrec, 4, "", "2", "4", "");
5477     MsiCloseHandle(hrec);
5478 
5479     r = MsiViewFetch(hview, &hrec);
5480     ok(!r, "got %u\n", r);
5481     check_record(hrec, 4, "", "3", "4", "");
5482     MsiCloseHandle(hrec);
5483 
5484     r = MsiViewFetch(hview, &hrec);
5485     ok(!r, "got %u\n", r);
5486     check_record(hrec, 4, "1", "2", "3", "4");
5487     MsiCloseHandle(hrec);
5488 
5489     r = MsiViewFetch(hview, &hrec);
5490     ok(!r, "got %u\n", r);
5491     check_record(hrec, 4, "1", "4", "3", "3");
5492     MsiCloseHandle(hrec);
5493 
5494     r = MsiViewFetch(hview, &hrec);
5495     ok(r == ERROR_NO_MORE_ITEMS, "got %u\n", r);
5496     MsiCloseHandle(hview);
5497 
5498     r = MsiDatabaseOpenViewA(hdb, "SELECT `A`, `B`, `C` FROM `table2`", &hview);
5499     ok(!r, "got %u\n", r);
5500     r = MsiViewExecute(hview, 0);
5501     ok(!r, "got %u\n", r);
5502 
5503     hrec = MsiCreateRecord(3);
5504     MsiRecordSetInteger(hrec, 1, 1);
5505     MsiRecordSetInteger(hrec, 2, 2);
5506     MsiRecordSetInteger(hrec, 3, 5);
5507     r = MsiViewModify(hview, MSIMODIFY_ASSIGN, hrec);
5508     ok(!r, "got %u\n", r);
5509     MsiCloseHandle(hrec);
5510 
5511     MsiCloseHandle(hview);
5512 
5513     r = MsiDatabaseOpenViewA(hdb, "SELECT * FROM `table2` ORDER BY `A`", &hview);
5514     ok(!r, "got %u\n", r);
5515     r = MsiViewExecute(hview, 0);
5516     ok(!r, "got %u\n", r);
5517 
5518     r = MsiViewFetch(hview, &hrec);
5519     ok(!r, "got %u\n", r);
5520     check_record(hrec, 4, "", "2", "4", "");
5521     MsiCloseHandle(hrec);
5522 
5523     r = MsiViewFetch(hview, &hrec);
5524     ok(!r, "got %u\n", r);
5525     check_record(hrec, 4, "", "3", "4", "");
5526     MsiCloseHandle(hrec);
5527 
5528     r = MsiViewFetch(hview, &hrec);
5529     ok(!r, "got %u\n", r);
5530     check_record(hrec, 4, "1", "2", "5", "");
5531     MsiCloseHandle(hrec);
5532 
5533     r = MsiViewFetch(hview, &hrec);
5534     ok(!r, "got %u\n", r);
5535     check_record(hrec, 4, "1", "4", "3", "3");
5536     MsiCloseHandle(hrec);
5537 
5538     r = MsiViewFetch(hview, &hrec);
5539     ok(r == ERROR_NO_MORE_ITEMS, "got %u\n", r);
5540     MsiCloseHandle(hview);
5541 
5542     /* close database */
5543     r = MsiCloseHandle( hdb );
5544     ok(r == ERROR_SUCCESS, "MsiOpenDatabase close failed\n");
5545 }
5546 
5547 static const WCHAR data10[] = { /* MOO */
5548     0x8001, 0x000b,
5549 };
5550 static const WCHAR data11[] = { /* AAR */
5551     0x8002, 0x8005,
5552     0x000c, 0x000f,
5553 };
5554 static const char data12[] = /* _StringData */
5555     "MOOABAARCDonetwofourfive";
5556 static const WCHAR data13[] = { /* _StringPool */
5557 /*  len, refs */
5558     0,   0,    /* string 0 ''     */
5559     0,   0,    /* string 1 ''     */
5560     0,   0,    /* string 2 ''     */
5561     0,   0,    /* string 3 ''     */
5562     0,   0,    /* string 4 ''     */
5563     3,   3,    /* string 5 'MOO'  */
5564     1,   1,    /* string 6 'A'    */
5565     1,   1,    /* string 7 'B'    */
5566     3,   3,    /* string 8 'AAR'  */
5567     1,   1,    /* string 9 'C'    */
5568     1,   1,    /* string a 'D'    */
5569     3,   1,    /* string b 'one'  */
5570     3,   1,    /* string c 'two'  */
5571     0,   0,    /* string d ''     */
5572     4,   1,    /* string e 'four' */
5573     4,   1,    /* string f 'five' */
5574 };
5575 
5576 static void test_stringtable(void)
5577 {
5578     MSIHANDLE hdb = 0, hview = 0, hrec = 0;
5579     IStorage *stg = NULL;
5580     IStream *stm;
5581     WCHAR name[0x20];
5582     HRESULT hr;
5583     const char *query;
5584     char buffer[MAX_PATH];
5585     WCHAR data[MAX_PATH];
5586     DWORD read;
5587     UINT r;
5588 
5589     static const DWORD mode = STGM_DIRECT | STGM_READ | STGM_SHARE_DENY_WRITE;
5590     static const WCHAR stringdata[] = {0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0}; /* _StringData */
5591     static const WCHAR stringpool[] = {0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0}; /* _StringPool */
5592     static const WCHAR moo[] = {0x4840, 0x3e16, 0x4818, 0}; /* MOO */
5593     static const WCHAR aar[] = {0x4840, 0x3a8a, 0x481b, 0}; /* AAR */
5594 
5595     DeleteFileA(msifile);
5596 
5597     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
5598     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5599 
5600     query = "CREATE TABLE `MOO` (`A` INT, `B` CHAR(72) PRIMARY KEY `A`)";
5601     r = run_query(hdb, 0, query);
5602     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5603 
5604     query = "CREATE TABLE `AAR` (`C` INT, `D` CHAR(72) PRIMARY KEY `C`)";
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 `MOO` (`A`, `B`) VALUES (1, 'one')";
5610     r = run_query(hdb, 0, query);
5611     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5612 
5613     /* insert persistent row */
5614     query = "INSERT INTO `AAR` (`C`, `D`) VALUES (2, 'two')";
5615     r = run_query(hdb, 0, query);
5616     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5617 
5618     /* open a view */
5619     query = "SELECT * FROM `MOO`";
5620     r = MsiDatabaseOpenViewA(hdb, query, &hview);
5621     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5622     r = MsiViewExecute(hview, 0);
5623     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5624 
5625     hrec = MsiCreateRecord(2);
5626 
5627     r = MsiRecordSetInteger(hrec, 1, 3);
5628     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5629     r = MsiRecordSetStringA(hrec, 2, "three");
5630     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5631 
5632     /* insert a nonpersistent row */
5633     r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec);
5634     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5635 
5636     r = MsiCloseHandle(hrec);
5637     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
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 
5643     /* insert persistent row */
5644     query = "INSERT INTO `MOO` (`A`, `B`) VALUES (4, 'four')";
5645     r = run_query(hdb, 0, query);
5646     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5647 
5648     /* insert persistent row */
5649     query = "INSERT INTO `AAR` (`C`, `D`) VALUES (5, 'five')";
5650     r = run_query(hdb, 0, query);
5651     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5652 
5653     r = MsiDatabaseCommit(hdb);
5654     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5655 
5656     r = MsiCloseHandle(hdb);
5657     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5658 
5659     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_READONLY, &hdb);
5660     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5661 
5662     query = "SELECT * FROM `MOO`";
5663     r = MsiDatabaseOpenViewA(hdb, query, &hview);
5664     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5665 
5666     r = MsiViewExecute(hview, 0);
5667     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5668 
5669     r = MsiViewFetch(hview, &hrec);
5670     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5671     check_record(hrec, 2, "1", "one");
5672     r = MsiCloseHandle(hrec);
5673     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5674 
5675     r = MsiViewFetch(hview, &hrec);
5676     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5677 
5678     r = MsiViewClose(hview);
5679     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5680     r = MsiCloseHandle(hview);
5681     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5682     r = MsiCloseHandle(hrec);
5683     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5684 
5685     query = "SELECT * FROM `AAR`";
5686     r = MsiDatabaseOpenViewA(hdb, query, &hview);
5687     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5688 
5689     r = MsiViewExecute(hview, 0);
5690     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5691 
5692     r = MsiViewFetch(hview, &hrec);
5693     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5694     check_record(hrec, 2, "2", "two");
5695     r = MsiCloseHandle(hrec);
5696     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5697 
5698     r = MsiViewFetch(hview, &hrec);
5699     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5700     check_record(hrec, 2, "5", "five");
5701     r = MsiCloseHandle(hrec);
5702     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5703 
5704     r = MsiViewFetch(hview, &hrec);
5705     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5706 
5707     r = MsiViewClose(hview);
5708     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5709     r = MsiCloseHandle(hview);
5710     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5711     r = MsiCloseHandle(hrec);
5712     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5713     r = MsiCloseHandle(hdb);
5714     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5715 
5716     MultiByteToWideChar(CP_ACP, 0, msifile, -1, name, 0x20);
5717     hr = StgOpenStorage(name, NULL, mode, NULL, 0, &stg);
5718     ok(hr == S_OK, "Expected S_OK, got %#lx\n", hr);
5719     ok(stg != NULL, "Expected non-NULL storage\n");
5720 
5721     hr = IStorage_OpenStream(stg, moo, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm);
5722     ok(hr == S_OK, "Expected S_OK, got %#lx\n", hr);
5723     ok(stm != NULL, "Expected non-NULL stream\n");
5724 
5725     hr = IStream_Read(stm, data, MAX_PATH, &read);
5726     ok(hr == S_OK, "Expected S_OK, got %#lx\n", hr);
5727     ok(read == 4, "Expected 4, got %lu\n", read);
5728     todo_wine ok(!memcmp(data, data10, read), "Unexpected data\n");
5729 
5730     hr = IStream_Release(stm);
5731     ok(hr == S_OK, "Expected S_OK, got %#lx\n", hr);
5732 
5733     hr = IStorage_OpenStream(stg, aar, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm);
5734     ok(hr == S_OK, "Expected S_OK, got %#lx\n", hr);
5735     ok(stm != NULL, "Expected non-NULL stream\n");
5736 
5737     hr = IStream_Read(stm, data, MAX_PATH, &read);
5738     ok(hr == S_OK, "Expected S_OK, got %#lx\n", hr);
5739     ok(read == 8, "Expected 8, got %lu\n", read);
5740     todo_wine
5741     {
5742         ok(!memcmp(data, data11, read), "Unexpected data\n");
5743     }
5744 
5745     hr = IStream_Release(stm);
5746     ok(hr == S_OK, "Expected S_OK, got %#lx\n", hr);
5747 
5748     hr = IStorage_OpenStream(stg, stringdata, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm);
5749     ok(hr == S_OK, "Expected S_OK, got %#lx\n", hr);
5750     ok(stm != NULL, "Expected non-NULL stream\n");
5751 
5752     hr = IStream_Read(stm, buffer, MAX_PATH, &read);
5753     ok(hr == S_OK, "Expected S_OK, got %#lx\n", hr);
5754     ok(read == 24, "Expected 24, got %lu\n", read);
5755     ok(!memcmp(buffer, data12, read), "Unexpected data\n");
5756 
5757     hr = IStream_Release(stm);
5758     ok(hr == S_OK, "Expected S_OK, got %#lx\n", hr);
5759 
5760     hr = IStorage_OpenStream(stg, stringpool, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm);
5761     ok(hr == S_OK, "Expected S_OK, got %#lx\n", hr);
5762     ok(stm != NULL, "Expected non-NULL stream\n");
5763 
5764     hr = IStream_Read(stm, data, MAX_PATH, &read);
5765     ok(hr == S_OK, "Expected S_OK, got %#lx\n", hr);
5766     todo_wine
5767     {
5768         ok(read == 64, "Expected 64, got %lu\n", read);
5769         ok(!memcmp(data, data13, read), "Unexpected data\n");
5770     }
5771 
5772     hr = IStream_Release(stm);
5773     ok(hr == S_OK, "Expected S_OK, got %#lx\n", hr);
5774 
5775     hr = IStorage_Release(stg);
5776     ok(hr == S_OK, "Expected S_OK, got %#lx\n", hr);
5777 
5778     DeleteFileA(msifile);
5779 }
5780 
5781 static void test_viewmodify_delete(void)
5782 {
5783     MSIHANDLE hdb = 0, hview = 0, hrec = 0;
5784     UINT r;
5785     const char *query;
5786 
5787     DeleteFileA(msifile);
5788 
5789     /* just MsiOpenDatabase should not create a file */
5790     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
5791     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5792 
5793     query = "CREATE TABLE `phone` ( "
5794             "`id` INT, `name` CHAR(32), `number` CHAR(32) "
5795             "PRIMARY KEY `id`)";
5796     r = run_query(hdb, 0, query);
5797     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5798 
5799     query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
5800         "VALUES('1', 'Alan', '5030581')";
5801     r = run_query(hdb, 0, query);
5802     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5803 
5804     query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
5805         "VALUES('2', 'Barry', '928440')";
5806     r = run_query(hdb, 0, query);
5807     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5808 
5809     query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
5810         "VALUES('3', 'Cindy', '2937550')";
5811     r = run_query(hdb, 0, query);
5812     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5813 
5814     query = "SELECT * FROM `phone` WHERE `id` <= 2";
5815     r = MsiDatabaseOpenViewA(hdb, query, &hview);
5816     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5817     r = MsiViewExecute(hview, 0);
5818     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5819     r = MsiViewFetch(hview, &hrec);
5820     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5821 
5822     /* delete 1 */
5823     r = MsiViewModify(hview, MSIMODIFY_DELETE, hrec);
5824     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5825 
5826     r = MsiCloseHandle(hrec);
5827     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5828     r = MsiViewFetch(hview, &hrec);
5829     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5830 
5831     /* delete 2 */
5832     MsiRecordSetInteger(hrec, 1, 4);
5833     r = MsiViewModify(hview, MSIMODIFY_DELETE, hrec);
5834     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5835 
5836     r = MsiCloseHandle(hrec);
5837     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5838     r = MsiViewClose(hview);
5839     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5840     r = MsiCloseHandle(hview);
5841     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5842 
5843     query = "SELECT * FROM `phone`";
5844     r = MsiDatabaseOpenViewA(hdb, query, &hview);
5845     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5846     r = MsiViewExecute(hview, 0);
5847     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5848     r = MsiViewFetch(hview, &hrec);
5849     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5850     check_record(hrec, 3, "3", "Cindy", "2937550");
5851     r = MsiCloseHandle(hrec);
5852     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5853 
5854     r = MsiViewFetch(hview, &hrec);
5855     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5856 
5857     r = MsiViewClose(hview);
5858     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5859     r = MsiCloseHandle(hview);
5860     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5861     r = MsiCloseHandle(hdb);
5862     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5863 }
5864 
5865 static const WCHAR _Tables[] = {0x4840, 0x3f7f, 0x4164, 0x422f, 0x4836, 0};
5866 static const WCHAR _StringData[] = {0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0};
5867 static const WCHAR _StringPool[] = {0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0};
5868 
5869 static const WCHAR data14[] = { /* _StringPool */
5870 /*  len, refs */
5871     0,   0,    /* string 0 ''    */
5872 };
5873 
5874 static const struct {
5875     LPCWSTR name;
5876     const void *data;
5877     DWORD size;
5878 } database_table_data[] =
5879 {
5880     {_Tables, NULL, 0},
5881     {_StringData, NULL, 0},
5882     {_StringPool, data14, sizeof data14},
5883 };
5884 
5885 static void enum_stream_names(IStorage *stg)
5886 {
5887     IEnumSTATSTG *stgenum = NULL;
5888     IStream *stm;
5889     HRESULT hr;
5890     STATSTG stat;
5891     ULONG n, count;
5892     BYTE data[MAX_PATH];
5893     BYTE check[MAX_PATH];
5894     DWORD sz;
5895 
5896     memset(check, 'a', MAX_PATH);
5897 
5898     hr = IStorage_EnumElements(stg, 0, NULL, 0, &stgenum);
5899     ok(hr == S_OK, "Expected S_OK, got %#lx\n", hr);
5900 
5901     n = 0;
5902     while(TRUE)
5903     {
5904         count = 0;
5905         hr = IEnumSTATSTG_Next(stgenum, 1, &stat, &count);
5906         if(FAILED(hr) || !count)
5907             break;
5908 
5909         ok(!lstrcmpW(stat.pwcsName, database_table_data[n].name),
5910            "Expected table %lu name to match\n", n);
5911 
5912         stm = NULL;
5913         hr = IStorage_OpenStream(stg, stat.pwcsName, NULL,
5914                                  STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm);
5915         ok(hr == S_OK, "Expected S_OK, got %#lx\n", hr);
5916         ok(stm != NULL, "Expected non-NULL stream\n");
5917 
5918         CoTaskMemFree(stat.pwcsName);
5919 
5920         sz = MAX_PATH;
5921         memset(data, 'a', MAX_PATH);
5922         hr = IStream_Read(stm, data, sz, &count);
5923         ok(hr == S_OK, "Expected S_OK, got %#lx\n", hr);
5924 
5925         ok(count == database_table_data[n].size,
5926            "Expected %lu, got %lu\n", database_table_data[n].size, count);
5927 
5928         if (!database_table_data[n].size)
5929             ok(!memcmp(data, check, MAX_PATH), "data should not be changed\n");
5930         else
5931             ok(!memcmp(data, database_table_data[n].data, database_table_data[n].size),
5932                "Expected table %lu data to match\n", n);
5933 
5934         IStream_Release(stm);
5935         n++;
5936     }
5937 
5938     ok(n == 3, "Expected 3, got %lu\n", n);
5939 
5940     IEnumSTATSTG_Release(stgenum);
5941 }
5942 
5943 static void test_defaultdatabase(void)
5944 {
5945     UINT r;
5946     HRESULT hr;
5947     MSIHANDLE hdb;
5948     IStorage *stg = NULL;
5949 
5950     DeleteFileA(msifile);
5951 
5952     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
5953     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5954 
5955     r = MsiDatabaseCommit(hdb);
5956     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5957 
5958     MsiCloseHandle(hdb);
5959 
5960     hr = StgOpenStorage(msifileW, NULL, STGM_READ | STGM_SHARE_DENY_WRITE, NULL, 0, &stg);
5961     ok(hr == S_OK, "Expected S_OK, got %#lx\n", hr);
5962     ok(stg != NULL, "Expected non-NULL stg\n");
5963 
5964     enum_stream_names(stg);
5965 
5966     IStorage_Release(stg);
5967     DeleteFileA(msifile);
5968 }
5969 
5970 static void test_order(void)
5971 {
5972     MSIHANDLE hdb, hview, hrec;
5973     LPCSTR query;
5974     int val;
5975     UINT r;
5976 
5977     hdb = create_db();
5978     ok(hdb, "failed to create db\n");
5979 
5980     query = "CREATE TABLE `Empty` ( `A` SHORT NOT NULL PRIMARY KEY `A`)";
5981     r = run_query(hdb, 0, query);
5982     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5983 
5984     query = "CREATE TABLE `Mesa` ( `A` SHORT NOT NULL, `B` SHORT, `C` SHORT PRIMARY KEY `A`)";
5985     r = run_query(hdb, 0, query);
5986     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5987 
5988     query = "INSERT INTO `Mesa` ( `A`, `B`, `C` ) VALUES ( 1, 2, 9 )";
5989     r = run_query(hdb, 0, query);
5990     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5991 
5992     query = "INSERT INTO `Mesa` ( `A`, `B`, `C` ) VALUES ( 3, 4, 7 )";
5993     r = run_query(hdb, 0, query);
5994     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5995 
5996     query = "INSERT INTO `Mesa` ( `A`, `B`, `C` ) VALUES ( 5, 6, 8 )";
5997     r = run_query(hdb, 0, query);
5998     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5999 
6000     query = "CREATE TABLE `Sideboard` ( `D` SHORT NOT NULL, `E` SHORT, `F` SHORT PRIMARY KEY `D`)";
6001     r = run_query(hdb, 0, query);
6002     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6003 
6004     query = "INSERT INTO `Sideboard` ( `D`, `E`, `F` ) VALUES ( 10, 11, 18 )";
6005     r = run_query(hdb, 0, query);
6006     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6007 
6008     query = "INSERT INTO `Sideboard` ( `D`, `E`, `F` ) VALUES ( 12, 13, 16 )";
6009     r = run_query(hdb, 0, query);
6010     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6011 
6012     query = "INSERT INTO `Sideboard` ( `D`, `E`, `F` ) VALUES ( 14, 15, 17 )";
6013     r = run_query(hdb, 0, query);
6014     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6015 
6016     query = "SELECT `A`, `B` FROM `Mesa` ORDER BY `C`";
6017     r = MsiDatabaseOpenViewA(hdb, query, &hview);
6018     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6019     r = MsiViewExecute(hview, 0);
6020     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6021 
6022     r = MsiViewFetch(hview, &hrec);
6023     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6024 
6025     val = MsiRecordGetInteger(hrec, 1);
6026     ok(val == 3, "Expected 3, got %d\n", val);
6027 
6028     val = MsiRecordGetInteger(hrec, 2);
6029     ok(val == 4, "Expected 3, got %d\n", val);
6030 
6031     MsiCloseHandle(hrec);
6032 
6033     r = MsiViewFetch(hview, &hrec);
6034     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6035 
6036     val = MsiRecordGetInteger(hrec, 1);
6037     ok(val == 5, "Expected 5, got %d\n", val);
6038 
6039     val = MsiRecordGetInteger(hrec, 2);
6040     ok(val == 6, "Expected 6, got %d\n", val);
6041 
6042     MsiCloseHandle(hrec);
6043 
6044     r = MsiViewFetch(hview, &hrec);
6045     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6046 
6047     val = MsiRecordGetInteger(hrec, 1);
6048     ok(val == 1, "Expected 1, got %d\n", val);
6049 
6050     val = MsiRecordGetInteger(hrec, 2);
6051     ok(val == 2, "Expected 2, got %d\n", val);
6052 
6053     MsiCloseHandle(hrec);
6054 
6055     r = MsiViewFetch(hview, &hrec);
6056     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6057 
6058     MsiViewClose(hview);
6059     MsiCloseHandle(hview);
6060 
6061     query = "SELECT `A`, `D` FROM `Mesa`, `Sideboard` ORDER BY `F`";
6062     r = MsiDatabaseOpenViewA(hdb, query, &hview);
6063     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6064     r = MsiViewExecute(hview, 0);
6065     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6066 
6067     r = MsiViewFetch(hview, &hrec);
6068     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6069 
6070     val = MsiRecordGetInteger(hrec, 1);
6071     ok(val == 1, "Expected 1, got %d\n", val);
6072 
6073     val = MsiRecordGetInteger(hrec, 2);
6074     ok(val == 12, "Expected 12, got %d\n", val);
6075 
6076     MsiCloseHandle(hrec);
6077 
6078     r = MsiViewFetch(hview, &hrec);
6079     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6080 
6081     val = MsiRecordGetInteger(hrec, 1);
6082     ok(val == 3, "Expected 3, got %d\n", val);
6083 
6084     val = MsiRecordGetInteger(hrec, 2);
6085     ok(val == 12, "Expected 12, got %d\n", val);
6086 
6087     MsiCloseHandle(hrec);
6088 
6089     r = MsiViewFetch(hview, &hrec);
6090     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6091 
6092     val = MsiRecordGetInteger(hrec, 1);
6093     ok(val == 5, "Expected 5, got %d\n", val);
6094 
6095     val = MsiRecordGetInteger(hrec, 2);
6096     ok(val == 12, "Expected 12, got %d\n", val);
6097 
6098     MsiCloseHandle(hrec);
6099 
6100     r = MsiViewFetch(hview, &hrec);
6101     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6102 
6103     val = MsiRecordGetInteger(hrec, 1);
6104     ok(val == 1, "Expected 1, got %d\n", val);
6105 
6106     val = MsiRecordGetInteger(hrec, 2);
6107     ok(val == 14, "Expected 14, got %d\n", val);
6108 
6109     MsiCloseHandle(hrec);
6110 
6111     r = MsiViewFetch(hview, &hrec);
6112     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6113 
6114     val = MsiRecordGetInteger(hrec, 1);
6115     ok(val == 3, "Expected 3, got %d\n", val);
6116 
6117     val = MsiRecordGetInteger(hrec, 2);
6118     ok(val == 14, "Expected 14, got %d\n", val);
6119 
6120     MsiCloseHandle(hrec);
6121 
6122     r = MsiViewFetch(hview, &hrec);
6123     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6124 
6125     val = MsiRecordGetInteger(hrec, 1);
6126     ok(val == 5, "Expected 5, got %d\n", val);
6127 
6128     val = MsiRecordGetInteger(hrec, 2);
6129     ok(val == 14, "Expected 14, got %d\n", val);
6130 
6131     MsiCloseHandle(hrec);
6132 
6133     r = MsiViewFetch(hview, &hrec);
6134     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6135 
6136     val = MsiRecordGetInteger(hrec, 1);
6137     ok(val == 1, "Expected 1, got %d\n", val);
6138 
6139     val = MsiRecordGetInteger(hrec, 2);
6140     ok(val == 10, "Expected 10, got %d\n", val);
6141 
6142     MsiCloseHandle(hrec);
6143 
6144     r = MsiViewFetch(hview, &hrec);
6145     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6146 
6147     val = MsiRecordGetInteger(hrec, 1);
6148     ok(val == 3, "Expected 3, got %d\n", val);
6149 
6150     val = MsiRecordGetInteger(hrec, 2);
6151     ok(val == 10, "Expected 10, got %d\n", val);
6152 
6153     MsiCloseHandle(hrec);
6154 
6155     r = MsiViewFetch(hview, &hrec);
6156     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6157 
6158     val = MsiRecordGetInteger(hrec, 1);
6159     ok(val == 5, "Expected 5, got %d\n", val);
6160 
6161     val = MsiRecordGetInteger(hrec, 2);
6162     ok(val == 10, "Expected 10, got %d\n", val);
6163 
6164     MsiCloseHandle(hrec);
6165 
6166     r = MsiViewFetch(hview, &hrec);
6167     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6168 
6169     MsiViewClose(hview);
6170     MsiCloseHandle(hview);
6171 
6172     query = "SELECT * FROM `Empty` ORDER BY `A`";
6173     r = MsiDatabaseOpenViewA(hdb, query, &hview);
6174     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6175     r = MsiViewExecute(hview, 0);
6176     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6177 
6178     r = MsiViewFetch(hview, &hrec);
6179     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6180 
6181     MsiViewClose(hview);
6182     MsiCloseHandle(hview);
6183 
6184     query = "CREATE TABLE `Buffet` ( `One` CHAR(72), `Two` SHORT PRIMARY KEY `One`)";
6185     r = run_query(hdb, 0, query);
6186     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6187 
6188     query = "INSERT INTO `Buffet` ( `One`, `Two` ) VALUES ( 'uno',  2)";
6189     r = run_query(hdb, 0, query);
6190     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6191 
6192     query = "INSERT INTO `Buffet` ( `One`, `Two` ) VALUES ( 'dos',  3)";
6193     r = run_query(hdb, 0, query);
6194     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6195 
6196     query = "INSERT INTO `Buffet` ( `One`, `Two` ) VALUES ( 'tres',  1)";
6197     r = run_query(hdb, 0, query);
6198     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6199 
6200     query = "SELECT * FROM `Buffet` WHERE `One` = 'dos' ORDER BY `Two`";
6201     r = MsiDatabaseOpenViewA(hdb, query, &hview);
6202     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6203     r = MsiViewExecute(hview, 0);
6204     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6205 
6206     r = MsiViewFetch(hview, &hrec);
6207     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6208     check_record(hrec, 2, "dos", "3");
6209     MsiCloseHandle(hrec);
6210 
6211     r = MsiViewFetch(hview, &hrec);
6212     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6213 
6214     MsiViewClose(hview);
6215     MsiCloseHandle(hview);
6216     MsiCloseHandle(hdb);
6217 }
6218 
6219 static void test_viewmodify_delete_temporary(void)
6220 {
6221     MSIHANDLE hdb, hview, hrec;
6222     const char *query;
6223     UINT r;
6224 
6225     DeleteFileA(msifile);
6226 
6227     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
6228     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6229 
6230     query = "CREATE TABLE `Table` ( `A` SHORT PRIMARY KEY `A` )";
6231     r = run_query(hdb, 0, query);
6232     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6233 
6234     query = "SELECT * FROM `Table`";
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 
6240     hrec = MsiCreateRecord(1);
6241     MsiRecordSetInteger(hrec, 1, 1);
6242 
6243     r = MsiViewModify(hview, MSIMODIFY_INSERT, hrec);
6244     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6245 
6246     MsiCloseHandle(hrec);
6247 
6248     hrec = MsiCreateRecord(1);
6249     MsiRecordSetInteger(hrec, 1, 2);
6250 
6251     r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec);
6252     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6253 
6254     MsiCloseHandle(hrec);
6255 
6256     hrec = MsiCreateRecord(1);
6257     MsiRecordSetInteger(hrec, 1, 3);
6258 
6259     r = MsiViewModify(hview, MSIMODIFY_INSERT, hrec);
6260     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6261 
6262     MsiCloseHandle(hrec);
6263 
6264     hrec = MsiCreateRecord(1);
6265     MsiRecordSetInteger(hrec, 1, 4);
6266 
6267     r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec);
6268     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6269 
6270     MsiCloseHandle(hrec);
6271     MsiViewClose(hview);
6272     MsiCloseHandle(hview);
6273 
6274     query = "SELECT * FROM `Table` WHERE  `A` = 2";
6275     r = MsiDatabaseOpenViewA(hdb, query, &hview);
6276     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6277     r = MsiViewExecute(hview, 0);
6278     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6279     r = MsiViewFetch(hview, &hrec);
6280     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6281 
6282     r = MsiViewModify(hview, MSIMODIFY_DELETE, hrec);
6283     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6284 
6285     MsiCloseHandle(hrec);
6286     MsiViewClose(hview);
6287     MsiCloseHandle(hview);
6288 
6289     query = "SELECT * FROM `Table` WHERE  `A` = 3";
6290     r = MsiDatabaseOpenViewA(hdb, query, &hview);
6291     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6292     r = MsiViewExecute(hview, 0);
6293     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6294     r = MsiViewFetch(hview, &hrec);
6295     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6296 
6297     r = MsiViewModify(hview, MSIMODIFY_DELETE, hrec);
6298     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6299 
6300     MsiCloseHandle(hrec);
6301     MsiViewClose(hview);
6302     MsiCloseHandle(hview);
6303 
6304     query = "SELECT * FROM `Table` ORDER BY `A`";
6305     r = MsiDatabaseOpenViewA(hdb, query, &hview);
6306     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6307     r = MsiViewExecute(hview, 0);
6308     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6309 
6310     r = MsiViewFetch(hview, &hrec);
6311     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6312 
6313     r = MsiRecordGetInteger(hrec, 1);
6314     ok(r == 1, "Expected 1, got %d\n", r);
6315 
6316     MsiCloseHandle(hrec);
6317 
6318     r = MsiViewFetch(hview, &hrec);
6319     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6320 
6321     r = MsiRecordGetInteger(hrec, 1);
6322     ok(r == 4, "Expected 4, got %d\n", r);
6323 
6324     MsiCloseHandle(hrec);
6325 
6326     r = MsiViewFetch(hview, &hrec);
6327     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6328 
6329     MsiViewClose(hview);
6330     MsiCloseHandle(hview);
6331     MsiCloseHandle(hdb);
6332     DeleteFileA(msifile);
6333 }
6334 
6335 static void test_deleterow(void)
6336 {
6337     MSIHANDLE hdb, hview, hrec;
6338     const char *query;
6339     UINT r;
6340 
6341     DeleteFileA(msifile);
6342 
6343     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
6344     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6345 
6346     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6347     r = run_query(hdb, 0, query);
6348     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6349 
6350     query = "INSERT INTO `Table` (`A`) VALUES ('one')";
6351     r = run_query(hdb, 0, query);
6352     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6353 
6354     query = "INSERT INTO `Table` (`A`) VALUES ('two')";
6355     r = run_query(hdb, 0, query);
6356     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6357 
6358     query = "DELETE FROM `Table` WHERE `A` = 'one'";
6359     r = run_query(hdb, 0, query);
6360     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6361 
6362     r = MsiDatabaseCommit(hdb);
6363     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6364 
6365     MsiCloseHandle(hdb);
6366 
6367     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_READONLY, &hdb);
6368     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6369 
6370     query = "SELECT * FROM `Table`";
6371     r = MsiDatabaseOpenViewA(hdb, query, &hview);
6372     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6373     r = MsiViewExecute(hview, 0);
6374     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6375 
6376     r = MsiViewFetch(hview, &hrec);
6377     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6378     check_record(hrec, 1, "two");
6379     MsiCloseHandle(hrec);
6380 
6381     r = MsiViewFetch(hview, &hrec);
6382     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6383 
6384     MsiViewClose(hview);
6385     MsiCloseHandle(hview);
6386     MsiCloseHandle(hdb);
6387     DeleteFileA(msifile);
6388 }
6389 
6390 static const CHAR import_dat[] = "A\n"
6391                                  "s72\n"
6392                                  "Table\tA\n"
6393                                  "This is a new 'string' ok\n";
6394 
6395 static void test_quotes(void)
6396 {
6397     MSIHANDLE hdb, hview, hrec;
6398     const char *query;
6399     UINT r;
6400 
6401     DeleteFileA(msifile);
6402 
6403     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
6404     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6405 
6406     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6407     r = run_query(hdb, 0, query);
6408     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6409 
6410     query = "INSERT INTO `Table` ( `A` ) VALUES ( 'This is a 'string' ok' )";
6411     r = run_query(hdb, 0, query);
6412     ok(r == ERROR_BAD_QUERY_SYNTAX,
6413        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6414 
6415     query = "INSERT INTO `Table` ( `A` ) VALUES ( \"This is a 'string' ok\" )";
6416     r = run_query(hdb, 0, query);
6417     ok(r == ERROR_BAD_QUERY_SYNTAX,
6418        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6419 
6420     query = "INSERT INTO `Table` ( `A` ) VALUES ( \"test\" )";
6421     r = run_query(hdb, 0, query);
6422     ok(r == ERROR_BAD_QUERY_SYNTAX,
6423        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6424 
6425     query = "INSERT INTO `Table` ( `A` ) VALUES ( 'This is a ''string'' ok' )";
6426     r = run_query(hdb, 0, query);
6427     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6428 
6429     query = "INSERT INTO `Table` ( `A` ) VALUES ( 'This is a '''string''' ok' )";
6430     r = run_query(hdb, 0, query);
6431     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6432 
6433     query = "INSERT INTO `Table` ( `A` ) VALUES ( 'This is a \'string\' ok' )";
6434     r = run_query(hdb, 0, query);
6435     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6436 
6437     query = "INSERT INTO `Table` ( `A` ) VALUES ( 'This is a \"string\" ok' )";
6438     r = run_query(hdb, 0, query);
6439     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6440 
6441     query = "SELECT * FROM `Table`";
6442     r = MsiDatabaseOpenViewA(hdb, query, &hview);
6443     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6444 
6445     r = MsiViewExecute(hview, 0);
6446     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6447 
6448     r = MsiViewFetch(hview, &hrec);
6449     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6450     check_record(hrec, 1, "This is a \"string\" ok");
6451     MsiCloseHandle(hrec);
6452 
6453     r = MsiViewFetch(hview, &hrec);
6454     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6455 
6456     MsiViewClose(hview);
6457     MsiCloseHandle(hview);
6458 
6459     write_file("import.idt", import_dat, (sizeof(import_dat) - 1) * sizeof(char));
6460 
6461     r = MsiDatabaseImportA(hdb, CURR_DIR, "import.idt");
6462     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6463 
6464     DeleteFileA("import.idt");
6465 
6466     query = "SELECT * FROM `Table`";
6467     r = MsiDatabaseOpenViewA(hdb, query, &hview);
6468     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6469 
6470     r = MsiViewExecute(hview, 0);
6471     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6472 
6473     r = MsiViewFetch(hview, &hrec);
6474     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6475     check_record(hrec, 1, "This is a new 'string' ok");
6476     MsiCloseHandle(hrec);
6477 
6478     r = MsiViewFetch(hview, &hrec);
6479     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6480 
6481     MsiViewClose(hview);
6482     MsiCloseHandle(hview);
6483     MsiCloseHandle(hdb);
6484     DeleteFileA(msifile);
6485 }
6486 
6487 static void test_carriagereturn(void)
6488 {
6489     MSIHANDLE hdb, hview, hrec;
6490     const char *query;
6491     UINT r;
6492 
6493     DeleteFileA(msifile);
6494 
6495     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
6496     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6497 
6498     query = "CREATE TABLE `Table`\r ( `A` CHAR(72) NOT NULL 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` \r( `A` CHAR(72) NOT NULL 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\r TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY 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\r `Table` ( `A` CHAR(72) NOT NULL PRIMARY 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` (\r `A` CHAR(72) NOT NULL PRIMARY KEY `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`\r CHAR(72) NOT NULL PRIMARY KEY `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)\r NOT NULL PRIMARY KEY `A` )";
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\r NULL PRIMARY KEY `A` )";
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 `Table` ( `A` CHAR(72) NOT \rNULL PRIMARY KEY `A` )";
6539     r = run_query(hdb, 0, query);
6540     ok(r == ERROR_BAD_QUERY_SYNTAX,
6541        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6542 
6543     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL\r PRIMARY KEY `A` )";
6544     r = run_query(hdb, 0, query);
6545     ok(r == ERROR_BAD_QUERY_SYNTAX,
6546        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6547 
6548     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL \rPRIMARY KEY `A` )";
6549     r = run_query(hdb, 0, query);
6550     ok(r == ERROR_BAD_QUERY_SYNTAX,
6551        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6552 
6553     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY\r KEY `A` )";
6554     r = run_query(hdb, 0, query);
6555     ok(r == ERROR_BAD_QUERY_SYNTAX,
6556        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6557 
6558     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY \rKEY `A` )";
6559     r = run_query(hdb, 0, query);
6560     ok(r == ERROR_BAD_QUERY_SYNTAX,
6561        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6562 
6563     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY\r `A` )";
6564     r = run_query(hdb, 0, query);
6565     ok(r == ERROR_BAD_QUERY_SYNTAX,
6566        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6567 
6568     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A`\r )";
6569     r = run_query(hdb, 0, query);
6570     ok(r == ERROR_BAD_QUERY_SYNTAX,
6571        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6572 
6573     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )\r";
6574     r = run_query(hdb, 0, query);
6575     ok(r == ERROR_BAD_QUERY_SYNTAX,
6576        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6577 
6578     query = "CREATE TABLE `\rOne` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6579     r = run_query(hdb, 0, query);
6580     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6581 
6582     query = "CREATE TABLE `Tw\ro` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6583     r = run_query(hdb, 0, query);
6584     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6585 
6586     query = "CREATE TABLE `Three\r` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6587     r = run_query(hdb, 0, query);
6588     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6589 
6590     query = "CREATE TABLE `Four` ( `A\r` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6591     r = run_query(hdb, 0, query);
6592     ok(r == ERROR_BAD_QUERY_SYNTAX,
6593        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6594 
6595     query = "CREATE TABLE `Four` ( `\rA` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6596     r = run_query(hdb, 0, query);
6597     ok(r == ERROR_BAD_QUERY_SYNTAX,
6598        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6599 
6600     query = "CREATE TABLE `Four` ( `A` CHAR(72\r) NOT NULL PRIMARY KEY `A` )";
6601     r = run_query(hdb, 0, query);
6602     ok(r == ERROR_BAD_QUERY_SYNTAX,
6603        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6604 
6605     query = "CREATE TABLE `Four` ( `A` CHAR(\r72) NOT NULL PRIMARY KEY `A` )";
6606     r = run_query(hdb, 0, query);
6607     ok(r == ERROR_BAD_QUERY_SYNTAX,
6608        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6609 
6610     query = "CREATE TABLE `Four` ( `A` CHAR(72) NOT NULL PRIMARY KEY `\rA` )";
6611     r = run_query(hdb, 0, query);
6612     ok(r == ERROR_BAD_QUERY_SYNTAX,
6613        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6614 
6615     query = "CREATE TABLE `Four` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A\r` )";
6616     r = run_query(hdb, 0, query);
6617     ok(r == ERROR_BAD_QUERY_SYNTAX,
6618        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6619 
6620     query = "CREATE TABLE `Four` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A\r` )";
6621     r = run_query(hdb, 0, query);
6622     ok(r == ERROR_BAD_QUERY_SYNTAX,
6623        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6624 
6625     query = "SELECT `Name` FROM `_Tables`";
6626     r = MsiDatabaseOpenViewA(hdb, query, &hview);
6627     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6628     r = MsiViewExecute(hview, 0);
6629     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6630 
6631     r = MsiViewFetch(hview, &hrec);
6632     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6633     check_record(hrec, 1, "\rOne");
6634     MsiCloseHandle(hrec);
6635 
6636     r = MsiViewFetch(hview, &hrec);
6637     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6638     check_record(hrec, 1, "Tw\ro");
6639     MsiCloseHandle(hrec);
6640 
6641     r = MsiViewFetch(hview, &hrec);
6642     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6643     check_record(hrec, 1, "Three\r");
6644     MsiCloseHandle(hrec);
6645 
6646     r = MsiViewFetch(hview, &hrec);
6647     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6648 
6649     MsiViewClose(hview);
6650     MsiCloseHandle(hview);
6651 
6652     MsiCloseHandle(hdb);
6653     DeleteFileA(msifile);
6654 }
6655 
6656 static void test_noquotes(void)
6657 {
6658     MSIHANDLE hdb, hview, hrec;
6659     const char *query;
6660     UINT r;
6661 
6662     DeleteFileA(msifile);
6663 
6664     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
6665     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6666 
6667     query = "CREATE TABLE Table ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6668     r = run_query(hdb, 0, query);
6669     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6670 
6671     query = "CREATE TABLE `Table` ( A CHAR(72) NOT NULL PRIMARY KEY `A` )";
6672     r = run_query(hdb, 0, query);
6673     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6674 
6675     query = "CREATE TABLE `Table2` ( `A` CHAR(72) NOT NULL PRIMARY KEY A )";
6676     r = run_query(hdb, 0, query);
6677     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6678 
6679     query = "CREATE TABLE `Table3` ( A CHAR(72) NOT NULL PRIMARY KEY A )";
6680     r = run_query(hdb, 0, query);
6681     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6682 
6683     query = "SELECT `Name` FROM `_Tables`";
6684     r = MsiDatabaseOpenViewA(hdb, query, &hview);
6685     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6686     r = MsiViewExecute(hview, 0);
6687     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6688 
6689     r = MsiViewFetch(hview, &hrec);
6690     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6691     check_record(hrec, 1, "Table");
6692     MsiCloseHandle(hrec);
6693 
6694     r = MsiViewFetch(hview, &hrec);
6695     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6696     check_record(hrec, 1, "Table2");
6697     MsiCloseHandle(hrec);
6698 
6699     r = MsiViewFetch(hview, &hrec);
6700     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6701     check_record(hrec, 1, "Table3");
6702     MsiCloseHandle(hrec);
6703 
6704     r = MsiViewFetch(hview, &hrec);
6705     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6706 
6707     MsiViewClose(hview);
6708     MsiCloseHandle(hview);
6709 
6710     query = "SELECT `Table`, `Number`, `Name` FROM `_Columns`";
6711     r = MsiDatabaseOpenViewA(hdb, query, &hview);
6712     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6713     r = MsiViewExecute(hview, 0);
6714     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6715 
6716     r = MsiViewFetch(hview, &hrec);
6717     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6718     check_record(hrec, 3, "Table", "1", "A");
6719     MsiCloseHandle(hrec);
6720 
6721     r = MsiViewFetch(hview, &hrec);
6722     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6723     check_record(hrec, 3, "Table2", "1", "A");
6724     MsiCloseHandle(hrec);
6725 
6726     r = MsiViewFetch(hview, &hrec);
6727     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6728     check_record(hrec, 3, "Table3", "1", "A");
6729     MsiCloseHandle(hrec);
6730 
6731     r = MsiViewFetch(hview, &hrec);
6732     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6733 
6734     MsiViewClose(hview);
6735     MsiCloseHandle(hview);
6736 
6737     query = "INSERT INTO Table ( `A` ) VALUES ( 'hi' )";
6738     r = run_query(hdb, 0, query);
6739     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6740 
6741     query = "INSERT INTO `Table` ( A ) VALUES ( 'hi' )";
6742     r = run_query(hdb, 0, query);
6743     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6744 
6745     query = "INSERT INTO `Table` ( `A` ) VALUES ( hi )";
6746     r = run_query(hdb, 0, query);
6747     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6748 
6749     query = "SELECT * FROM Table WHERE `A` = 'hi'";
6750     r = run_query(hdb, 0, query);
6751     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6752 
6753     query = "SELECT * FROM `Table` WHERE `A` = hi";
6754     r = run_query(hdb, 0, query);
6755     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6756 
6757     query = "SELECT * FROM Table";
6758     r = run_query(hdb, 0, query);
6759     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6760 
6761     query = "SELECT * FROM Table2";
6762     r = MsiDatabaseOpenViewA(hdb, query, &hview);
6763     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6764     r = MsiViewExecute(hview, 0);
6765     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6766 
6767     r = MsiViewFetch(hview, &hrec);
6768     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6769 
6770     MsiViewClose(hview);
6771     MsiCloseHandle(hview);
6772 
6773     query = "SELECT * FROM `Table` WHERE A = 'hi'";
6774     r = MsiDatabaseOpenViewA(hdb, query, &hview);
6775     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6776     r = MsiViewExecute(hview, 0);
6777     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6778 
6779     r = MsiViewFetch(hview, &hrec);
6780     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6781     check_record(hrec, 1, "hi");
6782     MsiCloseHandle(hrec);
6783 
6784     r = MsiViewFetch(hview, &hrec);
6785     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6786 
6787     MsiViewClose(hview);
6788     MsiCloseHandle(hview);
6789     MsiCloseHandle(hdb);
6790     DeleteFileA(msifile);
6791 }
6792 
6793 static void read_file_data(LPCSTR filename, LPSTR buffer)
6794 {
6795     HANDLE file;
6796     DWORD read;
6797 
6798     file = CreateFileA( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
6799     ZeroMemory(buffer, MAX_PATH);
6800     ReadFile(file, buffer, MAX_PATH, &read, NULL);
6801     CloseHandle(file);
6802 }
6803 
6804 static void test_forcecodepage(void)
6805 {
6806     MSIHANDLE hdb;
6807     const char *query;
6808     char buffer[MAX_PATH];
6809     UINT r;
6810 
6811     DeleteFileA(msifile);
6812     GetCurrentDirectoryA(MAX_PATH, CURR_DIR);
6813 
6814     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
6815     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6816 
6817     query = "SELECT * FROM `_ForceCodepage`";
6818     r = run_query(hdb, 0, query);
6819     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6820 
6821     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
6822     r = run_query(hdb, 0, query);
6823     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6824 
6825     query = "SELECT * FROM `_ForceCodepage`";
6826     r = run_query(hdb, 0, query);
6827     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6828 
6829     r = MsiDatabaseCommit(hdb);
6830     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6831 
6832     query = "SELECT * FROM `_ForceCodepage`";
6833     r = run_query(hdb, 0, query);
6834     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6835 
6836     MsiCloseHandle(hdb);
6837 
6838     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_DIRECT, &hdb);
6839     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6840 
6841     query = "SELECT * FROM `_ForceCodepage`";
6842     r = run_query(hdb, 0, query);
6843     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
6844 
6845     r = MsiDatabaseExportA(hdb, "_ForceCodepage", CURR_DIR, "forcecodepage.idt");
6846     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6847 
6848     read_file_data("forcecodepage.idt", buffer);
6849     ok(!lstrcmpA(buffer, "\r\n\r\n0\t_ForceCodepage\r\n"),
6850        "Expected \"\r\n\r\n0\t_ForceCodepage\r\n\", got \"%s\"\n", buffer);
6851 
6852     create_file_data("forcecodepage.idt", "\r\n\r\n850\t_ForceCodepage\r\n", 0);
6853 
6854     r = MsiDatabaseImportA(hdb, CURR_DIR, "forcecodepage.idt");
6855     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6856 
6857     r = MsiDatabaseExportA(hdb, "_ForceCodepage", CURR_DIR, "forcecodepage.idt");
6858     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6859 
6860     read_file_data("forcecodepage.idt", buffer);
6861     ok(!lstrcmpA(buffer, "\r\n\r\n850\t_ForceCodepage\r\n"),
6862        "Expected \"\r\n\r\n850\t_ForceCodepage\r\n\", got \"%s\"\n", buffer);
6863 
6864     create_file_data("forcecodepage.idt", "\r\n\r\n9999\t_ForceCodepage\r\n", 0);
6865 
6866     r = MsiDatabaseImportA(hdb, CURR_DIR, "forcecodepage.idt");
6867     ok(r == ERROR_FUNCTION_FAILED, "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
6868 
6869     MsiCloseHandle(hdb);
6870     DeleteFileA(msifile);
6871     DeleteFileA("forcecodepage.idt");
6872 }
6873 
6874 static void test_viewmodify_refresh(void)
6875 {
6876     MSIHANDLE hdb, hview, hrec;
6877     const char *query;
6878     UINT r;
6879 
6880     DeleteFileA(msifile);
6881 
6882     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
6883     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6884 
6885     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL, `B` INT PRIMARY KEY `A` )";
6886     r = run_query(hdb, 0, query);
6887     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6888 
6889     query = "INSERT INTO `Table` ( `A`, `B` ) VALUES ( 'hi', 1 )";
6890     r = run_query(hdb, 0, query);
6891     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6892 
6893     query = "SELECT * FROM `Table`";
6894     r = MsiDatabaseOpenViewA(hdb, query, &hview);
6895     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6896     r = MsiViewExecute(hview, 0);
6897     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6898 
6899     r = MsiViewFetch(hview, &hrec);
6900     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6901     check_record(hrec, 2, "hi", "1");
6902 
6903     MsiRecordSetInteger(hrec, 2, 5);
6904     r = MsiViewModify(hview, MSIMODIFY_REFRESH, hrec);
6905     ok(!r, "got %u\n", r);
6906     check_record(hrec, 2, "hi", "1");
6907 
6908     MsiRecordSetStringA(hrec, 1, "foo");
6909     r = MsiViewModify(hview, MSIMODIFY_REFRESH, hrec);
6910     ok(!r, "got %u\n", r);
6911     check_record(hrec, 2, "hi", "1");
6912 
6913     query = "UPDATE `Table` SET `B` = 2 WHERE `A` = 'hi'";
6914     r = run_query(hdb, 0, query);
6915     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6916 
6917     r = MsiViewModify(hview, MSIMODIFY_REFRESH, hrec);
6918     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6919     check_record(hrec, 2, "hi", "2");
6920 
6921     r = run_query(hdb, 0, "UPDATE `Table` SET `B` = NULL WHERE `A` = 'hi'");
6922     ok(!r, "got %u\n", r);
6923 
6924     r = MsiViewModify(hview, MSIMODIFY_REFRESH, hrec);
6925     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6926     check_record(hrec, 2, "hi", "");
6927 
6928     MsiCloseHandle(hrec);
6929 
6930     MsiViewClose(hview);
6931     MsiCloseHandle(hview);
6932 
6933     query = "INSERT INTO `Table` ( `A`, `B` ) VALUES ( 'hello', 3 )";
6934     r = run_query(hdb, 0, query);
6935     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6936 
6937     query = "SELECT * FROM `Table` WHERE `B` = 3";
6938     r = MsiDatabaseOpenViewA(hdb, query, &hview);
6939     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6940     r = MsiViewExecute(hview, 0);
6941     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6942 
6943     r = MsiViewFetch(hview, &hrec);
6944     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6945 
6946     query = "UPDATE `Table` SET `B` = 2 WHERE `A` = 'hello'";
6947     r = run_query(hdb, 0, query);
6948     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6949 
6950     query = "INSERT INTO `Table` ( `A`, `B` ) VALUES ( 'hithere', 3 )";
6951     r = run_query(hdb, 0, query);
6952     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6953 
6954     r = MsiViewModify(hview, MSIMODIFY_REFRESH, hrec);
6955     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6956     check_record(hrec, 2, "hello", "2");
6957     MsiCloseHandle(hrec);
6958 
6959     MsiViewClose(hview);
6960     MsiCloseHandle(hview);
6961 
6962     r = MsiDatabaseOpenViewA(hdb, "SELECT `B` FROM `Table` WHERE `A` = 'hello'", &hview);
6963     ok(!r, "got %u\n", r);
6964     r = MsiViewExecute(hview, 0);
6965     ok(!r, "got %u\n", r);
6966 
6967     r = MsiViewFetch(hview, &hrec);
6968     ok(!r, "got %u\n", r);
6969     check_record(hrec, 1, "2");
6970 
6971     MsiRecordSetInteger(hrec, 1, 8);
6972     r = MsiViewModify(hview, MSIMODIFY_REFRESH, hrec);
6973     ok(!r, "got %u\n", r);
6974     check_record(hrec, 1, "2");
6975 
6976     MsiCloseHandle(hrec);
6977     MsiCloseHandle(hview);
6978 
6979     MsiCloseHandle(hdb);
6980     DeleteFileA(msifile);
6981 }
6982 
6983 static void test_where_viewmodify(void)
6984 {
6985     MSIHANDLE hdb, hview, hrec;
6986     const char *query;
6987     UINT r;
6988 
6989     DeleteFileA(msifile);
6990 
6991     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
6992     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6993 
6994     query = "CREATE TABLE `Table` ( `A` INT, `B` INT PRIMARY KEY `A` )";
6995     r = run_query(hdb, 0, query);
6996     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6997 
6998     query = "INSERT INTO `Table` ( `A`, `B` ) VALUES ( 1, 2 )";
6999     r = run_query(hdb, 0, query);
7000     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7001 
7002     query = "INSERT INTO `Table` ( `A`, `B` ) VALUES ( 3, 4 )";
7003     r = run_query(hdb, 0, query);
7004     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7005 
7006     query = "INSERT INTO `Table` ( `A`, `B` ) VALUES ( 5, 6 )";
7007     r = run_query(hdb, 0, query);
7008     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7009 
7010     /* `B` = 3 doesn't match, but the view shouldn't be executed */
7011     query = "SELECT * FROM `Table` WHERE `B` = 3";
7012     r = MsiDatabaseOpenViewA(hdb, query, &hview);
7013     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7014 
7015     hrec = MsiCreateRecord(2);
7016     MsiRecordSetInteger(hrec, 1, 7);
7017     MsiRecordSetInteger(hrec, 2, 8);
7018 
7019     r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec);
7020     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7021 
7022     MsiCloseHandle(hrec);
7023     MsiViewClose(hview);
7024     MsiCloseHandle(hview);
7025 
7026     query = "SELECT * FROM `Table` WHERE `A` = 7";
7027     r = MsiDatabaseOpenViewA(hdb, query, &hview);
7028     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7029     r = MsiViewExecute(hview, 0);
7030     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7031 
7032     r = MsiViewFetch(hview, &hrec);
7033     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7034 
7035     r = MsiRecordGetInteger(hrec, 1);
7036     ok(r == 7, "Expected 7, got %d\n", r);
7037 
7038     r = MsiRecordGetInteger(hrec, 2);
7039     ok(r == 8, "Expected 8, got %d\n", r);
7040 
7041     MsiRecordSetInteger(hrec, 2, 9);
7042 
7043     r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
7044     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7045 
7046     MsiCloseHandle(hrec);
7047     MsiViewClose(hview);
7048     MsiCloseHandle(hview);
7049 
7050     query = "SELECT * FROM `Table` WHERE `A` = 7";
7051     r = MsiDatabaseOpenViewA(hdb, query, &hview);
7052     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7053     r = MsiViewExecute(hview, 0);
7054     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7055 
7056     r = MsiViewFetch(hview, &hrec);
7057     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7058 
7059     r = MsiRecordGetInteger(hrec, 1);
7060     ok(r == 7, "Expected 7, got %d\n", r);
7061 
7062     r = MsiRecordGetInteger(hrec, 2);
7063     ok(r == 9, "Expected 9, got %d\n", r);
7064 
7065     query = "UPDATE `Table` SET `B` = 10 WHERE `A` = 7";
7066     r = run_query(hdb, 0, query);
7067     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7068 
7069     r = MsiViewModify(hview, MSIMODIFY_REFRESH, hrec);
7070     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7071 
7072     r = MsiRecordGetInteger(hrec, 1);
7073     ok(r == 7, "Expected 7, got %d\n", r);
7074 
7075     r = MsiRecordGetInteger(hrec, 2);
7076     ok(r == 10, "Expected 10, got %d\n", r);
7077 
7078     MsiCloseHandle(hrec);
7079     MsiViewClose(hview);
7080     MsiCloseHandle(hview);
7081     MsiCloseHandle(hdb);
7082 }
7083 
7084 static BOOL create_storage(LPCSTR name)
7085 {
7086     WCHAR nameW[MAX_PATH];
7087     IStorage *stg;
7088     IStream *stm;
7089     HRESULT hr;
7090     DWORD count;
7091     BOOL res = FALSE;
7092 
7093     MultiByteToWideChar(CP_ACP, 0, name, -1, nameW, MAX_PATH);
7094     hr = StgCreateDocfile(nameW, STGM_CREATE | STGM_READWRITE |
7095                           STGM_DIRECT | STGM_SHARE_EXCLUSIVE, 0, &stg);
7096     if (FAILED(hr))
7097         return FALSE;
7098 
7099     hr = IStorage_CreateStream(stg, nameW, STGM_WRITE | STGM_SHARE_EXCLUSIVE,
7100                                0, 0, &stm);
7101     if (FAILED(hr))
7102         goto done;
7103 
7104     hr = IStream_Write(stm, "stgdata", 8, &count);
7105     if (SUCCEEDED(hr))
7106         res = TRUE;
7107 
7108 done:
7109     IStream_Release(stm);
7110     IStorage_Release(stg);
7111 
7112     return res;
7113 }
7114 
7115 static void test_storages_table(void)
7116 {
7117     MSIHANDLE hdb, hview, hrec;
7118     IStorage *stg, *inner;
7119     IStream *stm;
7120     char file[MAX_PATH];
7121     char buf[MAX_PATH];
7122     WCHAR name[MAX_PATH];
7123     LPCSTR query;
7124     HRESULT hr;
7125     DWORD size;
7126     UINT r;
7127 
7128     hdb = create_db();
7129     ok(hdb, "failed to create db\n");
7130 
7131     r = MsiDatabaseCommit(hdb);
7132     ok(r == ERROR_SUCCESS , "Failed to commit database\n");
7133 
7134     MsiCloseHandle(hdb);
7135 
7136     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_TRANSACT, &hdb);
7137     ok(r == ERROR_SUCCESS , "Failed to open database\n");
7138 
7139     /* check the column types */
7140     hrec = get_column_info(hdb, "SELECT * FROM `_Storages`", MSICOLINFO_TYPES);
7141     ok(hrec, "failed to get column info hrecord\n");
7142     check_record(hrec, 2, "s62", "V0");
7143     MsiCloseHandle(hrec);
7144 
7145     /* now try the names */
7146     hrec = get_column_info(hdb, "SELECT * FROM `_Storages`", MSICOLINFO_NAMES);
7147     ok(hrec, "failed to get column info hrecord\n");
7148     check_record(hrec, 2, "Name", "Data");
7149     MsiCloseHandle(hrec);
7150 
7151     create_storage("storage.bin");
7152 
7153     hrec = MsiCreateRecord(2);
7154     MsiRecordSetStringA(hrec, 1, "stgname");
7155 
7156     r = MsiRecordSetStreamA(hrec, 2, "storage.bin");
7157     ok(r == ERROR_SUCCESS, "Failed to add stream data to the hrecord: %d\n", r);
7158 
7159     DeleteFileA("storage.bin");
7160 
7161     query = "INSERT INTO `_Storages` (`Name`, `Data`) VALUES (?, ?)";
7162     r = MsiDatabaseOpenViewA(hdb, query, &hview);
7163     ok(r == ERROR_SUCCESS, "Failed to open database hview: %d\n", r);
7164 
7165     r = MsiViewExecute(hview, hrec);
7166     ok(r == ERROR_SUCCESS, "Failed to execute hview: %d\n", r);
7167 
7168     MsiCloseHandle(hrec);
7169     MsiViewClose(hview);
7170     MsiCloseHandle(hview);
7171 
7172     query = "SELECT `Name`, `Data` FROM `_Storages`";
7173     r = MsiDatabaseOpenViewA(hdb, query, &hview);
7174     ok(r == ERROR_SUCCESS, "Failed to open database hview: %d\n", r);
7175 
7176     r = MsiViewExecute(hview, 0);
7177     ok(r == ERROR_SUCCESS, "Failed to execute hview: %d\n", r);
7178 
7179     r = MsiViewFetch(hview, &hrec);
7180     ok(r == ERROR_SUCCESS, "Failed to fetch hrecord: %d\n", r);
7181 
7182     size = MAX_PATH;
7183     r = MsiRecordGetStringA(hrec, 1, file, &size);
7184     ok(r == ERROR_SUCCESS, "Failed to get string: %d\n", r);
7185     ok(!lstrcmpA(file, "stgname"), "Expected \"stgname\", got \"%s\"\n", file);
7186 
7187     size = MAX_PATH;
7188     lstrcpyA(buf, "apple");
7189     r = MsiRecordReadStream(hrec, 2, buf, &size);
7190     ok(r == ERROR_INVALID_DATA, "Expected ERROR_INVALID_DATA, got %d\n", r);
7191     ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf);
7192     ok(size == 0, "Expected 0, got %lu\n", size);
7193 
7194     MsiCloseHandle(hrec);
7195 
7196     r = MsiViewFetch(hview, &hrec);
7197     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7198 
7199     MsiViewClose(hview);
7200     MsiCloseHandle(hview);
7201 
7202     MsiDatabaseCommit(hdb);
7203     MsiCloseHandle(hdb);
7204 
7205     MultiByteToWideChar(CP_ACP, 0, msifile, -1, name, MAX_PATH);
7206     hr = StgOpenStorage(name, NULL, STGM_DIRECT | STGM_READ |
7207                         STGM_SHARE_DENY_WRITE, NULL, 0, &stg);
7208     ok(hr == S_OK, "Expected S_OK, got %#lx\n", hr);
7209     ok(stg != NULL, "Expected non-NULL storage\n");
7210 
7211     MultiByteToWideChar(CP_ACP, 0, "stgname", -1, name, MAX_PATH);
7212     hr = IStorage_OpenStorage(stg, name, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE,
7213                               NULL, 0, &inner);
7214     ok(hr == S_OK, "Expected S_OK, got %#lx\n", hr);
7215     ok(inner != NULL, "Expected non-NULL storage\n");
7216 
7217     MultiByteToWideChar(CP_ACP, 0, "storage.bin", -1, name, MAX_PATH);
7218     hr = IStorage_OpenStream(inner, name, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm);
7219     ok(hr == S_OK, "Expected S_OK, got %#lx\n", hr);
7220     ok(stm != NULL, "Expected non-NULL stream\n");
7221 
7222     hr = IStream_Read(stm, buf, MAX_PATH, &size);
7223     ok(hr == S_OK, "Expected S_OK, got %#lx\n", hr);
7224     ok(size == 8, "Expected 8, got %lu\n", size);
7225     ok(!lstrcmpA(buf, "stgdata"), "Expected \"stgdata\", got \"%s\"\n", buf);
7226 
7227     IStream_Release(stm);
7228     IStorage_Release(inner);
7229 
7230     IStorage_Release(stg);
7231     DeleteFileA(msifile);
7232 }
7233 
7234 static void test_dbtopackage(void)
7235 {
7236     MSIHANDLE hdb, hpkg;
7237     CHAR package[12], buf[MAX_PATH];
7238     DWORD size;
7239     UINT r;
7240 
7241     /* create an empty database, transact mode */
7242     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
7243     ok(r == ERROR_SUCCESS, "Failed to create database\n");
7244 
7245     set_summary_info(hdb);
7246 
7247     create_directory_table(hdb);
7248 
7249     create_custom_action_table(hdb);
7250     add_custom_action_entry(hdb, "'SetProp', 51, 'MYPROP', 'grape'");
7251 
7252     sprintf(package, "#%lu", hdb);
7253     r = MsiOpenPackageA(package, &hpkg);
7254     if (r == ERROR_INSTALL_PACKAGE_REJECTED)
7255     {
7256         skip("Not enough rights to perform tests\n");
7257         goto error;
7258     }
7259     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7260 
7261     /* property is not set yet */
7262     size = MAX_PATH;
7263     lstrcpyA(buf, "kiwi");
7264     r = MsiGetPropertyA(hpkg, "MYPROP", buf, &size);
7265     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7266     ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf);
7267     ok(size == 0, "Expected 0, got %lu\n", size);
7268 
7269     /* run the custom action to set the property */
7270     r = MsiDoActionA(hpkg, "SetProp");
7271     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7272 
7273     /* property is now set */
7274     size = MAX_PATH;
7275     lstrcpyA(buf, "kiwi");
7276     r = MsiGetPropertyA(hpkg, "MYPROP", buf, &size);
7277     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7278     ok(!lstrcmpA(buf, "grape"), "Expected \"grape\", got \"%s\"\n", buf);
7279     ok(size == 5, "Expected 5, got %lu\n", size);
7280 
7281     MsiCloseHandle(hpkg);
7282 
7283     /* reset the package */
7284     r = MsiOpenPackageA(package, &hpkg);
7285     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7286 
7287     /* property is not set anymore */
7288     size = MAX_PATH;
7289     lstrcpyA(buf, "kiwi");
7290     r = MsiGetPropertyA(hpkg, "MYPROP", buf, &size);
7291     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7292     todo_wine
7293     {
7294         ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf);
7295         ok(size == 0, "Expected 0, got %lu\n", size);
7296     }
7297 
7298     MsiCloseHandle(hdb);
7299     MsiCloseHandle(hpkg);
7300 
7301     /* create an empty database, direct mode */
7302     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATEDIRECT, &hdb);
7303     ok(r == ERROR_SUCCESS, "Failed to create database\n");
7304 
7305     set_summary_info(hdb);
7306 
7307     create_directory_table(hdb);
7308 
7309     create_custom_action_table(hdb);
7310     add_custom_action_entry(hdb, "'SetProp', 51, 'MYPROP', 'grape'");
7311 
7312     sprintf(package, "#%lu", hdb);
7313     r = MsiOpenPackageA(package, &hpkg);
7314     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7315 
7316     /* property is not set yet */
7317     size = MAX_PATH;
7318     lstrcpyA(buf, "kiwi");
7319     r = MsiGetPropertyA(hpkg, "MYPROP", buf, &size);
7320     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7321     ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf);
7322     ok(size == 0, "Expected 0, got %lu\n", size);
7323 
7324     /* run the custom action to set the property */
7325     r = MsiDoActionA(hpkg, "SetProp");
7326     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7327 
7328     /* property is now set */
7329     size = MAX_PATH;
7330     lstrcpyA(buf, "kiwi");
7331     r = MsiGetPropertyA(hpkg, "MYPROP", buf, &size);
7332     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7333     ok(!lstrcmpA(buf, "grape"), "Expected \"grape\", got \"%s\"\n", buf);
7334     ok(size == 5, "Expected 5, got %lu\n", size);
7335 
7336     MsiCloseHandle(hpkg);
7337 
7338     /* reset the package */
7339     r = MsiOpenPackageA(package, &hpkg);
7340     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7341 
7342     /* property is not set anymore */
7343     size = MAX_PATH;
7344     lstrcpyA(buf, "kiwi");
7345     r = MsiGetPropertyA(hpkg, "MYPROP", buf, &size);
7346     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7347     todo_wine
7348     {
7349         ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf);
7350         ok(size == 0, "Expected 0, got %lu\n", size);
7351     }
7352 
7353     MsiCloseHandle(hpkg);
7354 
7355 error:
7356     MsiCloseHandle(hdb);
7357     DeleteFileA(msifile);
7358 }
7359 
7360 static void test_droptable(void)
7361 {
7362     MSIHANDLE hdb, hview, hrec;
7363     LPCSTR query;
7364     UINT r;
7365 
7366     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
7367     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7368 
7369     query = "CREATE TABLE `One` ( `A` INT PRIMARY KEY `A` )";
7370     r = run_query(hdb, 0, query);
7371     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7372 
7373     query = "SELECT * FROM `One`";
7374     r = do_query(hdb, query, &hrec);
7375     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7376 
7377     query = "SELECT `Name` FROM `_Tables` WHERE `Name` = 'One'";
7378     r = MsiDatabaseOpenViewA(hdb, query, &hview);
7379     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7380     r = MsiViewExecute(hview, 0);
7381     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7382 
7383     r = MsiViewFetch(hview, &hrec);
7384     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7385     check_record(hrec, 1, "One");
7386     MsiCloseHandle(hrec);
7387 
7388     MsiViewClose(hview);
7389     MsiCloseHandle(hview);
7390 
7391     query = "SELECT `Table`, `Number`, `Name` FROM `_Columns` WHERE `Table` = 'One'";
7392     r = MsiDatabaseOpenViewA(hdb, query, &hview);
7393     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7394     r = MsiViewExecute(hview, 0);
7395     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7396 
7397     r = MsiViewFetch(hview, &hrec);
7398     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7399     check_record(hrec, 3, "One", "1", "A");
7400     MsiCloseHandle(hrec);
7401 
7402     r = MsiViewFetch(hview, &hrec);
7403     ok(r == ERROR_NO_MORE_ITEMS,
7404        "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7405 
7406     MsiViewClose(hview);
7407     MsiCloseHandle(hview);
7408 
7409     query = "DROP `One`";
7410     r = run_query(hdb, 0, query);
7411     ok(r == ERROR_BAD_QUERY_SYNTAX,
7412        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7413 
7414     query = "DROP TABLE";
7415     r = run_query(hdb, 0, query);
7416     ok(r == ERROR_BAD_QUERY_SYNTAX,
7417        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7418 
7419     query = "DROP TABLE `One`";
7420     hview = 0;
7421     r = MsiDatabaseOpenViewA(hdb, query, &hview);
7422     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7423     r = MsiViewExecute(hview, 0);
7424     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7425 
7426     r = MsiViewFetch(hview, &hrec);
7427     ok(r == ERROR_FUNCTION_FAILED,
7428        "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
7429 
7430     MsiViewClose(hview);
7431     MsiCloseHandle(hview);
7432 
7433     query = "SELECT * FROM `IDontExist`";
7434     r = do_query(hdb, query, &hrec);
7435     ok(r == ERROR_BAD_QUERY_SYNTAX,
7436        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7437 
7438     query = "SELECT * FROM `One`";
7439     r = do_query(hdb, query, &hrec);
7440     ok(r == ERROR_BAD_QUERY_SYNTAX,
7441        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7442 
7443     query = "CREATE TABLE `One` ( `A` INT PRIMARY KEY `A` )";
7444     r = run_query(hdb, 0, query);
7445     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7446 
7447     query = "DROP TABLE One";
7448     r = run_query(hdb, 0, query);
7449     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7450 
7451     query = "SELECT * FROM `One`";
7452     r = do_query(hdb, query, &hrec);
7453     ok(r == ERROR_BAD_QUERY_SYNTAX,
7454        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7455 
7456     query = "SELECT * FROM `_Tables` WHERE `Name` = 'One'";
7457     r = do_query(hdb, query, &hrec);
7458     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7459 
7460     query = "SELECT * FROM `_Columns` WHERE `Table` = 'One'";
7461     r = do_query(hdb, query, &hrec);
7462     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7463 
7464     query = "CREATE TABLE `One` ( `B` INT, `C` INT PRIMARY KEY `B` )";
7465     r = run_query(hdb, 0, query);
7466     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7467 
7468     query = "SELECT * FROM `One`";
7469     r = do_query(hdb, query, &hrec);
7470     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7471 
7472     query = "SELECT `Name` FROM `_Tables` WHERE `Name` = 'One'";
7473     r = MsiDatabaseOpenViewA(hdb, query, &hview);
7474     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7475     r = MsiViewExecute(hview, 0);
7476     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7477 
7478     r = MsiViewFetch(hview, &hrec);
7479     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7480     check_record(hrec, 1, "One");
7481     MsiCloseHandle(hrec);
7482 
7483     MsiViewClose(hview);
7484     MsiCloseHandle(hview);
7485 
7486     query = "SELECT `Table`, `Number`, `Name` FROM `_Columns` WHERE `Table` = 'One'";
7487     r = MsiDatabaseOpenViewA(hdb, query, &hview);
7488     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7489     r = MsiViewExecute(hview, 0);
7490     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7491 
7492     r = MsiViewFetch(hview, &hrec);
7493     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7494     check_record(hrec, 3, "One", "1", "B");
7495     MsiCloseHandle(hrec);
7496 
7497     r = MsiViewFetch(hview, &hrec);
7498     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7499     check_record(hrec, 3, "One", "2", "C");
7500     MsiCloseHandle(hrec);
7501 
7502     r = MsiViewFetch(hview, &hrec);
7503     ok(r == ERROR_NO_MORE_ITEMS,
7504        "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7505 
7506     MsiViewClose(hview);
7507     MsiCloseHandle(hview);
7508 
7509     query = "DROP TABLE One";
7510     r = run_query(hdb, 0, query);
7511     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7512 
7513     query = "SELECT * FROM `One`";
7514     r = do_query(hdb, query, &hrec);
7515     ok(r == ERROR_BAD_QUERY_SYNTAX,
7516        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7517 
7518     query = "SELECT * FROM `_Tables` WHERE `Name` = 'One'";
7519     r = do_query(hdb, query, &hrec);
7520     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7521 
7522     query = "SELECT * FROM `_Columns` WHERE `Table` = 'One'";
7523     r = do_query(hdb, query, &hrec);
7524     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
7525 
7526     MsiCloseHandle(hdb);
7527     DeleteFileA(msifile);
7528 }
7529 
7530 static void test_dbmerge(void)
7531 {
7532     MSIHANDLE hdb, href, hview, hrec;
7533     CHAR buf[MAX_PATH];
7534     LPCSTR query;
7535     DWORD size;
7536     UINT r;
7537 
7538     r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
7539     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7540 
7541     r = MsiOpenDatabaseW(L"refdb.msi", MSIDBOPEN_CREATE, &href);
7542     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7543 
7544     /* hDatabase is invalid */
7545     r = MsiDatabaseMergeA(0, href, "MergeErrors");
7546     ok(r == ERROR_INVALID_HANDLE,
7547        "Expected ERROR_INVALID_HANDLE, got %d\n", r);
7548 
7549     /* hDatabaseMerge is invalid */
7550     r = MsiDatabaseMergeA(hdb, 0, "MergeErrors");
7551     ok(r == ERROR_INVALID_HANDLE,
7552        "Expected ERROR_INVALID_HANDLE, got %d\n", r);
7553 
7554     /* szTableName is NULL */
7555     r = MsiDatabaseMergeA(hdb, href, NULL);
7556     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7557 
7558     /* szTableName is empty */
7559     r = MsiDatabaseMergeA(hdb, href, "");
7560     ok(r == ERROR_INVALID_TABLE, "Expected ERROR_INVALID_TABLE, got %d\n", r);
7561 
7562     /* both DBs empty, szTableName is valid */
7563     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7564     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7565 
7566     query = "CREATE TABLE `One` ( `A` INT PRIMARY KEY `A` )";
7567     r = run_query(hdb, 0, query);
7568     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7569 
7570     query = "CREATE TABLE `One` ( `A` CHAR(72) PRIMARY KEY `A` )";
7571     r = run_query(href, 0, query);
7572     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7573 
7574     /* column types don't match */
7575     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7576     ok(r == ERROR_DATATYPE_MISMATCH,
7577        "Expected ERROR_DATATYPE_MISMATCH, got %d\n", r);
7578 
7579     /* nothing in MergeErrors */
7580     query = "SELECT * FROM `MergeErrors`";
7581     r = do_query(hdb, query, &hrec);
7582     ok(r == ERROR_BAD_QUERY_SYNTAX,
7583        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7584 
7585     query = "DROP TABLE `One`";
7586     r = run_query(hdb, 0, query);
7587     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7588 
7589     query = "DROP TABLE `One`";
7590     r = run_query(href, 0, query);
7591     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7592 
7593     query = "CREATE TABLE `One` ( "
7594         "`A` CHAR(72), "
7595         "`B` CHAR(56), "
7596         "`C` CHAR(64) LOCALIZABLE, "
7597         "`D` LONGCHAR, "
7598         "`E` CHAR(72) NOT NULL, "
7599         "`F` CHAR(56) NOT NULL, "
7600         "`G` CHAR(64) NOT NULL LOCALIZABLE, "
7601         "`H` LONGCHAR NOT NULL "
7602         "PRIMARY KEY `A` )";
7603     r = run_query(hdb, 0, query);
7604     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7605 
7606     query = "CREATE TABLE `One` ( "
7607         "`A` CHAR(64), "
7608         "`B` CHAR(64), "
7609         "`C` CHAR(64), "
7610         "`D` CHAR(64), "
7611         "`E` CHAR(64) NOT NULL, "
7612         "`F` CHAR(64) NOT NULL, "
7613         "`G` CHAR(64) NOT NULL, "
7614         "`H` CHAR(64) NOT NULL "
7615         "PRIMARY KEY `A` )";
7616     r = run_query(href, 0, query);
7617     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7618 
7619     /* column string types don't match exactly */
7620     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7621     ok(r == ERROR_SUCCESS,
7622        "Expected ERROR_SUCCESS, got %d\n", r);
7623 
7624     /* nothing in MergeErrors */
7625     query = "SELECT * FROM `MergeErrors`";
7626     r = do_query(hdb, query, &hrec);
7627     ok(r == ERROR_BAD_QUERY_SYNTAX,
7628        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7629 
7630     query = "DROP TABLE `One`";
7631     r = run_query(hdb, 0, query);
7632     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7633 
7634     query = "DROP TABLE `One`";
7635     r = run_query(href, 0, query);
7636     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7637 
7638     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A` )";
7639     r = run_query(hdb, 0, query);
7640     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7641 
7642     query = "CREATE TABLE `One` ( `A` INT, `C` INT PRIMARY KEY `A` )";
7643     r = run_query(href, 0, query);
7644     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7645 
7646     /* column names don't match */
7647     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7648     ok(r == ERROR_DATATYPE_MISMATCH,
7649        "Expected ERROR_DATATYPE_MISMATCH, got %d\n", r);
7650 
7651     /* nothing in MergeErrors */
7652     query = "SELECT * FROM `MergeErrors`";
7653     r = do_query(hdb, query, &hrec);
7654     ok(r == ERROR_BAD_QUERY_SYNTAX,
7655        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7656 
7657     query = "DROP TABLE `One`";
7658     r = run_query(hdb, 0, query);
7659     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7660 
7661     query = "DROP TABLE `One`";
7662     r = run_query(href, 0, query);
7663     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7664 
7665     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A` )";
7666     r = run_query(hdb, 0, query);
7667     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7668 
7669     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `B` )";
7670     r = run_query(href, 0, query);
7671     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7672 
7673     /* primary keys don't match */
7674     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7675     ok(r == ERROR_DATATYPE_MISMATCH,
7676        "Expected ERROR_DATATYPE_MISMATCH, got %d\n", r);
7677 
7678     /* nothing in MergeErrors */
7679     query = "SELECT * FROM `MergeErrors`";
7680     r = do_query(hdb, query, &hrec);
7681     ok(r == ERROR_BAD_QUERY_SYNTAX,
7682        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7683 
7684     query = "DROP TABLE `One`";
7685     r = run_query(hdb, 0, query);
7686     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7687 
7688     query = "DROP TABLE `One`";
7689     r = run_query(href, 0, query);
7690     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7691 
7692     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A` )";
7693     r = run_query(hdb, 0, query);
7694     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7695 
7696     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A`, `B` )";
7697     r = run_query(href, 0, query);
7698     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7699 
7700     /* number of primary keys doesn't match */
7701     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7702     ok(r == ERROR_DATATYPE_MISMATCH,
7703        "Expected ERROR_DATATYPE_MISMATCH, got %d\n", r);
7704 
7705     /* nothing in MergeErrors */
7706     query = "SELECT * FROM `MergeErrors`";
7707     r = do_query(hdb, query, &hrec);
7708     ok(r == ERROR_BAD_QUERY_SYNTAX,
7709        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7710 
7711     query = "DROP TABLE `One`";
7712     r = run_query(hdb, 0, query);
7713     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7714 
7715     query = "DROP TABLE `One`";
7716     r = run_query(href, 0, query);
7717     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7718 
7719     query = "CREATE TABLE `One` ( `A` INT, `B` INT, `C` INT PRIMARY KEY `A` )";
7720     r = run_query(hdb, 0, query);
7721     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7722 
7723     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A` )";
7724     r = run_query(href, 0, query);
7725     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7726 
7727     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 1, 2 )";
7728     r = run_query(href, 0, query);
7729     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7730 
7731     /* number of columns doesn't match */
7732     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7733     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7734 
7735     query = "SELECT * FROM `One`";
7736     r = do_query(hdb, query, &hrec);
7737     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7738 
7739     r = MsiRecordGetInteger(hrec, 1);
7740     ok(r == 1, "Expected 1, got %d\n", r);
7741 
7742     r = MsiRecordGetInteger(hrec, 2);
7743     ok(r == 2, "Expected 2, got %d\n", r);
7744 
7745     r = MsiRecordGetInteger(hrec, 3);
7746     ok(r == MSI_NULL_INTEGER, "Expected MSI_NULL_INTEGER, got %d\n", r);
7747 
7748     MsiCloseHandle(hrec);
7749 
7750     /* nothing in MergeErrors */
7751     query = "SELECT * FROM `MergeErrors`";
7752     r = do_query(hdb, query, &hrec);
7753     ok(r == ERROR_BAD_QUERY_SYNTAX,
7754        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7755 
7756     query = "DROP TABLE `One`";
7757     r = run_query(hdb, 0, query);
7758     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7759 
7760     query = "DROP TABLE `One`";
7761     r = run_query(href, 0, query);
7762     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7763 
7764     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A` )";
7765     r = run_query(hdb, 0, query);
7766     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7767 
7768     query = "CREATE TABLE `One` ( `A` INT, `B` INT, `C` INT PRIMARY KEY `A` )";
7769     r = run_query(href, 0, query);
7770     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7771 
7772     query = "INSERT INTO `One` ( `A`, `B`, `C` ) VALUES ( 1, 2, 3 )";
7773     r = run_query(href, 0, query);
7774     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7775 
7776     /* number of columns doesn't match */
7777     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7778     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7779 
7780     query = "SELECT * FROM `One`";
7781     r = do_query(hdb, query, &hrec);
7782     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7783 
7784     r = MsiRecordGetInteger(hrec, 1);
7785     ok(r == 1, "Expected 1, got %d\n", r);
7786 
7787     r = MsiRecordGetInteger(hrec, 2);
7788     ok(r == 2, "Expected 2, got %d\n", r);
7789 
7790     r = MsiRecordGetInteger(hrec, 3);
7791     ok(r == MSI_NULL_INTEGER, "Expected MSI_NULL_INTEGER, got %d\n", r);
7792 
7793     MsiCloseHandle(hrec);
7794 
7795     /* nothing in MergeErrors */
7796     query = "SELECT * FROM `MergeErrors`";
7797     r = do_query(hdb, query, &hrec);
7798     ok(r == ERROR_BAD_QUERY_SYNTAX,
7799        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7800 
7801     query = "DROP TABLE `One`";
7802     r = run_query(hdb, 0, query);
7803     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7804 
7805     query = "DROP TABLE `One`";
7806     r = run_query(href, 0, query);
7807     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7808 
7809     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A` )";
7810     r = run_query(hdb, 0, query);
7811     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7812 
7813     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 1, 1 )";
7814     r = run_query(hdb, 0, query);
7815     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7816 
7817     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 2, 2 )";
7818     r = run_query(hdb, 0, query);
7819     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7820 
7821     query = "CREATE TABLE `One` ( `A` INT, `B` INT PRIMARY KEY `A` )";
7822     r = run_query(href, 0, query);
7823     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7824 
7825     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 1, 2 )";
7826     r = run_query(href, 0, query);
7827     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7828 
7829     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 2, 3 )";
7830     r = run_query(href, 0, query);
7831     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7832 
7833     /* primary keys match, rows do not */
7834     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7835     ok(r == ERROR_FUNCTION_FAILED,
7836        "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
7837 
7838     /* nothing in MergeErrors */
7839     query = "SELECT * FROM `MergeErrors`";
7840     r = do_query(hdb, query, &hrec);
7841     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7842     check_record(hrec, 2, "One", "2");
7843     MsiCloseHandle(hrec);
7844 
7845     r = MsiDatabaseOpenViewA(hdb, "SELECT * FROM `MergeErrors`", &hview);
7846     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7847 
7848     r = MsiViewGetColumnInfo(hview, MSICOLINFO_NAMES, &hrec);
7849     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7850     check_record(hrec, 2, "Table", "NumRowMergeConflicts");
7851     MsiCloseHandle(hrec);
7852 
7853     r = MsiViewGetColumnInfo(hview, MSICOLINFO_TYPES, &hrec);
7854     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7855     check_record(hrec, 2, "s255", "i2");
7856     MsiCloseHandle(hrec);
7857 
7858     MsiViewClose(hview);
7859     MsiCloseHandle(hview);
7860 
7861     query = "DROP TABLE `MergeErrors`";
7862     r = run_query(hdb, 0, query);
7863     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7864 
7865     query = "DROP TABLE `One`";
7866     r = run_query(hdb, 0, query);
7867     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7868 
7869     query = "DROP TABLE `One`";
7870     r = run_query(href, 0, query);
7871     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7872 
7873     query = "CREATE TABLE `One` ( `A` INT, `B` CHAR(72) PRIMARY KEY `A` )";
7874     r = run_query(href, 0, query);
7875     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7876 
7877     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 1, 'hi' )";
7878     r = run_query(href, 0, query);
7879     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7880 
7881     /* table from merged database is not in target database */
7882     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7883     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7884 
7885     query = "SELECT * FROM `One`";
7886     r = do_query(hdb, query, &hrec);
7887     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7888     check_record(hrec, 2, "1", "hi");
7889     MsiCloseHandle(hrec);
7890 
7891     /* nothing in MergeErrors */
7892     query = "SELECT * FROM `MergeErrors`";
7893     r = do_query(hdb, query, &hrec);
7894     ok(r == ERROR_BAD_QUERY_SYNTAX,
7895        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7896 
7897     query = "DROP TABLE `One`";
7898     r = run_query(hdb, 0, query);
7899     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7900 
7901     query = "DROP TABLE `One`";
7902     r = run_query(href, 0, query);
7903     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7904 
7905     query = "CREATE TABLE `One` ( "
7906             "`A` CHAR(72), `B` INT PRIMARY KEY `A` )";
7907     r = run_query(hdb, 0, query);
7908     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7909 
7910     query = "CREATE TABLE `One` ( "
7911             "`A` CHAR(72), `B` INT PRIMARY KEY `A` )";
7912     r = run_query(href, 0, query);
7913     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7914 
7915     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 'hi', 1 )";
7916     r = run_query(href, 0, query);
7917     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7918 
7919     /* primary key is string */
7920     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7921     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7922 
7923     query = "SELECT * FROM `One`";
7924     r = do_query(hdb, query, &hrec);
7925     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7926     check_record(hrec, 2, "hi", "1");
7927     MsiCloseHandle(hrec);
7928 
7929     /* nothing in MergeErrors */
7930     query = "SELECT * FROM `MergeErrors`";
7931     r = do_query(hdb, query, &hrec);
7932     ok(r == ERROR_BAD_QUERY_SYNTAX,
7933        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7934 
7935     create_file_data("codepage.idt", "\r\n\r\n850\t_ForceCodepage\r\n", 0);
7936 
7937     GetCurrentDirectoryA(MAX_PATH, buf);
7938     r = MsiDatabaseImportA(hdb, buf, "codepage.idt");
7939     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7940 
7941     query = "DROP TABLE `One`";
7942     r = run_query(hdb, 0, query);
7943     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7944 
7945     query = "DROP TABLE `One`";
7946     r = run_query(href, 0, query);
7947     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7948 
7949     query = "CREATE TABLE `One` ( "
7950             "`A` INT, `B` CHAR(72) LOCALIZABLE PRIMARY KEY `A` )";
7951     r = run_query(hdb, 0, query);
7952     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7953 
7954     query = "CREATE TABLE `One` ( "
7955             "`A` INT, `B` CHAR(72) LOCALIZABLE PRIMARY KEY `A` )";
7956     r = run_query(href, 0, query);
7957     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7958 
7959     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 1, 'hi' )";
7960     r = run_query(href, 0, query);
7961     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7962 
7963     /* code page does not match */
7964     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
7965     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7966 
7967     query = "SELECT * FROM `One`";
7968     r = do_query(hdb, query, &hrec);
7969     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7970     check_record(hrec, 2, "1", "hi");
7971     MsiCloseHandle(hrec);
7972 
7973     /* nothing in MergeErrors */
7974     query = "SELECT * FROM `MergeErrors`";
7975     r = do_query(hdb, query, &hrec);
7976     ok(r == ERROR_BAD_QUERY_SYNTAX,
7977        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
7978 
7979     query = "DROP TABLE `One`";
7980     r = run_query(hdb, 0, query);
7981     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7982 
7983     query = "DROP TABLE `One`";
7984     r = run_query(href, 0, query);
7985     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7986 
7987     query = "CREATE TABLE `One` ( `A` INT, `B` OBJECT PRIMARY KEY `A` )";
7988     r = run_query(hdb, 0, query);
7989     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7990 
7991     query = "CREATE TABLE `One` ( `A` INT, `B` OBJECT PRIMARY KEY `A` )";
7992     r = run_query(href, 0, query);
7993     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
7994 
7995     create_file("binary.dat");
7996     hrec = MsiCreateRecord(1);
7997     MsiRecordSetStreamA(hrec, 1, "binary.dat");
7998 
7999     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 1, ? )";
8000     r = run_query(href, hrec, query);
8001     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8002 
8003     MsiCloseHandle(hrec);
8004 
8005     /* binary data to merge */
8006     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
8007     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8008 
8009     query = "SELECT * FROM `One`";
8010     r = do_query(hdb, query, &hrec);
8011     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8012 
8013     r = MsiRecordGetInteger(hrec, 1);
8014     ok(r == 1, "Expected 1, got %d\n", r);
8015 
8016     size = MAX_PATH;
8017     ZeroMemory(buf, MAX_PATH);
8018     r = MsiRecordReadStream(hrec, 2, buf, &size);
8019     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8020     ok(!lstrcmpA(buf, "binary.dat\n"),
8021        "Expected \"binary.dat\\n\", got \"%s\"\n", buf);
8022 
8023     MsiCloseHandle(hrec);
8024 
8025     /* nothing in MergeErrors */
8026     query = "SELECT * FROM `MergeErrors`";
8027     r = do_query(hdb, query, &hrec);
8028     ok(r == ERROR_BAD_QUERY_SYNTAX,
8029        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
8030 
8031     query = "DROP TABLE `One`";
8032     r = run_query(hdb, 0, query);
8033     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8034 
8035     query = "DROP TABLE `One`";
8036     r = run_query(href, 0, query);
8037     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8038 
8039     query = "CREATE TABLE `One` ( `A` INT, `B` CHAR(72) PRIMARY KEY `A` )";
8040     r = run_query(hdb, 0, query);
8041     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8042     r = run_query(href, 0, query);
8043     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8044 
8045     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 1, 'foo' )";
8046     r = run_query(href, 0, query);
8047     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8048 
8049     query = "INSERT INTO `One` ( `A`, `B` ) VALUES ( 2, 'bar' )";
8050     r = run_query(href, 0, query);
8051     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8052 
8053     r = MsiDatabaseMergeA(hdb, href, "MergeErrors");
8054     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8055 
8056     query = "SELECT * FROM `One`";
8057     r = MsiDatabaseOpenViewA(hdb, query, &hview);
8058     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8059     r = MsiViewExecute(hview, 0);
8060     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8061 
8062     r = MsiViewFetch(hview, &hrec);
8063     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8064     check_record(hrec, 2, "1", "foo");
8065     MsiCloseHandle(hrec);
8066 
8067     r = MsiViewFetch(hview, &hrec);
8068     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8069     check_record(hrec, 2, "2", "bar");
8070     MsiCloseHandle(hrec);
8071 
8072     r = MsiViewFetch(hview, &hrec);
8073     ok(r == ERROR_NO_MORE_ITEMS,
8074        "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
8075 
8076     MsiViewClose(hview);
8077     MsiCloseHandle(hview);
8078 
8079     MsiCloseHandle(hdb);
8080     MsiCloseHandle(href);
8081     DeleteFileA(msifile);
8082     DeleteFileW(L"refdb.msi");
8083     DeleteFileA("codepage.idt");
8084     DeleteFileA("binary.dat");
8085 }
8086 
8087 static void test_select_with_tablenames(void)
8088 {
8089     MSIHANDLE hdb, view, rec;
8090     LPCSTR query;
8091     UINT r;
8092     int i;
8093 
8094     int vals[4][2] = {
8095         {1,12},
8096         {4,12},
8097         {1,15},
8098         {4,15}};
8099 
8100     hdb = create_db();
8101     ok(hdb, "failed to create db\n");
8102 
8103     /* Build a pair of tables with the same column names, but unique data */
8104     query = "CREATE TABLE `T1` ( `A` SHORT, `B` SHORT PRIMARY KEY `A`)";
8105     r = run_query(hdb, 0, query);
8106     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8107 
8108     query = "INSERT INTO `T1` ( `A`, `B` ) VALUES ( 1, 2 )";
8109     r = run_query(hdb, 0, query);
8110     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8111 
8112     query = "INSERT INTO `T1` ( `A`, `B` ) VALUES ( 4, 5 )";
8113     r = run_query(hdb, 0, query);
8114     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8115 
8116     query = "CREATE TABLE `T2` ( `A` SHORT, `B` SHORT PRIMARY KEY `A`)";
8117     r = run_query(hdb, 0, query);
8118     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8119 
8120     query = "INSERT INTO `T2` ( `A`, `B` ) VALUES ( 11, 12 )";
8121     r = run_query(hdb, 0, query);
8122     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8123 
8124     query = "INSERT INTO `T2` ( `A`, `B` ) VALUES ( 14, 15 )";
8125     r = run_query(hdb, 0, query);
8126     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8127 
8128 
8129     /* Test that selection based on prefixing the column with the table
8130      * actually selects the right data */
8131 
8132     query = "SELECT T1.A, T2.B FROM T1,T2";
8133     r = MsiDatabaseOpenViewA(hdb, query, &view);
8134     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8135     r = MsiViewExecute(view, 0);
8136     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8137 
8138     for (i = 0; i < 4; i++)
8139     {
8140         r = MsiViewFetch(view, &rec);
8141         ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8142 
8143         r = MsiRecordGetInteger(rec, 1);
8144         ok(r == vals[i][0], "Expected %d, got %d\n", vals[i][0], r);
8145 
8146         r = MsiRecordGetInteger(rec, 2);
8147         ok(r == vals[i][1], "Expected %d, got %d\n", vals[i][1], r);
8148 
8149         MsiCloseHandle(rec);
8150     }
8151 
8152     r = MsiViewFetch(view, &rec);
8153     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
8154 
8155     MsiViewClose(view);
8156     MsiCloseHandle(view);
8157     MsiCloseHandle(hdb);
8158     DeleteFileA(msifile);
8159 }
8160 
8161 static const UINT ordervals[6][3] =
8162 {
8163     { MSI_NULL_INTEGER, 12, 13 },
8164     { 1, 2, 3 },
8165     { 6, 4, 5 },
8166     { 8, 9, 7 },
8167     { 10, 11, MSI_NULL_INTEGER },
8168     { 14, MSI_NULL_INTEGER, 15 }
8169 };
8170 
8171 static void test_insertorder(void)
8172 {
8173     MSIHANDLE hdb, view, rec;
8174     LPCSTR query;
8175     UINT r;
8176     int i;
8177 
8178     hdb = create_db();
8179     ok(hdb, "failed to create db\n");
8180 
8181     query = "CREATE TABLE `T` ( `A` SHORT, `B` SHORT, `C` SHORT PRIMARY KEY `A`)";
8182     r = run_query(hdb, 0, query);
8183     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8184 
8185     query = "INSERT INTO `T` ( `A`, `B`, `C` ) VALUES ( 1, 2, 3 )";
8186     r = run_query(hdb, 0, query);
8187     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8188 
8189     query = "INSERT INTO `T` ( `B`, `C`, `A` ) VALUES ( 4, 5, 6 )";
8190     r = run_query(hdb, 0, query);
8191     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8192 
8193     query = "INSERT INTO `T` ( `C`, `A`, `B` ) VALUES ( 7, 8, 9 )";
8194     r = run_query(hdb, 0, query);
8195     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8196 
8197     query = "INSERT INTO `T` ( `A`, `B` ) VALUES ( 10, 11 )";
8198     r = run_query(hdb, 0, query);
8199     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8200 
8201     query = "INSERT INTO `T` ( `B`, `C` ) VALUES ( 12, 13 )";
8202     r = run_query(hdb, 0, query);
8203     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8204 
8205     /* fails because the primary key already
8206      * has an MSI_NULL_INTEGER value set above
8207      */
8208     query = "INSERT INTO `T` ( `C` ) VALUES ( 14 )";
8209     r = run_query(hdb, 0, query);
8210     ok(r == ERROR_FUNCTION_FAILED,
8211        "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
8212 
8213     /* replicate the error where primary key is set twice */
8214     query = "INSERT INTO `T` ( `A`, `C` ) VALUES ( 1, 14 )";
8215     r = run_query(hdb, 0, query);
8216     ok(r == ERROR_FUNCTION_FAILED,
8217        "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
8218 
8219     query = "INSERT INTO `T` ( `A`, `C` ) VALUES ( 14, 15 )";
8220     r = run_query(hdb, 0, query);
8221     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8222 
8223     query = "INSERT INTO `T` VALUES ( 16 )";
8224     r = run_query(hdb, 0, query);
8225     ok(r == ERROR_BAD_QUERY_SYNTAX,
8226        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
8227 
8228     query = "INSERT INTO `T` VALUES ( 17, 18 )";
8229     r = run_query(hdb, 0, query);
8230     ok(r == ERROR_BAD_QUERY_SYNTAX,
8231        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
8232 
8233     query = "INSERT INTO `T` VALUES ( 19, 20, 21 )";
8234     r = run_query(hdb, 0, query);
8235     ok(r == ERROR_BAD_QUERY_SYNTAX,
8236        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
8237 
8238     query = "SELECT * FROM `T`";
8239     r = MsiDatabaseOpenViewA(hdb, query, &view);
8240     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8241     r = MsiViewExecute(view, 0);
8242     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8243 
8244     for (i = 0; i < 6; i++)
8245     {
8246         r = MsiViewFetch(view, &rec);
8247         ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8248 
8249         r = MsiRecordGetInteger(rec, 1);
8250         ok(r == ordervals[i][0], "Expected %d, got %d\n", ordervals[i][0], r);
8251 
8252         r = MsiRecordGetInteger(rec, 2);
8253         ok(r == ordervals[i][1], "Expected %d, got %d\n", ordervals[i][1], r);
8254 
8255         r = MsiRecordGetInteger(rec, 3);
8256         ok(r == ordervals[i][2], "Expected %d, got %d\n", ordervals[i][2], r);
8257 
8258         MsiCloseHandle(rec);
8259     }
8260 
8261     r = MsiViewFetch(view, &rec);
8262     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
8263 
8264     MsiViewClose(view);
8265     MsiCloseHandle(view);
8266 
8267     query = "DELETE FROM `T` WHERE `A` IS NULL";
8268     r = run_query(hdb, 0, query);
8269     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8270 
8271     query = "INSERT INTO `T` ( `B`, `C` ) VALUES ( 12, 13 ) TEMPORARY";
8272     r = run_query(hdb, 0, query);
8273     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8274 
8275     query = "SELECT * FROM `T`";
8276     r = MsiDatabaseOpenViewA(hdb, query, &view);
8277     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8278     r = MsiViewExecute(view, 0);
8279     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8280 
8281     for (i = 0; i < 6; i++)
8282     {
8283         r = MsiViewFetch(view, &rec);
8284         ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8285 
8286         r = MsiRecordGetInteger(rec, 1);
8287         ok(r == ordervals[i][0], "Expected %d, got %d\n", ordervals[i][0], r);
8288 
8289         r = MsiRecordGetInteger(rec, 2);
8290         ok(r == ordervals[i][1], "Expected %d, got %d\n", ordervals[i][1], r);
8291 
8292         r = MsiRecordGetInteger(rec, 3);
8293         ok(r == ordervals[i][2], "Expected %d, got %d\n", ordervals[i][2], r);
8294 
8295         MsiCloseHandle(rec);
8296     }
8297 
8298     r = MsiViewFetch(view, &rec);
8299     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
8300 
8301     MsiViewClose(view);
8302     MsiCloseHandle(view);
8303     MsiCloseHandle(hdb);
8304     DeleteFileA(msifile);
8305 }
8306 
8307 static void test_columnorder(void)
8308 {
8309     MSIHANDLE hdb, view, rec;
8310     LPCSTR query;
8311     UINT r;
8312 
8313     hdb = create_db();
8314     ok(hdb, "failed to create db\n");
8315 
8316     /* Each column is a slot:
8317      * ---------------------
8318      * | B | C | A | E | D |
8319      * ---------------------
8320      *
8321      * When a column is selected as a primary key,
8322      * the column occupying the nth primary key slot is swapped
8323      * with the current position of the primary key in question:
8324      *
8325      * set primary key `D`
8326      * ---------------------    ---------------------
8327      * | B | C | A | E | D | -> | D | C | A | E | B |
8328      * ---------------------    ---------------------
8329      *
8330      * set primary key `E`
8331      * ---------------------    ---------------------
8332      * | D | C | A | E | B | -> | D | E | A | C | B |
8333      * ---------------------    ---------------------
8334      */
8335 
8336     query = "CREATE TABLE `T` ( `B` SHORT NOT NULL, `C` SHORT NOT NULL, "
8337             "`A` CHAR(255), `E` INT, `D` CHAR(255) NOT NULL "
8338             "PRIMARY KEY `D`, `E`)";
8339     r = run_query(hdb, 0, query);
8340     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8341 
8342     query = "SELECT * FROM `T`";
8343     r = MsiDatabaseOpenViewA(hdb, query, &view);
8344     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8345 
8346     r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
8347     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8348     check_record(rec, 5, "s255", "I2", "S255", "i2", "i2");
8349     MsiCloseHandle(rec);
8350 
8351     r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec);
8352     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8353     check_record(rec, 5, "D", "E", "A", "C", "B");
8354     MsiCloseHandle(rec);
8355 
8356     MsiViewClose(view);
8357     MsiCloseHandle(view);
8358 
8359     query = "INSERT INTO `T` ( `B`, `C`, `A`, `E`, `D` ) "
8360             "VALUES ( 1, 2, 'a', 3, 'bc' )";
8361     r = run_query(hdb, 0, query);
8362     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8363 
8364     query = "SELECT * FROM `T`";
8365     r = do_query(hdb, query, &rec);
8366     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8367     check_record(rec, 5, "bc", "3", "a", "2", "1");
8368     MsiCloseHandle(rec);
8369 
8370     query = "SELECT `Table`, `Number`, `Name` FROM `_Columns` WHERE `Table` = 'T'";
8371     r = MsiDatabaseOpenViewA(hdb, query, &view);
8372     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8373     r = MsiViewExecute(view, 0);
8374     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8375 
8376     r = MsiViewFetch(view, &rec);
8377     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8378     check_record(rec, 3, "T", "1", "D");
8379     MsiCloseHandle(rec);
8380 
8381     r = MsiViewFetch(view, &rec);
8382     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8383     check_record(rec, 3, "T", "2", "E");
8384     MsiCloseHandle(rec);
8385 
8386     r = MsiViewFetch(view, &rec);
8387     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8388     check_record(rec, 3, "T", "3", "A");
8389     MsiCloseHandle(rec);
8390 
8391     r = MsiViewFetch(view, &rec);
8392     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8393     check_record(rec, 3, "T", "4", "C");
8394     MsiCloseHandle(rec);
8395 
8396     r = MsiViewFetch(view, &rec);
8397     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8398     check_record(rec, 3, "T", "5", "B");
8399     MsiCloseHandle(rec);
8400 
8401     r = MsiViewFetch(view, &rec);
8402     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
8403 
8404     MsiViewClose(view);
8405     MsiCloseHandle(view);
8406 
8407     query = "CREATE TABLE `Z` ( `B` SHORT NOT NULL, `C` SHORT NOT NULL, "
8408             "`A` CHAR(255), `E` INT, `D` CHAR(255) NOT NULL "
8409             "PRIMARY KEY `C`, `A`, `D`)";
8410     r = run_query(hdb, 0, query);
8411     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8412 
8413     query = "SELECT * FROM `Z`";
8414     r = MsiDatabaseOpenViewA(hdb, query, &view);
8415     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8416 
8417     r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
8418     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8419     check_record(rec, 5, "i2", "S255", "s255", "I2", "i2");
8420     MsiCloseHandle(rec);
8421 
8422     r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec);
8423     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8424     check_record(rec, 5, "C", "A", "D", "E", "B");
8425     MsiCloseHandle(rec);
8426 
8427     MsiViewClose(view);
8428     MsiCloseHandle(view);
8429 
8430     query = "INSERT INTO `Z` ( `B`, `C`, `A`, `E`, `D` ) "
8431             "VALUES ( 1, 2, 'a', 3, 'bc' )";
8432     r = run_query(hdb, 0, query);
8433     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8434 
8435     query = "SELECT * FROM `Z`";
8436     r = do_query(hdb, query, &rec);
8437     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8438     check_record(rec, 5, "2", "a", "bc", "3", "1");
8439     MsiCloseHandle(rec);
8440 
8441     query = "SELECT `Table`, `Number`, `Name` FROM `_Columns` WHERE `Table` = 'T'";
8442     r = MsiDatabaseOpenViewA(hdb, query, &view);
8443     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8444     r = MsiViewExecute(view, 0);
8445     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8446 
8447     r = MsiViewFetch(view, &rec);
8448     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8449     check_record(rec, 3, "T", "1", "D");
8450     MsiCloseHandle(rec);
8451 
8452     r = MsiViewFetch(view, &rec);
8453     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8454     check_record(rec, 3, "T", "2", "E");
8455     MsiCloseHandle(rec);
8456 
8457     r = MsiViewFetch(view, &rec);
8458     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8459     check_record(rec, 3, "T", "3", "A");
8460     MsiCloseHandle(rec);
8461 
8462     r = MsiViewFetch(view, &rec);
8463     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8464     check_record(rec, 3, "T", "4", "C");
8465     MsiCloseHandle(rec);
8466 
8467     r = MsiViewFetch(view, &rec);
8468     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
8469     check_record(rec, 3, "T", "5", "B");
8470     MsiCloseHandle(rec);
8471 
8472     r = MsiViewFetch(view, &rec);
8473     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
8474 
8475     MsiViewClose(view);
8476     MsiCloseHandle(view);
8477 
8478     MsiCloseHandle(hdb);
8479     DeleteFileA(msifile);
8480 }
8481 
8482 static void test_createtable(void)
8483 {
8484     MSIHANDLE hdb, htab = 0, hrec = 0;
8485     LPCSTR query;
8486     UINT res;
8487     DWORD size;
8488     char buffer[0x20];
8489 
8490     hdb = create_db();
8491     ok(hdb, "failed to create db\n");
8492 
8493     query = "CREATE TABLE `blah` (`foo` CHAR(72) NOT NULL PRIMARY KEY `foo`)";
8494     res = MsiDatabaseOpenViewA( hdb, query, &htab );
8495     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
8496     if(res == ERROR_SUCCESS )
8497     {
8498         res = MsiViewExecute( htab, hrec );
8499         ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
8500 
8501         res = MsiViewGetColumnInfo( htab, MSICOLINFO_NAMES, &hrec );
8502         todo_wine ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
8503 
8504         size = sizeof(buffer);
8505         res = MsiRecordGetStringA(hrec, 1, buffer, &size );
8506         todo_wine ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
8507         MsiCloseHandle( hrec );
8508 
8509         res = MsiViewClose( htab );
8510         ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
8511 
8512         res = MsiCloseHandle( htab );
8513         ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
8514     }
8515 
8516     query = "CREATE TABLE `a` (`b` INT PRIMARY KEY `b`)";
8517     res = MsiDatabaseOpenViewA( hdb, query, &htab );
8518     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
8519     if(res == ERROR_SUCCESS )
8520     {
8521         res = MsiViewExecute( htab, 0 );
8522         ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
8523 
8524         res = MsiViewClose( htab );
8525         ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
8526 
8527         res = MsiCloseHandle( htab );
8528         ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
8529 
8530         query = "SELECT * FROM `a`";
8531         res = MsiDatabaseOpenViewA( hdb, query, &htab );
8532         ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
8533 
8534         res = MsiViewGetColumnInfo( htab, MSICOLINFO_NAMES, &hrec );
8535         ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
8536         check_record(hrec, 1, "b");
8537         MsiCloseHandle( hrec );
8538 
8539         res = MsiViewClose( htab );
8540         ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
8541 
8542         res = MsiCloseHandle( htab );
8543         ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
8544 
8545         res = MsiDatabaseCommit(hdb);
8546         ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
8547 
8548         res = MsiCloseHandle(hdb);
8549         ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
8550 
8551         res = MsiOpenDatabaseW(msifileW, MSIDBOPEN_TRANSACT, &hdb );
8552         ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
8553 
8554         query = "SELECT * FROM `a`";
8555         res = MsiDatabaseOpenViewA( hdb, query, &htab );
8556         ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
8557 
8558         res = MsiViewGetColumnInfo( htab, MSICOLINFO_NAMES, &hrec );
8559         ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
8560         check_record(hrec, 1, "b");
8561         res = MsiCloseHandle( hrec );
8562         ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
8563 
8564         res = MsiViewClose( htab );
8565         ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
8566 
8567         res = MsiCloseHandle( htab );
8568         ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
8569     }
8570 
8571     res = MsiDatabaseCommit(hdb);
8572     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
8573 
8574     res = MsiCloseHandle(hdb);
8575     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
8576 
8577     DeleteFileA(msifile);
8578 }
8579 
8580 static void test_embedded_nulls(void)
8581 {
8582     static const char control_table[] =
8583         "Dialog\tText\n"
8584         "s72\tL0\n"
8585         "Control\tDialog\n"
8586         "LicenseAgreementDlg\ttext\x11\x19text\0text";
8587     UINT r;
8588     DWORD sz;
8589     MSIHANDLE hdb, hrec;
8590     char buffer[32];
8591 
8592     r = MsiOpenDatabaseW( msifileW, MSIDBOPEN_CREATE, &hdb );
8593     ok( r == ERROR_SUCCESS, "failed to open database %u\n", r );
8594 
8595     GetCurrentDirectoryA( MAX_PATH, CURR_DIR );
8596     write_file( "temp_file", control_table, sizeof(control_table) );
8597     r = MsiDatabaseImportA( hdb, CURR_DIR, "temp_file" );
8598     ok( r == ERROR_SUCCESS, "failed to import table %u\n", r );
8599     DeleteFileA( "temp_file" );
8600 
8601     r = do_query( hdb, "SELECT `Text` FROM `Control` WHERE `Dialog` = 'LicenseAgreementDlg'", &hrec );
8602     ok( r == ERROR_SUCCESS, "query failed %u\n", r );
8603 
8604     buffer[0] = 0;
8605     sz = sizeof(buffer);
8606     r = MsiRecordGetStringA( hrec, 1, buffer, &sz );
8607     ok( r == ERROR_SUCCESS, "failed to get string %u\n", r );
8608     ok( !memcmp( "text\r\ntext\ntext", buffer, sizeof("text\r\ntext\ntext") - 1 ), "wrong buffer contents \"%s\"\n", buffer );
8609 
8610     MsiCloseHandle( hrec );
8611     MsiCloseHandle( hdb );
8612     DeleteFileA( msifile );
8613 }
8614 
8615 static void test_select_column_names(void)
8616 {
8617     MSIHANDLE hdb = 0, rec, view;
8618     UINT r;
8619 
8620     DeleteFileA(msifile);
8621 
8622     r = MsiOpenDatabaseW( msifileW, MSIDBOPEN_CREATE, &hdb );
8623     ok( r == ERROR_SUCCESS , "failed to open database: %u\n", r );
8624 
8625     r = try_query( hdb, "CREATE TABLE `t` (`a` CHAR NOT NULL, `b` CHAR PRIMARY KEY `a`)");
8626     ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
8627 
8628     r = try_query( hdb, "SELECT `t`.`b` FROM `t` WHERE `t`.`b` = `x`" );
8629     ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %u\n", r );
8630 
8631     r = try_query( hdb, "SELECT '', `t`.`b` FROM `t` WHERE `t`.`b` = 'x'" );
8632     ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
8633 
8634     r = try_query( hdb, "SELECT *, `t`.`b` FROM `t` WHERE `t`.`b` = 'x'" );
8635     todo_wine ok( r == ERROR_SUCCESS, "query failed: %u\n", r );
8636 
8637     r = try_query( hdb, "SELECT 'b', `t`.`b` FROM `t` WHERE `t`.`b` = 'x'" );
8638     ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
8639 
8640     r = try_query( hdb, "SELECT `t`.`b`, '' FROM `t` WHERE `t`.`b` = 'x'" );
8641     ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
8642 
8643     r = try_query( hdb, "SELECT `t`.`b`, '' FROM `t` WHERE `t`.`b` = 'x' ORDER BY `b`" );
8644     ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
8645 
8646     r = try_query( hdb, "SELECT `t`.`b`, '' FROM `t` WHERE `t`.`b` = 'x' ORDER BY 'b'" );
8647     ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %u\n", r );
8648 
8649     r = try_query( hdb, "SELECT 't'.'b' FROM `t` WHERE `t`.`b` = 'x'" );
8650     ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %u\n", r );
8651 
8652     r = try_query( hdb, "SELECT 'b' FROM `t` WHERE `t`.`b` = 'x'" );
8653     ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
8654 
8655     r = try_query( hdb, "INSERT INTO `t` ( `a`, `b` ) VALUES( '1', '2' )" );
8656     ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
8657 
8658     r = try_query( hdb, "INSERT INTO `t` ( `a`, `b` ) VALUES( '3', '4' )" );
8659     ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
8660 
8661     r = MsiDatabaseOpenViewA( hdb, "SELECT '' FROM `t`", &view );
8662     ok( r == ERROR_SUCCESS, "failed to open database view: %u\n", r );
8663 
8664     r = MsiViewExecute( view, 0 );
8665     ok( r == ERROR_SUCCESS, "failed to execute view: %u\n", r );
8666 
8667     r = MsiViewFetch( view, &rec );
8668     ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r );
8669     check_record(rec, 1, "");
8670     MsiCloseHandle(rec);
8671 
8672     r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec);
8673     ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r );
8674     check_record(rec, 1, "");
8675     MsiCloseHandle(rec);
8676 
8677     r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
8678     ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r );
8679     check_record(rec, 1, "f0");
8680     MsiCloseHandle(rec);
8681 
8682     r = MsiViewFetch( view, &rec );
8683     ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r );
8684     check_record(rec, 1, "");
8685     MsiCloseHandle( rec );
8686 
8687     r = MsiViewFetch( view, &rec );
8688     ok( r == ERROR_NO_MORE_ITEMS, "unexpected result: %u\n", r );
8689     MsiCloseHandle( rec );
8690 
8691     MsiViewClose( view );
8692     MsiCloseHandle( view );
8693 
8694     r = MsiDatabaseOpenViewA( hdb, "SELECT `a`, '' FROM `t`", &view );
8695     ok( r == ERROR_SUCCESS, "failed to open database view: %u\n", r );
8696 
8697     r = MsiViewExecute( view, 0 );
8698     ok( r == ERROR_SUCCESS, "failed to execute view: %u\n", r );
8699 
8700     r = MsiViewFetch( view, &rec );
8701     ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r );
8702     check_record(rec, 2, "1", "");
8703     MsiCloseHandle( rec );
8704 
8705     r = MsiViewFetch( view, &rec );
8706     ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r );
8707     check_record(rec, 2, "3", "");
8708     MsiCloseHandle( rec );
8709 
8710     r = MsiViewFetch( view, &rec );
8711     ok( r == ERROR_NO_MORE_ITEMS, "unexpected result: %u\n", r );
8712     MsiCloseHandle( rec );
8713 
8714     MsiViewClose( view );
8715     MsiCloseHandle( view );
8716 
8717     r = MsiDatabaseOpenViewA( hdb, "SELECT '', `a` FROM `t`", &view );
8718     ok( r == ERROR_SUCCESS, "failed to open database view: %u\n", r );
8719 
8720     r = MsiViewExecute( view, 0 );
8721     ok( r == ERROR_SUCCESS, "failed to execute view: %u\n", r );
8722 
8723     r = MsiViewFetch( view, &rec );
8724     ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r );
8725     check_record(rec, 2, "", "1");
8726     MsiCloseHandle( rec );
8727 
8728     r = MsiViewFetch( view, &rec );
8729     ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r );
8730     check_record(rec, 2, "", "3");
8731     MsiCloseHandle( rec );
8732 
8733     r = MsiViewFetch( view, &rec );
8734     ok( r == ERROR_NO_MORE_ITEMS, "unexpected result: %u\n", r );
8735     MsiCloseHandle( rec );
8736 
8737     MsiViewClose( view );
8738     MsiCloseHandle( view );
8739 
8740     r = MsiDatabaseOpenViewA( hdb, "SELECT `a`, '', `b` FROM `t`", &view );
8741     ok( r == ERROR_SUCCESS, "failed to open database view: %u\n", r );
8742 
8743     r = MsiViewExecute( view, 0 );
8744     ok( r == ERROR_SUCCESS, "failed to execute view: %u\n", r );
8745 
8746     r = MsiViewFetch( view, &rec );
8747     ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r );
8748     check_record(rec, 3, "1", "", "2");
8749     MsiCloseHandle( rec );
8750 
8751     r = MsiViewFetch( view, &rec );
8752     ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r );
8753     check_record(rec, 3, "3", "", "4");
8754     MsiCloseHandle( rec );
8755 
8756     r = MsiViewFetch( view, &rec );
8757     ok( r == ERROR_NO_MORE_ITEMS, "unexpected result: %u\n", r );
8758     MsiCloseHandle( rec );
8759 
8760     MsiViewClose( view );
8761     MsiCloseHandle( view );
8762 
8763     r = try_query( hdb, "SELECT '' FROM `t` WHERE `t`.`b` = 'x'" );
8764     ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
8765 
8766     r = try_query( hdb, "SELECT `` FROM `t` WHERE `t`.`b` = 'x'" );
8767     todo_wine ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %u\n", r );
8768 
8769     r = try_query( hdb, "SELECT `b` FROM 't' WHERE `t`.`b` = 'x'" );
8770     ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %u\n", r );
8771 
8772     r = try_query( hdb, "SELECT `b` FROM `t` WHERE 'b' = 'x'" );
8773     ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %u\n", r );
8774 
8775     r = try_query( hdb, "SELECT `t`.`b`, `` FROM `t` WHERE `t`.`b` = 'x'" );
8776     todo_wine ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %u\n", r );
8777 
8778     r = MsiCloseHandle( hdb );
8779     ok(r == ERROR_SUCCESS , "failed to close database: %u\n", r);
8780 }
8781 
8782 static void test_primary_keys(void)
8783 {
8784     MSIHANDLE hdb, keys;
8785     char buffer[5];
8786     DWORD size;
8787     UINT r;
8788 
8789     hdb = create_db();
8790 
8791     r = MsiDatabaseGetPrimaryKeysA(hdb, "T", &keys);
8792     ok(r == ERROR_INVALID_TABLE, "got %u\n", r);
8793 
8794     r = run_query(hdb, 0, "CREATE TABLE `T` (`A` SHORT, `B` SHORT, `C` SHORT PRIMARY KEY `A`)");
8795     ok(!r, "got %u\n", r);
8796 
8797     r = MsiDatabaseGetPrimaryKeysA(hdb, "T", &keys);
8798     ok(!r, "got %u\n", r);
8799     check_record(keys, 1, "A");
8800     size = sizeof(buffer);
8801     r = MsiRecordGetStringA(keys, 0, buffer, &size);
8802     ok(!r, "got %u\n", r);
8803     ok(!strcmp(buffer, "T"), "got \"%s\"\n", buffer);
8804     MsiCloseHandle(keys);
8805 
8806     r = run_query(hdb, 0, "CREATE TABLE `U` (`A` SHORT, `B` SHORT, `C` SHORT PRIMARY KEY `B`, `C`)");
8807     ok(!r, "got %u\n", r);
8808 
8809     r = MsiDatabaseGetPrimaryKeysA(hdb, "U", &keys);
8810     ok(!r, "got %u\n", r);
8811     check_record(keys, 2, "B", "C");
8812     size = sizeof(buffer);
8813     r = MsiRecordGetStringA(keys, 0, buffer, &size);
8814     ok(!r, "got %u\n", r);
8815     ok(!strcmp(buffer, "U"), "got \"%s\"\n", buffer);
8816     MsiCloseHandle(keys);
8817     MsiCloseHandle(hdb);
8818     DeleteFileA(msifile);
8819 }
8820 
8821 static void test_viewmodify_merge(void)
8822 {
8823     MSIHANDLE view, rec, db = create_db();
8824     UINT r;
8825 
8826     r = run_query(db, 0, "CREATE TABLE `T` (`A` SHORT, `B` SHORT PRIMARY KEY `A`)");
8827     ok(!r, "got %u\n", r);
8828     r = run_query(db, 0, "INSERT INTO `T` (`A`, `B`) VALUES (1, 2)");
8829     ok(!r, "got %u\n", r);
8830 
8831     r = MsiDatabaseOpenViewA(db, "SELECT * FROM `T`", &view);
8832     ok(!r, "got %u\n", r);
8833     r = MsiViewExecute(view, 0);
8834     ok(!r, "got %u\n", r);
8835 
8836     rec = MsiCreateRecord(2);
8837     MsiRecordSetInteger(rec, 1, 1);
8838     MsiRecordSetInteger(rec, 2, 2);
8839     r = MsiViewModify(view, MSIMODIFY_MERGE, rec);
8840     ok(!r, "got %u\n", r);
8841 
8842     MsiCloseHandle(rec);
8843     MsiCloseHandle(view);
8844 
8845     r = MsiDatabaseOpenViewA(db, "SELECT * FROM `T`", &view);
8846     ok(!r, "got %u\n", r);
8847     r = MsiViewExecute(view, 0);
8848     ok(!r, "got %u\n", r);
8849 
8850     r = MsiViewFetch(view, &rec);
8851     ok(!r, "got %u\n", r);
8852     check_record(rec, 2, "1", "2");
8853     MsiCloseHandle(rec);
8854 
8855     r = MsiViewFetch(view, &rec);
8856     ok(r == ERROR_NO_MORE_ITEMS, "got %u\n", r);
8857     MsiCloseHandle(view);
8858 
8859     r = MsiDatabaseOpenViewA(db, "SELECT * FROM `T`", &view);
8860     ok(!r, "got %u\n", r);
8861     r = MsiViewExecute(view, 0);
8862     ok(!r, "got %u\n", r);
8863 
8864     rec = MsiCreateRecord(2);
8865     MsiRecordSetInteger(rec, 1, 1);
8866     MsiRecordSetInteger(rec, 2, 3);
8867     r = MsiViewModify(view, MSIMODIFY_MERGE, rec);
8868     todo_wine
8869     ok(r == ERROR_FUNCTION_FAILED, "got %u\n", r);
8870 
8871     MsiRecordSetInteger(rec, 1, 2);
8872     r = MsiViewModify(view, MSIMODIFY_MERGE, rec);
8873     ok(!r, "got %u\n", r);
8874 
8875     MsiCloseHandle(rec);
8876     MsiCloseHandle(view);
8877 
8878     r = MsiDatabaseOpenViewA(db, "SELECT * FROM `T`", &view);
8879     ok(!r, "got %u\n", r);
8880     r = MsiViewExecute(view, 0);
8881     ok(!r, "got %u\n", r);
8882 
8883     r = MsiViewFetch(view, &rec);
8884     ok(!r, "got %u\n", r);
8885     check_record(rec, 2, "1", "2");
8886     MsiCloseHandle(rec);
8887 
8888     r = MsiViewFetch(view, &rec);
8889     ok(!r, "got %u\n", r);
8890     check_record(rec, 2, "2", "3");
8891     MsiCloseHandle(rec);
8892 
8893     r = MsiViewFetch(view, &rec);
8894     ok(r == ERROR_NO_MORE_ITEMS, "got %u\n", r);
8895     MsiCloseHandle(view);
8896 
8897     r = run_query(db, 0, "CREATE TABLE `U` (`A` SHORT, `B` SHORT, `C` SHORT, `D` SHORT PRIMARY KEY `A`, `B`)");
8898     ok(!r, "got %u\n", r);
8899     r = run_query(db, 0, "INSERT INTO `U` (`A`, `B`, `C`, `D`) VALUES (1, 2, 3, 4)");
8900     ok(!r, "got %u\n", r);
8901 
8902     r = MsiDatabaseOpenViewA(db, "SELECT * FROM `U`", &view);
8903     ok(!r, "got %u\n", r);
8904     r = MsiViewExecute(view, 0);
8905     ok(!r, "got %u\n", r);
8906 
8907     rec = MsiCreateRecord(4);
8908     MsiRecordSetInteger(rec, 1, 1);
8909     MsiRecordSetInteger(rec, 2, 2);
8910     MsiRecordSetInteger(rec, 3, 3);
8911     MsiRecordSetInteger(rec, 4, 4);
8912     r = MsiViewModify(view, MSIMODIFY_MERGE, rec);
8913     ok(!r, "got %u\n", r);
8914 
8915     MsiRecordSetInteger(rec, 3, 4);
8916     r = MsiViewModify(view, MSIMODIFY_MERGE, rec);
8917     todo_wine
8918     ok(r == ERROR_FUNCTION_FAILED, "got %u\n", r);
8919 
8920     MsiRecordSetInteger(rec, 2, 4);
8921     r = MsiViewModify(view, MSIMODIFY_MERGE, rec);
8922     ok(!r, "got %u\n", r);
8923 
8924     MsiCloseHandle(rec);
8925     MsiCloseHandle(view);
8926 
8927     r = MsiDatabaseOpenViewA(db, "SELECT * FROM `U`", &view);
8928     ok(!r, "got %u\n", r);
8929     r = MsiViewExecute(view, 0);
8930     ok(!r, "got %u\n", r);
8931 
8932     r = MsiViewFetch(view, &rec);
8933     ok(!r, "got %u\n", r);
8934     check_record(rec, 4, "1", "2", "3", "4");
8935     MsiCloseHandle(rec);
8936 
8937     r = MsiViewFetch(view, &rec);
8938     ok(!r, "got %u\n", r);
8939     check_record(rec, 4, "1", "4", "4", "4");
8940     MsiCloseHandle(rec);
8941 
8942     r = MsiViewFetch(view, &rec);
8943     ok(r == ERROR_NO_MORE_ITEMS, "got %u\n", r);
8944     MsiCloseHandle(view);
8945 
8946     r = MsiDatabaseOpenViewA(db, "SELECT `A`,`C` FROM `U`", &view);
8947     ok(!r, "got %u\n", r);
8948     r = MsiViewExecute(view, 0);
8949     ok(!r, "got %u\n", r);
8950 
8951     rec = MsiCreateRecord(2);
8952     MsiRecordSetInteger(rec, 1, 1);
8953     MsiRecordSetInteger(rec, 2, 2);
8954     r = MsiViewModify(view, MSIMODIFY_MERGE, rec);
8955     ok(!r, "got %u\n", r);
8956 
8957     r = MsiViewModify(view, MSIMODIFY_MERGE, rec);
8958     ok(!r, "got %u\n", r);
8959 
8960     MsiRecordSetInteger(rec, 2, 3);
8961     r = MsiViewModify(view, MSIMODIFY_MERGE, rec);
8962     todo_wine
8963     ok(r == ERROR_FUNCTION_FAILED, "got %u\n", r);
8964 
8965     MsiCloseHandle(rec);
8966     MsiCloseHandle(view);
8967 
8968     r = MsiDatabaseOpenViewA(db, "SELECT * FROM `U` ORDER BY `B`", &view);
8969     ok(!r, "got %u\n", r);
8970     r = MsiViewExecute(view, 0);
8971     ok(!r, "got %u\n", r);
8972 
8973     r = MsiViewFetch(view, &rec);
8974     ok(!r, "got %u\n", r);
8975     check_record(rec, 4, "1", "", "2", "");
8976     MsiCloseHandle(rec);
8977 
8978     r = MsiViewFetch(view, &rec);
8979     ok(!r, "got %u\n", r);
8980     check_record(rec, 4, "1", "2", "3", "4");
8981     MsiCloseHandle(rec);
8982 
8983     r = MsiViewFetch(view, &rec);
8984     ok(!r, "got %u\n", r);
8985     check_record(rec, 4, "1", "4", "4", "4");
8986     MsiCloseHandle(rec);
8987 
8988     r = MsiViewFetch(view, &rec);
8989     ok(r == ERROR_NO_MORE_ITEMS, "got %u\n", r);
8990     MsiCloseHandle(view);
8991 
8992     r = MsiDatabaseOpenViewA(db, "SELECT `A`,`B`,`C` FROM `U`", &view);
8993     ok(!r, "got %u\n", r);
8994     r = MsiViewExecute(view, 0);
8995     ok(!r, "got %u\n", r);
8996 
8997     rec = MsiCreateRecord(3);
8998     MsiRecordSetInteger(rec, 1, 1);
8999     MsiRecordSetInteger(rec, 2, 2);
9000     MsiRecordSetInteger(rec, 3, 3);
9001     r = MsiViewModify(view, MSIMODIFY_MERGE, rec);
9002     todo_wine
9003     ok(r == ERROR_FUNCTION_FAILED, "got %u\n", r);
9004 
9005     MsiRecordSetInteger(rec, 1, 1);
9006     MsiRecordSetInteger(rec, 2, MSI_NULL_INTEGER);
9007     MsiRecordSetInteger(rec, 3, 2);
9008     r = MsiViewModify(view, MSIMODIFY_MERGE, rec);
9009     ok(!r, "got %u\n", r);
9010 
9011     MsiCloseHandle(rec);
9012     MsiCloseHandle(view);
9013 
9014     MsiCloseHandle(db);
9015     DeleteFileA(msifile);
9016 }
9017 
9018 static void test_viewmodify_insert(void)
9019 {
9020     MSIHANDLE view, rec, db = create_db();
9021     UINT r;
9022 
9023     r = run_query(db, 0, "CREATE TABLE `T` (`A` SHORT, `B` SHORT PRIMARY KEY `A`)");
9024     ok(!r, "got %u\n", r);
9025 
9026     r = MsiDatabaseOpenViewA(db, "SELECT * FROM `T`", &view);
9027     ok(!r, "got %u\n", r);
9028     r = MsiViewExecute(view, 0);
9029     ok(!r, "got %u\n", r);
9030 
9031     rec = MsiCreateRecord(2);
9032     MsiRecordSetInteger(rec, 1, 1);
9033     MsiRecordSetInteger(rec, 2, 2);
9034     r = MsiViewModify(view, MSIMODIFY_INSERT, rec);
9035     ok(!r, "got %u\n", r);
9036 
9037     MsiCloseHandle(rec);
9038     MsiCloseHandle(view);
9039 
9040     r = MsiDatabaseOpenViewA(db, "SELECT * FROM `T`", &view);
9041     ok(!r, "got %u\n", r);
9042     r = MsiViewExecute(view, 0);
9043     ok(!r, "got %u\n", r);
9044 
9045     r = MsiViewFetch(view, &rec);
9046     ok(!r, "got %u\n", r);
9047     check_record(rec, 2, "1", "2");
9048     MsiCloseHandle(rec);
9049 
9050     r = MsiViewFetch(view, &rec);
9051     ok(r == ERROR_NO_MORE_ITEMS, "got %u\n", r);
9052     MsiCloseHandle(view);
9053 
9054     r = MsiDatabaseOpenViewA(db, "SELECT * FROM `T`", &view);
9055     ok(!r, "got %u\n", r);
9056     r = MsiViewExecute(view, 0);
9057     ok(!r, "got %u\n", r);
9058 
9059     rec = MsiCreateRecord(2);
9060     MsiRecordSetInteger(rec, 1, 1);
9061     MsiRecordSetInteger(rec, 2, 2);
9062     r = MsiViewModify(view, MSIMODIFY_INSERT, rec);
9063     ok(r == ERROR_FUNCTION_FAILED, "got %u\n", r);
9064 
9065     MsiRecordSetInteger(rec, 2, 3);
9066     r = MsiViewModify(view, MSIMODIFY_INSERT, rec);
9067     ok(r == ERROR_FUNCTION_FAILED, "got %u\n", r);
9068 
9069     MsiRecordSetInteger(rec, 1, 3);
9070     r = MsiViewModify(view, MSIMODIFY_INSERT, rec);
9071     ok(!r, "got %u\n", r);
9072 
9073     MsiCloseHandle(rec);
9074     MsiCloseHandle(view);
9075 
9076     r = MsiDatabaseOpenViewA(db, "SELECT * FROM `T`", &view);
9077     ok(!r, "got %u\n", r);
9078     r = MsiViewExecute(view, 0);
9079     ok(!r, "got %u\n", r);
9080 
9081     r = MsiViewFetch(view, &rec);
9082     ok(!r, "got %u\n", r);
9083     check_record(rec, 2, "1", "2");
9084     MsiCloseHandle(rec);
9085 
9086     r = MsiViewFetch(view, &rec);
9087     ok(!r, "got %u\n", r);
9088     check_record(rec, 2, "3", "3");
9089     MsiCloseHandle(rec);
9090 
9091     r = MsiViewFetch(view, &rec);
9092     ok(r == ERROR_NO_MORE_ITEMS, "got %u\n", r);
9093     MsiCloseHandle(view);
9094 
9095     r = run_query(db, 0, "CREATE TABLE `U` (`A` SHORT, `B` SHORT, `C` SHORT, `D` SHORT PRIMARY KEY `A`, `B`)");
9096     ok(!r, "got %u\n", r);
9097 
9098     r = MsiDatabaseOpenViewA(db, "SELECT * FROM `U`", &view);
9099     ok(!r, "got %u\n", r);
9100     r = MsiViewExecute(view, 0);
9101     ok(!r, "got %u\n", r);
9102 
9103     rec = MsiCreateRecord(4);
9104     MsiRecordSetInteger(rec, 1, 1);
9105     MsiRecordSetInteger(rec, 2, 2);
9106     MsiRecordSetInteger(rec, 3, 3);
9107     MsiRecordSetInteger(rec, 4, 4);
9108     r = MsiViewModify(view, MSIMODIFY_INSERT, rec);
9109     ok(!r, "got %u\n", r);
9110 
9111     MsiRecordSetInteger(rec, 2, 4);
9112     r = MsiViewModify(view, MSIMODIFY_INSERT, rec);
9113     ok(!r, "got %u\n", r);
9114 
9115     MsiCloseHandle(rec);
9116     MsiCloseHandle(view);
9117 
9118     r = MsiDatabaseOpenViewA(db, "SELECT * FROM `U`", &view);
9119     ok(!r, "got %u\n", r);
9120     r = MsiViewExecute(view, 0);
9121     ok(!r, "got %u\n", r);
9122 
9123     r = MsiViewFetch(view, &rec);
9124     ok(!r, "got %u\n", r);
9125     check_record(rec, 4, "1", "2", "3", "4");
9126     MsiCloseHandle(rec);
9127 
9128     r = MsiViewFetch(view, &rec);
9129     ok(!r, "got %u\n", r);
9130     check_record(rec, 4, "1", "4", "3", "4");
9131     MsiCloseHandle(rec);
9132 
9133     r = MsiViewFetch(view, &rec);
9134     ok(r == ERROR_NO_MORE_ITEMS, "got %u\n", r);
9135     MsiCloseHandle(view);
9136 
9137     r = MsiDatabaseOpenViewA(db, "SELECT `A`,`C` FROM `U`", &view);
9138     ok(!r, "got %u\n", r);
9139     r = MsiViewExecute(view, 0);
9140     ok(!r, "got %u\n", r);
9141 
9142     rec = MsiCreateRecord(2);
9143     MsiRecordSetInteger(rec, 1, 1);
9144     MsiRecordSetInteger(rec, 2, 2);
9145     r = MsiViewModify(view, MSIMODIFY_INSERT, rec);
9146     ok(!r, "got %u\n", r);
9147 
9148     r = MsiViewModify(view, MSIMODIFY_INSERT, rec);
9149     ok(r == ERROR_FUNCTION_FAILED, "got %u\n", r);
9150 
9151     MsiCloseHandle(rec);
9152     MsiCloseHandle(view);
9153 
9154     r = MsiDatabaseOpenViewA(db, "SELECT * FROM `U` ORDER BY `B`", &view);
9155     ok(!r, "got %u\n", r);
9156     r = MsiViewExecute(view, 0);
9157     ok(!r, "got %u\n", r);
9158 
9159     r = MsiViewFetch(view, &rec);
9160     ok(!r, "got %u\n", r);
9161     check_record(rec, 4, "1", "", "2", "");
9162     MsiCloseHandle(rec);
9163 
9164     r = MsiViewFetch(view, &rec);
9165     ok(!r, "got %u\n", r);
9166     check_record(rec, 4, "1", "2", "3", "4");
9167     MsiCloseHandle(rec);
9168 
9169     r = MsiViewFetch(view, &rec);
9170     ok(!r, "got %u\n", r);
9171     check_record(rec, 4, "1", "4", "3", "4");
9172     MsiCloseHandle(rec);
9173 
9174     r = MsiViewFetch(view, &rec);
9175     ok(r == ERROR_NO_MORE_ITEMS, "got %u\n", r);
9176     MsiCloseHandle(view);
9177 
9178     MsiCloseHandle(db);
9179     DeleteFileA(msifile);
9180 }
9181 
9182 static void test_view_get_error(void)
9183 {
9184     MSIHANDLE view, rec, db = create_db();
9185     MSIDBERROR err;
9186     char buffer[5];
9187     DWORD sz;
9188     UINT r;
9189 
9190     r = run_query(db, 0, "CREATE TABLE `T` (`A` SHORT, `B` SHORT NOT NULL PRIMARY KEY `A`)");
9191     ok(!r, "got %u\n", r);
9192     r = run_query(db, 0, "INSERT INTO `T` (`A`, `B`) VALUES (1, 2)");
9193     r = run_query(db, 0, "CREATE TABLE `_Validation` ("
9194             "`Table` CHAR(32) NOT NULL, `Column` CHAR(32) NOT NULL, "
9195             "`Nullable` CHAR(4) NOT NULL, `MinValue` INT, `MaxValue` INT, "
9196             "`KeyTable` CHAR(255), `KeyColumn` SHORT, `Category` CHAR(32), "
9197             "`Set` CHAR(255), `Description` CHAR(255) PRIMARY KEY `Table`, `Column`)");
9198     ok(!r, "got %u\n", r);
9199     r = run_query(db, 0, "INSERT INTO `_Validation` (`Table`, `Column`, `Nullable`) VALUES ('T', 'A', 'N')");
9200     ok(!r, "got %u\n", r);
9201     r = run_query(db, 0, "INSERT INTO `_Validation` (`Table`, `Column`, `Nullable`) VALUES ('T', 'B', 'N')");
9202     ok(!r, "got %u\n", r);
9203 
9204     r = MsiDatabaseOpenViewA(db, "SELECT * FROM `T`", &view);
9205     ok(!r, "got %u\n", r);
9206 
9207     r = MsiViewExecute(view, 0);
9208     ok(!r, "got %u\n", r);
9209 
9210     sz = 0;
9211     err = MsiViewGetErrorA(0, NULL, &sz);
9212     ok(err == MSIDBERROR_INVALIDARG, "got %d\n", err);
9213     ok(sz == 0, "got size %lu\n", sz);
9214 
9215     err = MsiViewGetErrorA(view, NULL, NULL);
9216     ok(err == MSIDBERROR_INVALIDARG, "got %d\n", err);
9217 
9218     sz = 0;
9219     err = MsiViewGetErrorA(view, NULL, &sz);
9220     ok(err == MSIDBERROR_NOERROR, "got %d\n", err);
9221     ok(sz == 0, "got size %lu\n", sz);
9222 
9223     sz = 0;
9224     strcpy(buffer, "x");
9225     err = MsiViewGetErrorA(view, buffer, &sz);
9226     ok(err == MSIDBERROR_MOREDATA, "got %d\n", err);
9227     ok(!strcmp(buffer, "x"), "got \"%s\"\n", buffer);
9228     ok(sz == 0, "got size %lu\n", sz);
9229 
9230     sz = 1;
9231     strcpy(buffer, "x");
9232     err = MsiViewGetErrorA(view, buffer, &sz);
9233     ok(err == MSIDBERROR_NOERROR, "got %d\n", err);
9234     ok(!buffer[0], "got \"%s\"\n", buffer);
9235     ok(sz == 0, "got size %lu\n", sz);
9236 
9237     rec = MsiCreateRecord(2);
9238     MsiRecordSetInteger(rec, 1, 1);
9239     MsiRecordSetInteger(rec, 2, 2);
9240     r = MsiViewModify(view, MSIMODIFY_VALIDATE_NEW, rec);
9241     ok(r == ERROR_INVALID_DATA, "got %u\n", r);
9242 
9243     sz = 2;
9244     strcpy(buffer, "x");
9245     err = MsiViewGetErrorA(view, buffer, &sz);
9246     ok(err == MSIDBERROR_DUPLICATEKEY, "got %d\n", err);
9247     ok(!strcmp(buffer, "A"), "got \"%s\"\n", buffer);
9248     ok(sz == 1, "got size %lu\n", sz);
9249 
9250     sz = 2;
9251     strcpy(buffer, "x");
9252     err = MsiViewGetErrorA(view, buffer, &sz);
9253     todo_wine ok(err == MSIDBERROR_NOERROR, "got %d\n", err);
9254     todo_wine ok(!buffer[0], "got \"%s\"\n", buffer);
9255     todo_wine ok(sz == 0, "got size %lu\n", sz);
9256 
9257     r = MsiViewModify(view, MSIMODIFY_VALIDATE_NEW, rec);
9258     ok(r == ERROR_INVALID_DATA, "got %u\n", r);
9259 
9260     sz = 1;
9261     strcpy(buffer, "x");
9262     err = MsiViewGetErrorA(view, buffer, &sz);
9263     ok(err == MSIDBERROR_MOREDATA, "got %d\n", err);
9264     ok(!buffer[0], "got \"%s\"\n", buffer);
9265     ok(sz == 1, "got size %lu\n", sz);
9266 
9267     sz = 1;
9268     strcpy(buffer, "x");
9269     err = MsiViewGetErrorA(view, buffer, &sz);
9270     todo_wine ok(err == MSIDBERROR_NOERROR, "got %d\n", err);
9271     ok(!buffer[0], "got \"%s\"\n", buffer);
9272     todo_wine ok(sz == 0, "got size %lu\n", sz);
9273 
9274     r = MsiViewModify(view, MSIMODIFY_VALIDATE_NEW, rec);
9275     ok(r == ERROR_INVALID_DATA, "got %u\n", r);
9276 
9277     sz = 0;
9278     strcpy(buffer, "x");
9279     err = MsiViewGetErrorA(view, buffer, &sz);
9280     ok(err == MSIDBERROR_MOREDATA, "got %d\n", err);
9281     ok(!strcmp(buffer, "x"), "got \"%s\"\n", buffer);
9282     ok(sz == 1, "got size %lu\n", sz);
9283 
9284     sz = 0;
9285     strcpy(buffer, "x");
9286     err = MsiViewGetErrorA(view, buffer, &sz);
9287     ok(err == MSIDBERROR_MOREDATA, "got %d\n", err);
9288     ok(!strcmp(buffer, "x"), "got \"%s\"\n", buffer);
9289     todo_wine ok(sz == 0, "got size %lu\n", sz);
9290 
9291     MsiCloseHandle(rec);
9292     MsiCloseHandle(view);
9293     MsiCloseHandle(db);
9294     DeleteFileA(msifile);
9295 }
9296 
9297 static void test_viewfetch_wraparound(void)
9298 {
9299     MSIHANDLE db = 0, view = 0, rec = 0;
9300     UINT r, i, idset, tries;
9301     const char *query;
9302 
9303     DeleteFileA(msifile);
9304 
9305     /* just MsiOpenDatabase should not create a file */
9306     r = MsiOpenDatabaseW( msifileW, MSIDBOPEN_CREATE, &db );
9307     ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r );
9308 
9309     query = "CREATE TABLE `phone` ( "
9310             "`id` INT, `name` CHAR(32), `number` CHAR(32) "
9311             "PRIMARY KEY `id`)";
9312     r = run_query( db, 0, query );
9313     ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r );
9314 
9315     query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
9316         "VALUES('1', 'Alan', '5030581')";
9317     r = run_query( db, 0, query );
9318     ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r );
9319 
9320     query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
9321         "VALUES('2', 'Barry', '928440')";
9322     r = run_query( db, 0, query );
9323     ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r );
9324 
9325     query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
9326         "VALUES('3', 'Cindy', '2937550')";
9327     r = run_query( db, 0, query );
9328     ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r );
9329 
9330     query = "SELECT * FROM `phone`";
9331     r = MsiDatabaseOpenViewA( db, query, &view );
9332     ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r );
9333 
9334     r = MsiViewExecute( view, 0 );
9335     ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r );
9336 
9337     for (tries = 0; tries < 3; tries++)
9338     {
9339         winetest_push_context( "Wraparound attempt #%d", tries );
9340         idset = 0;
9341 
9342         for (i = 0; i < 3; i++)
9343         {
9344             winetest_push_context( "Record #%d", i );
9345 
9346             r = MsiViewFetch( view, &rec );
9347             ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r );
9348             if (r != ERROR_SUCCESS)
9349             {
9350                 winetest_pop_context();
9351                 break;
9352             }
9353 
9354             r = MsiRecordGetInteger(rec, 1);
9355             ok(r >= 1 && r <= 3, "Expected 1 <= id <= 3, got %d\n", r);
9356             if (r < sizeof(idset) * 8)
9357             {
9358                 ok(!(idset & (1 << r)), "Duplicate id %d\n", r);
9359                 idset |= 1 << r;
9360             }
9361 
9362             MsiCloseHandle(rec);
9363 
9364             winetest_pop_context();
9365         }
9366 
9367         r = MsiViewFetch(view, &rec);
9368         ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
9369 
9370         winetest_pop_context();
9371     }
9372 
9373     MsiViewClose(view);
9374     MsiCloseHandle(view);
9375     MsiCloseHandle(db);
9376     DeleteFileA(msifile);
9377 }
9378 
9379 START_TEST(db)
9380 {
9381     test_msidatabase();
9382     test_msiinsert();
9383     test_msidecomposedesc();
9384     test_msibadqueries();
9385     test_viewmodify();
9386     test_viewgetcolumninfo();
9387     test_getcolinfo();
9388     test_msiexport();
9389     test_longstrings();
9390     test_streamtable();
9391     test_binary();
9392     test_where_not_in_selected();
9393     test_where();
9394     test_msiimport();
9395     test_binary_import();
9396     test_markers();
9397     test_handle_limit();
9398     test_try_transform();
9399     test_join();
9400     test_temporary_table();
9401     test_alter();
9402     test_integers();
9403     test_update();
9404     test_special_tables();
9405     test_tables_order();
9406     test_rows_order();
9407     test_select_markers();
9408     test_viewmodify_update();
9409     test_viewmodify_assign();
9410     test_stringtable();
9411     test_viewmodify_delete();
9412     test_defaultdatabase();
9413     test_order();
9414     test_viewmodify_delete_temporary();
9415     test_deleterow();
9416     test_quotes();
9417     test_carriagereturn();
9418     test_noquotes();
9419     test_forcecodepage();
9420     test_viewmodify_refresh();
9421     test_where_viewmodify();
9422     test_storages_table();
9423     test_dbtopackage();
9424     test_droptable();
9425     test_dbmerge();
9426     test_select_with_tablenames();
9427     test_insertorder();
9428     test_columnorder();
9429     test_suminfo_import();
9430     test_createtable();
9431     test_collation();
9432     test_embedded_nulls();
9433     test_select_column_names();
9434     test_primary_keys();
9435     test_viewmodify_merge();
9436     test_viewmodify_insert();
9437     test_view_get_error();
9438     test_viewfetch_wraparound();
9439 }
9440