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