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