mshtml: Add tests for get_scrollLeft.
[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 <msiquery.h>
28
29 #include <objidl.h>
30
31 #include "wine/test.h"
32
33 static const char *msifile = "winetest.msi";
34 static const char *msifile2 = "winetst2.msi";
35 static const char *mstfile = "winetst.mst";
36
37 static void test_msidatabase(void)
38 {
39     MSIHANDLE hdb = 0, hdb2 = 0;
40     UINT res;
41
42     DeleteFile(msifile);
43
44     res = MsiOpenDatabase( msifile, msifile2, &hdb );
45     ok( res == ERROR_OPEN_FAILED, "expected failure\n");
46
47     res = MsiOpenDatabase( msifile, (LPSTR) 0xff, &hdb );
48     ok( res == ERROR_INVALID_PARAMETER, "expected failure\n");
49
50     res = MsiCloseHandle( hdb );
51     ok( res == ERROR_SUCCESS , "Failed to close database\n" );
52
53     /* create an empty database */
54     res = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb );
55     ok( res == ERROR_SUCCESS , "Failed to create database\n" );
56
57     res = MsiDatabaseCommit( hdb );
58     ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
59
60     ok( INVALID_FILE_ATTRIBUTES != GetFileAttributes( msifile ), "database should exist\n");
61
62     res = MsiCloseHandle( hdb );
63     ok( res == ERROR_SUCCESS , "Failed to close database\n" );
64     res = MsiOpenDatabase( msifile, msifile2, &hdb2 );
65     ok( res == ERROR_SUCCESS , "Failed to open database\n" );
66
67     ok( INVALID_FILE_ATTRIBUTES != GetFileAttributes( msifile2 ), "database should exist\n");
68
69     res = MsiDatabaseCommit( hdb2 );
70     ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
71
72     res = MsiCloseHandle( hdb2 );
73     ok( res == ERROR_SUCCESS , "Failed to close database\n" );
74
75     res = MsiOpenDatabase( msifile, msifile2, &hdb2 );
76     ok( res == ERROR_SUCCESS , "Failed to open database\n" );
77
78     res = MsiCloseHandle( hdb2 );
79     ok( res == ERROR_SUCCESS , "Failed to close database\n" );
80
81     ok( INVALID_FILE_ATTRIBUTES == GetFileAttributes( msifile2 ), "uncommitted database should not exist\n");
82
83     res = MsiOpenDatabase( msifile, msifile2, &hdb2 );
84     ok( res == ERROR_SUCCESS , "Failed to close database\n" );
85
86     res = MsiDatabaseCommit( hdb2 );
87     ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
88
89     res = MsiCloseHandle( hdb2 );
90     ok( res == ERROR_SUCCESS , "Failed to close database\n" );
91
92     ok( INVALID_FILE_ATTRIBUTES != GetFileAttributes( msifile2 ), "committed database should exist\n");
93
94     res = MsiOpenDatabase( msifile, MSIDBOPEN_READONLY, &hdb );
95     ok( res == ERROR_SUCCESS , "Failed to open database\n" );
96
97     res = MsiCloseHandle( hdb );
98     ok( res == ERROR_SUCCESS , "Failed to close database\n" );
99
100     res = MsiOpenDatabase( msifile, MSIDBOPEN_DIRECT, &hdb );
101     ok( res == ERROR_SUCCESS , "Failed to open database\n" );
102
103     res = MsiCloseHandle( hdb );
104     ok( res == ERROR_SUCCESS , "Failed to close database\n" );
105
106     res = MsiOpenDatabase( msifile, MSIDBOPEN_TRANSACT, &hdb );
107     ok( res == ERROR_SUCCESS , "Failed to open database\n" );
108
109     res = MsiCloseHandle( hdb );
110     ok( res == ERROR_SUCCESS , "Failed to close database\n" );
111     ok( INVALID_FILE_ATTRIBUTES != GetFileAttributes( msifile ), "database should exist\n");
112
113     /* MSIDBOPEN_CREATE deletes the database if MsiCommitDatabase isn't called */
114     res = MsiOpenDatabase( msifile, MSIDBOPEN_CREATE, &hdb );
115     ok( res == ERROR_SUCCESS , "Failed to open database\n" );
116
117     ok( INVALID_FILE_ATTRIBUTES != GetFileAttributes( msifile ), "database should exist\n");
118
119     res = MsiCloseHandle( hdb );
120     ok( res == ERROR_SUCCESS , "Failed to close database\n" );
121
122     ok( INVALID_FILE_ATTRIBUTES == GetFileAttributes( msifile ), "database should exist\n");
123
124     res = MsiOpenDatabase( msifile, MSIDBOPEN_CREATE, &hdb );
125     ok( res == ERROR_SUCCESS , "Failed to open database\n" );
126
127     res = MsiDatabaseCommit( hdb );
128     ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
129
130     ok( INVALID_FILE_ATTRIBUTES != GetFileAttributes( msifile ), "database should exist\n");
131
132     res = MsiCloseHandle( hdb );
133     ok( res == ERROR_SUCCESS , "Failed to close database\n" );
134
135     res = DeleteFile( msifile2 );
136     ok( res == TRUE, "Failed to delete database\n" );
137
138     res = DeleteFile( msifile );
139     ok( res == TRUE, "Failed to delete database\n" );
140 }
141
142 static UINT do_query(MSIHANDLE hdb, const char *query, MSIHANDLE *phrec)
143 {
144     MSIHANDLE hview = 0;
145     UINT r, ret;
146
147     /* open a select query */
148     r = MsiDatabaseOpenView(hdb, query, &hview);
149     if (r != ERROR_SUCCESS)
150         return r;
151     r = MsiViewExecute(hview, 0);
152     if (r != ERROR_SUCCESS)
153         return r;
154     ret = MsiViewFetch(hview, phrec);
155     r = MsiViewClose(hview);
156     if (r != ERROR_SUCCESS)
157         return r;
158     r = MsiCloseHandle(hview);
159     if (r != ERROR_SUCCESS)
160         return r;
161     return ret;
162 }
163
164 static UINT run_query( MSIHANDLE hdb, MSIHANDLE hrec, const char *query )
165 {
166     MSIHANDLE hview = 0;
167     UINT r;
168
169     r = MsiDatabaseOpenView(hdb, query, &hview);
170     if( r != ERROR_SUCCESS )
171         return r;
172
173     r = MsiViewExecute(hview, hrec);
174     if( r == ERROR_SUCCESS )
175         r = MsiViewClose(hview);
176     MsiCloseHandle(hview);
177     return r;
178 }
179
180 static UINT create_component_table( MSIHANDLE hdb )
181 {
182     return run_query( hdb, 0,
183             "CREATE TABLE `Component` ( "
184             "`Component` CHAR(72) NOT NULL, "
185             "`ComponentId` CHAR(38), "
186             "`Directory_` CHAR(72) NOT NULL, "
187             "`Attributes` SHORT NOT NULL, "
188             "`Condition` CHAR(255), "
189             "`KeyPath` CHAR(72) "
190             "PRIMARY KEY `Component`)" );
191 }
192
193 static UINT create_custom_action_table( MSIHANDLE hdb )
194 {
195     return run_query( hdb, 0,
196             "CREATE TABLE `CustomAction` ( "
197             "`Action` CHAR(72) NOT NULL, "
198             "`Type` SHORT NOT NULL, "
199             "`Source` CHAR(72), "
200             "`Target` CHAR(255) "
201             "PRIMARY KEY `Action`)" );
202 }
203
204 static UINT create_directory_table( MSIHANDLE hdb )
205 {
206     return run_query( hdb, 0,
207             "CREATE TABLE `Directory` ( "
208             "`Directory` CHAR(255) NOT NULL, "
209             "`Directory_Parent` CHAR(255), "
210             "`DefaultDir` CHAR(255) NOT NULL "
211             "PRIMARY KEY `Directory`)" );
212 }
213
214 static UINT create_feature_components_table( MSIHANDLE hdb )
215 {
216     return run_query( hdb, 0,
217             "CREATE TABLE `FeatureComponents` ( "
218             "`Feature_` CHAR(38) NOT NULL, "
219             "`Component_` CHAR(72) NOT NULL "
220             "PRIMARY KEY `Feature_`, `Component_` )" );
221 }
222
223 static UINT create_std_dlls_table( MSIHANDLE hdb )
224 {
225     return run_query( hdb, 0,
226             "CREATE TABLE `StdDlls` ( "
227             "`File` CHAR(255) NOT NULL, "
228             "`Binary_` CHAR(72) NOT NULL "
229             "PRIMARY KEY `File` )" );
230 }
231
232 static UINT create_binary_table( MSIHANDLE hdb )
233 {
234     return run_query( hdb, 0,
235             "CREATE TABLE `Binary` ( "
236             "`Name` CHAR(72) NOT NULL, "
237             "`Data` CHAR(72) NOT NULL "
238             "PRIMARY KEY `Name` )" );
239 }
240
241 static UINT add_component_entry( MSIHANDLE hdb, const char *values )
242 {
243     char insert[] = "INSERT INTO `Component`  "
244             "(`Component`, `ComponentId`, `Directory_`, `Attributes`, `Condition`, `KeyPath`) "
245             "VALUES( %s )";
246     char *query;
247     UINT sz, r;
248
249     sz = strlen(values) + sizeof insert;
250     query = HeapAlloc(GetProcessHeap(),0,sz);
251     sprintf(query,insert,values);
252     r = run_query( hdb, 0, query );
253     HeapFree(GetProcessHeap(), 0, query);
254     return r;
255 }
256
257 static UINT add_custom_action_entry( MSIHANDLE hdb, const char *values )
258 {
259     char insert[] = "INSERT INTO `CustomAction`  "
260             "(`Action`, `Type`, `Source`, `Target`) "
261             "VALUES( %s )";
262     char *query;
263     UINT sz, r;
264
265     sz = strlen(values) + sizeof insert;
266     query = HeapAlloc(GetProcessHeap(),0,sz);
267     sprintf(query,insert,values);
268     r = run_query( hdb, 0, query );
269     HeapFree(GetProcessHeap(), 0, query);
270     return r;
271 }
272
273 static UINT add_feature_components_entry( MSIHANDLE hdb, const char *values )
274 {
275     char insert[] = "INSERT INTO `FeatureComponents` "
276             "(`Feature_`, `Component_`) "
277             "VALUES( %s )";
278     char *query;
279     UINT sz, r;
280
281     sz = strlen(values) + sizeof insert;
282     query = HeapAlloc(GetProcessHeap(),0,sz);
283     sprintf(query,insert,values);
284     r = run_query( hdb, 0, query );
285     HeapFree(GetProcessHeap(), 0, query);
286     return r;
287 }
288
289 static UINT add_std_dlls_entry( MSIHANDLE hdb, const char *values )
290 {
291     char insert[] = "INSERT INTO `StdDlls` "
292             "(`File`, `Binary_`) "
293             "VALUES( %s )";
294     char *query;
295     UINT sz, r;
296
297     sz = strlen(values) + sizeof insert;
298     query = HeapAlloc(GetProcessHeap(),0,sz);
299     sprintf(query,insert,values);
300     r = run_query( hdb, 0, query );
301     HeapFree(GetProcessHeap(), 0, query);
302     return r;
303 }
304
305 static UINT add_binary_entry( MSIHANDLE hdb, const char *values )
306 {
307     char insert[] = "INSERT INTO `Binary` "
308             "(`Name`, `Data`) "
309             "VALUES( %s )";
310     char *query;
311     UINT sz, r;
312
313     sz = strlen(values) + sizeof insert;
314     query = HeapAlloc(GetProcessHeap(),0,sz);
315     sprintf(query,insert,values);
316     r = run_query( hdb, 0, query );
317     HeapFree(GetProcessHeap(), 0, query);
318     return r;
319 }
320
321 static void test_msiinsert(void)
322 {
323     MSIHANDLE hdb = 0, hview = 0, hrec = 0;
324     UINT r;
325     const char *query;
326     char buf[80];
327     DWORD sz;
328
329     DeleteFile(msifile);
330
331     /* just MsiOpenDatabase should not create a file */
332     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
333     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
334
335     /* create a table */
336     query = "CREATE TABLE `phone` ( "
337             "`id` INT, `name` CHAR(32), `number` CHAR(32) "
338             "PRIMARY KEY `id`)";
339     r = MsiDatabaseOpenView(hdb, query, &hview);
340     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
341     r = MsiViewExecute(hview, 0);
342     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
343     r = MsiViewClose(hview);
344     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
345     r = MsiCloseHandle(hview);
346     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
347
348     /* insert a value into it */
349     query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
350         "VALUES('1', 'Abe', '8675309')";
351     r = MsiDatabaseOpenView(hdb, query, &hview);
352     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
353     r = MsiViewExecute(hview, 0);
354     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
355     r = MsiViewClose(hview);
356     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
357     r = MsiCloseHandle(hview);
358     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
359
360     query = "SELECT * FROM `phone` WHERE `id` = 1";
361     r = do_query(hdb, query, &hrec);
362     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
363
364     /* check the record contains what we put in it */
365     r = MsiRecordGetFieldCount(hrec);
366     ok(r == 3, "record count wrong\n");
367
368     todo_wine {
369     r = MsiRecordIsNull(hrec, 0);
370     ok(r == FALSE, "field 0 not null\n");
371     }
372
373     r = MsiRecordGetInteger(hrec, 1);
374     ok(r == 1, "field 1 contents wrong\n");
375     sz = sizeof buf;
376     r = MsiRecordGetString(hrec, 2, buf, &sz);
377     ok(r == ERROR_SUCCESS, "field 2 content fetch failed\n");
378     ok(!strcmp(buf,"Abe"), "field 2 content incorrect\n");
379     sz = sizeof buf;
380     r = MsiRecordGetString(hrec, 3, buf, &sz);
381     ok(r == ERROR_SUCCESS, "field 3 content fetch failed\n");
382     ok(!strcmp(buf,"8675309"), "field 3 content incorrect\n");
383
384     r = MsiCloseHandle(hrec);
385     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
386
387     /* open a select query */
388     hrec = 100;
389     query = "SELECT * FROM `phone` WHERE `id` >= 10";
390     r = do_query(hdb, query, &hrec);
391     ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch failed\n");
392     ok(hrec == 0, "hrec should be null\n");
393
394     r = MsiCloseHandle(hrec);
395     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
396
397     query = "SELECT * FROM `phone` WHERE `id` < 0";
398     r = do_query(hdb, query, &hrec);
399     ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch failed\n");
400
401     query = "SELECT * FROM `phone` WHERE `id` <= 0";
402     r = do_query(hdb, query, &hrec);
403     ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch failed\n");
404
405     query = "SELECT * FROM `phone` WHERE `id` <> 1";
406     r = do_query(hdb, query, &hrec);
407     ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch failed\n");
408
409     query = "SELECT * FROM `phone` WHERE `id` > 10";
410     r = do_query(hdb, query, &hrec);
411     ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch failed\n");
412
413     /* now try a few bad INSERT xqueries */
414     query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
415         "VALUES(?, ?)";
416     r = MsiDatabaseOpenView(hdb, query, &hview);
417     ok(r == ERROR_BAD_QUERY_SYNTAX, "MsiDatabaseOpenView failed\n");
418
419     /* construct a record to insert */
420     hrec = MsiCreateRecord(4);
421     r = MsiRecordSetInteger(hrec, 1, 2);
422     ok(r == ERROR_SUCCESS, "MsiRecordSetInteger failed\n");
423     r = MsiRecordSetString(hrec, 2, "Adam");
424     ok(r == ERROR_SUCCESS, "MsiRecordSetString failed\n");
425     r = MsiRecordSetString(hrec, 3, "96905305");
426     ok(r == ERROR_SUCCESS, "MsiRecordSetString failed\n");
427
428     /* insert another value, using a record and wildcards */
429     query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
430         "VALUES(?, ?, ?)";
431     r = MsiDatabaseOpenView(hdb, query, &hview);
432     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
433
434     if (r == ERROR_SUCCESS)
435     {
436         r = MsiViewExecute(hview, hrec);
437         ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
438         r = MsiViewClose(hview);
439         ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
440         r = MsiCloseHandle(hview);
441         ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
442     }
443     r = MsiCloseHandle(hrec);
444     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
445
446     r = MsiViewFetch(0, NULL);
447     ok(r == ERROR_INVALID_PARAMETER, "MsiViewFetch failed\n");
448
449     r = MsiDatabaseCommit(hdb);
450     ok(r == ERROR_SUCCESS, "MsiDatabaseCommit failed\n");
451
452     r = MsiCloseHandle(hdb);
453     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
454
455     r = DeleteFile(msifile);
456     ok(r == TRUE, "file didn't exist after commit\n");
457 }
458
459 typedef UINT (WINAPI *fnMsiDecomposeDescriptorA)(LPCSTR, LPCSTR, LPSTR, LPSTR, DWORD *);
460 static fnMsiDecomposeDescriptorA pMsiDecomposeDescriptorA;
461
462 static void test_msidecomposedesc(void)
463 {
464     char prod[MAX_FEATURE_CHARS+1], comp[MAX_FEATURE_CHARS+1], feature[MAX_FEATURE_CHARS+1];
465     const char *desc;
466     UINT r;
467     DWORD len;
468     HMODULE hmod;
469
470     hmod = GetModuleHandle("msi.dll");
471     pMsiDecomposeDescriptorA = (fnMsiDecomposeDescriptorA)
472         GetProcAddress(hmod, "MsiDecomposeDescriptorA");
473     if (!pMsiDecomposeDescriptorA)
474         return;
475
476     /* test a valid feature descriptor */
477     desc = "']gAVn-}f(ZXfeAR6.jiFollowTheWhiteRabbit>3w2x^IGfe?CxI5heAvk.";
478     len = 0;
479     r = pMsiDecomposeDescriptorA(desc, prod, feature, comp, &len);
480     ok(r == ERROR_SUCCESS, "returned an error\n");
481     ok(len == strlen(desc), "length was wrong\n");
482     ok(strcmp(prod,"{90110409-6000-11D3-8CFE-0150048383C9}")==0, "product wrong\n");
483     ok(strcmp(feature,"FollowTheWhiteRabbit")==0, "feature wrong\n");
484     ok(strcmp(comp,"{A7CD68DB-EF74-49C8-FBB2-A7C463B2AC24}")==0,"component wrong\n");
485
486     /* test an invalid feature descriptor with too many characters */
487     desc = "']gAVn-}f(ZXfeAR6.ji"
488            "ThisWillFailIfTheresMoreThanAGuidsChars>"
489            "3w2x^IGfe?CxI5heAvk.";
490     len = 0;
491     r = pMsiDecomposeDescriptorA(desc, prod, feature, comp, &len);
492     ok(r == ERROR_INVALID_PARAMETER, "returned wrong error\n");
493
494     /*
495      * Test a valid feature descriptor with the
496      * maximum number of characters and some trailing characters.
497      */
498     desc = "']gAVn-}f(ZXfeAR6.ji"
499            "ThisWillWorkIfTheresLTEThanAGuidsChars>"
500            "3w2x^IGfe?CxI5heAvk."
501            "extra";
502     len = 0;
503     r = pMsiDecomposeDescriptorA(desc, prod, feature, comp, &len);
504     ok(r == ERROR_SUCCESS, "returned wrong error\n");
505     ok(len == (strlen(desc) - strlen("extra")), "length wrong\n");
506
507     len = 0;
508     r = pMsiDecomposeDescriptorA(desc, prod, feature, NULL, &len);
509     ok(r == ERROR_SUCCESS, "returned wrong error\n");
510     ok(len == (strlen(desc) - strlen("extra")), "length wrong\n");
511
512     len = 0;
513     r = pMsiDecomposeDescriptorA(desc, prod, NULL, NULL, &len);
514     ok(r == ERROR_SUCCESS, "returned wrong error\n");
515     ok(len == (strlen(desc) - strlen("extra")), "length wrong\n");
516
517     len = 0;
518     r = pMsiDecomposeDescriptorA(desc, NULL, NULL, NULL, &len);
519     ok(r == ERROR_SUCCESS, "returned wrong error\n");
520     ok(len == (strlen(desc) - strlen("extra")), "length wrong\n");
521
522     len = 0;
523     r = pMsiDecomposeDescriptorA(NULL, NULL, NULL, NULL, &len);
524     ok(r == ERROR_INVALID_PARAMETER, "returned wrong error\n");
525     ok(len == 0, "length wrong\n");
526 }
527
528 static UINT try_query_param( MSIHANDLE hdb, LPCSTR szQuery, MSIHANDLE hrec )
529 {
530     MSIHANDLE htab = 0;
531     UINT res;
532
533     res = MsiDatabaseOpenView( hdb, szQuery, &htab );
534     if(res == ERROR_SUCCESS )
535     {
536         UINT r;
537
538         r = MsiViewExecute( htab, hrec );
539         if(r != ERROR_SUCCESS )
540             res = r;
541
542         r = MsiViewClose( htab );
543         if(r != ERROR_SUCCESS )
544             res = r;
545
546         r = MsiCloseHandle( htab );
547         if(r != ERROR_SUCCESS )
548             res = r;
549     }
550     return res;
551 }
552
553 static UINT try_query( MSIHANDLE hdb, LPCSTR szQuery )
554 {
555     return try_query_param( hdb, szQuery, 0 );
556 }
557
558 static UINT try_insert_query( MSIHANDLE hdb, LPCSTR szQuery )
559 {
560     MSIHANDLE hrec = 0;
561     UINT r;
562
563     hrec = MsiCreateRecord( 1 );
564     MsiRecordSetString( hrec, 1, "Hello");
565
566     r = try_query_param( hdb, szQuery, hrec );
567
568     MsiCloseHandle( hrec );
569     return r;
570 }
571
572 static void test_msibadqueries(void)
573 {
574     MSIHANDLE hdb = 0;
575     UINT r;
576
577     DeleteFile(msifile);
578
579     /* just MsiOpenDatabase should not create a file */
580     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
581     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
582
583     r = MsiDatabaseCommit( hdb );
584     ok(r == ERROR_SUCCESS , "Failed to commit database\n");
585
586     r = MsiCloseHandle( hdb );
587     ok(r == ERROR_SUCCESS , "Failed to close database\n");
588
589     /* open it readonly */
590     r = MsiOpenDatabase(msifile, MSIDBOPEN_READONLY, &hdb );
591     ok(r == ERROR_SUCCESS , "Failed to open database r/o\n");
592
593     /* add a table to it */
594     r = try_query( hdb, "select * from _Tables");
595     ok(r == ERROR_SUCCESS , "query 1 failed\n");
596
597     r = MsiCloseHandle( hdb );
598     ok(r == ERROR_SUCCESS , "Failed to close database r/o\n");
599
600     /* open it read/write */
601     r = MsiOpenDatabase(msifile, MSIDBOPEN_TRANSACT, &hdb );
602     ok(r == ERROR_SUCCESS , "Failed to open database r/w\n");
603
604     /* a bunch of test queries that fail with the native MSI */
605
606     r = try_query( hdb, "CREATE TABLE");
607     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2a return code\n");
608
609     r = try_query( hdb, "CREATE TABLE `a`");
610     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2b return code\n");
611
612     r = try_query( hdb, "CREATE TABLE `a` ()");
613     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2c return code\n");
614
615     r = try_query( hdb, "CREATE TABLE `a` (`b`)");
616     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2d return code\n");
617
618     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) )");
619     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2e return code\n");
620
621     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL)");
622     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2f return code\n");
623
624     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY)");
625     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2g return code\n");
626
627     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY)");
628     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2h return code\n");
629
630     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY)");
631     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2i return code\n");
632
633     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY 'b')");
634     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2j return code\n");
635
636     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY `b')");
637     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2k return code\n");
638
639     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY `b')");
640     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2l return code\n");
641
642     r = try_query( hdb, "CREATE TABLE `a` (`b` CHA(72) NOT NULL PRIMARY KEY `b`)");
643     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2m return code\n");
644
645     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(-1) NOT NULL PRIMARY KEY `b`)");
646     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2n return code\n");
647
648     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(720) NOT NULL PRIMARY KEY `b`)");
649     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2o return code\n");
650
651     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL KEY `b`)");
652     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2p return code\n");
653
654     r = try_query( hdb, "CREATE TABLE `a` (`` CHAR(72) NOT NULL PRIMARY KEY `b`)");
655     ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2p return code\n");
656
657     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY `b`)");
658     ok(r == ERROR_SUCCESS , "valid query 2z failed\n");
659
660     r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY `b`)");
661     ok(r == ERROR_BAD_QUERY_SYNTAX , "created same table again\n");
662
663     r = try_query( hdb, "CREATE TABLE `aa` (`b` CHAR(72) NOT NULL, `c` "
664           "CHAR(72), `d` CHAR(255) NOT NULL LOCALIZABLE PRIMARY KEY `b`)");
665     ok(r == ERROR_SUCCESS , "query 4 failed\n");
666
667     r = MsiDatabaseCommit( hdb );
668     ok(r == ERROR_SUCCESS , "Failed to commit database after write\n");
669
670     r = try_query( hdb, "CREATE TABLE `blah` (`foo` CHAR(72) NOT NULL "
671                           "PRIMARY KEY `foo`)");
672     ok(r == ERROR_SUCCESS , "query 4 failed\n");
673
674     r = try_insert_query( hdb, "insert into a  ( `b` ) VALUES ( ? )");
675     ok(r == ERROR_SUCCESS , "failed to insert record in db\n");
676
677     r = MsiDatabaseCommit( hdb );
678     ok(r == ERROR_SUCCESS , "Failed to commit database after write\n");
679
680     r = try_query( hdb, "CREATE TABLE `boo` (`foo` CHAR(72) NOT NULL "
681                           "PRIMARY KEY `ba`)");
682     ok(r != ERROR_SUCCESS , "query 5 succeeded\n");
683
684     r = try_query( hdb,"CREATE TABLE `bee` (`foo` CHAR(72) NOT NULL )");
685     ok(r != ERROR_SUCCESS , "query 6 succeeded\n");
686
687     r = try_query( hdb, "CREATE TABLE `temp` (`t` CHAR(72) NOT NULL "
688                           "PRIMARY KEY `t`)");
689     ok(r == ERROR_SUCCESS , "query 7 failed\n");
690
691     r = try_query( hdb, "CREATE TABLE `c` (`b` CHAR NOT NULL PRIMARY KEY `b`)");
692     ok(r == ERROR_SUCCESS , "query 8 failed\n");
693
694     r = try_query( hdb, "select * from c");
695     ok(r == ERROR_SUCCESS , "query failed\n");
696
697     r = try_query( hdb, "select * from c where b = 'x");
698     todo_wine ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
699
700     r = try_query( hdb, "select * from 'c'");
701     ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
702
703     r = try_query( hdb, "select * from ''");
704     ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
705
706     r = try_query( hdb, "select * from c where b = x");
707     ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
708
709     r = try_query( hdb, "select * from c where b = \"x\"");
710     ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
711
712     r = try_query( hdb, "select * from c where b = 'x'");
713     ok(r == ERROR_SUCCESS, "query failed\n");
714
715     r = try_query( hdb, "select * from c where b = '\"x'");
716     ok(r == ERROR_SUCCESS, "query failed\n");
717
718     if (0)  /* FIXME: this query causes trouble with other tests */
719     {
720         r = try_query( hdb, "select * from c where b = '\\\'x'");
721         ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
722     }
723
724     r = try_query( hdb, "select * from 'c'");
725     ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
726
727     r = MsiCloseHandle( hdb );
728     ok(r == ERROR_SUCCESS , "Failed to close database transact\n");
729
730     r = DeleteFile( msifile );
731     ok(r == TRUE, "file didn't exist after commit\n");
732 }
733
734 static void test_viewmodify(void)
735 {
736     MSIHANDLE hdb = 0, hview = 0, hrec = 0;
737     UINT r;
738     MSIDBERROR err;
739     const char *query;
740     char buffer[0x100];
741     DWORD sz;
742
743     DeleteFile(msifile);
744
745     /* just MsiOpenDatabase should not create a file */
746     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
747     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
748
749     query = "CREATE TABLE `phone` ( "
750             "`id` INT, `name` CHAR(32), `number` CHAR(32) "
751             "PRIMARY KEY `id`)";
752     r = run_query( hdb, 0, query );
753     ok(r == ERROR_SUCCESS, "query failed\n");
754
755     /* check what the error function reports without doing anything */
756     sz = 0;
757     /* passing NULL as the 3rd param make function to crash on older platforms */
758     err = MsiViewGetError( 0, NULL, &sz );
759     ok(err == MSIDBERROR_INVALIDARG, "MsiViewGetError return\n");
760
761     /* open a view */
762     query = "SELECT * FROM `phone`";
763     r = MsiDatabaseOpenView(hdb, query, &hview);
764     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
765
766     /* see what happens with a good hview and bad args */
767     err = MsiViewGetError( hview, NULL, NULL );
768     ok(err == MSIDBERROR_INVALIDARG || err == MSIDBERROR_NOERROR,
769        "MsiViewGetError returns %u (expected -3)\n", err);
770     err = MsiViewGetError( hview, buffer, NULL );
771     ok(err == MSIDBERROR_INVALIDARG, "MsiViewGetError return\n");
772
773     /* see what happens with a zero length buffer */
774     sz = 0;
775     buffer[0] = 'x';
776     err = MsiViewGetError( hview, buffer, &sz );
777     ok(err == MSIDBERROR_MOREDATA, "MsiViewGetError return\n");
778     ok(buffer[0] == 'x', "buffer cleared\n");
779     ok(sz == 0, "size not zero\n");
780
781     /* ok this one is strange */
782     sz = 0;
783     err = MsiViewGetError( hview, NULL, &sz );
784     ok(err == MSIDBERROR_NOERROR, "MsiViewGetError return\n");
785     ok(sz == 0, "size not zero\n");
786
787     /* see if it really has an error */
788     sz = sizeof buffer;
789     buffer[0] = 'x';
790     err = MsiViewGetError( hview, buffer, &sz );
791     ok(err == MSIDBERROR_NOERROR, "MsiViewGetError return\n");
792     ok(buffer[0] == 0, "buffer not cleared\n");
793     ok(sz == 0, "size not zero\n");
794
795     r = MsiViewExecute(hview, 0);
796     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
797
798     /* try some invalid records */
799     r = MsiViewModify(hview, MSIMODIFY_INSERT, 0 );
800     ok(r == ERROR_INVALID_HANDLE, "MsiViewModify failed\n");
801     r = MsiViewModify(hview, -1, 0 );
802     ok(r == ERROR_INVALID_HANDLE, "MsiViewModify failed\n");
803
804     /* try an small record */
805     hrec = MsiCreateRecord(1);
806     r = MsiViewModify(hview, -1, hrec );
807     ok(r == ERROR_INVALID_DATA, "MsiViewModify failed\n");
808
809     r = MsiCloseHandle(hrec);
810     ok(r == ERROR_SUCCESS, "failed to close record\n");
811
812     /* insert a valid record */
813     hrec = MsiCreateRecord(3);
814
815     r = MsiRecordSetInteger(hrec, 1, 1);
816     ok(r == ERROR_SUCCESS, "failed to set integer\n");
817     r = MsiRecordSetString(hrec, 2, "bob");
818     ok(r == ERROR_SUCCESS, "failed to set string\n");
819     r = MsiRecordSetString(hrec, 3, "7654321");
820     ok(r == ERROR_SUCCESS, "failed to set string\n");
821
822     r = MsiViewExecute(hview, 0);
823     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
824     r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec );
825     ok(r == ERROR_SUCCESS, "MsiViewModify failed\n");
826
827     /* insert the same thing again */
828     r = MsiViewExecute(hview, 0);
829     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
830
831     /* should fail ... */
832     r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec );
833     ok(r == ERROR_FUNCTION_FAILED, "MsiViewModify failed\n");
834
835     r = MsiCloseHandle(hrec);
836     ok(r == ERROR_SUCCESS, "failed to close record\n");
837
838     r = MsiViewClose(hview);
839     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
840     r = MsiCloseHandle(hview);
841     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
842
843     query = "SELECT * FROM `phone`";
844     r = MsiDatabaseOpenView(hdb, query, &hview);
845     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
846
847     r = MsiViewExecute(hview, 0);
848     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
849
850     r = MsiViewFetch(hview, &hrec);
851     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
852
853     r = MsiRecordGetInteger(hrec, 1);
854     ok(r == 1, "Expected 1, got %d\n", r);
855
856     sz = sizeof(buffer);
857     r = MsiRecordGetString(hrec, 2, buffer, &sz);
858     ok(r == ERROR_SUCCESS, "MsiRecordGetString failed\n");
859     ok(!lstrcmp(buffer, "bob"), "Expected bob, got %s\n", buffer);
860
861     sz = sizeof(buffer);
862     r = MsiRecordGetString(hrec, 3, buffer, &sz);
863     ok(r == ERROR_SUCCESS, "MsiRecordGetString failed\n");
864     ok(!lstrcmp(buffer, "7654321"), "Expected 7654321, got %s\n", buffer);
865
866     /* update the view, non-primary key */
867     r = MsiRecordSetString(hrec, 3, "3141592");
868     ok(r == ERROR_SUCCESS, "MsiRecordSetString failed\n");
869
870     r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
871     ok(r == ERROR_SUCCESS, "MsiViewModify failed\n");
872
873     /* do it again */
874     r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
875     ok(r == ERROR_SUCCESS, "MsiViewModify failed: %d\n", r);
876
877     /* update the view, primary key */
878     r = MsiRecordSetInteger(hrec, 1, 5);
879     ok(r == ERROR_SUCCESS, "MsiRecordSetInteger failed\n");
880
881     r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
882     ok(r == ERROR_FUNCTION_FAILED, "MsiViewModify failed\n");
883
884     r = MsiCloseHandle(hrec);
885     ok(r == ERROR_SUCCESS, "failed to close record\n");
886
887     r = MsiViewClose(hview);
888     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
889     r = MsiCloseHandle(hview);
890     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
891
892     query = "SELECT * FROM `phone`";
893     r = MsiDatabaseOpenView(hdb, query, &hview);
894     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
895
896     r = MsiViewExecute(hview, 0);
897     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
898
899     r = MsiViewFetch(hview, &hrec);
900     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
901
902     r = MsiRecordGetInteger(hrec, 1);
903     ok(r == 1, "Expected 1, got %d\n", r);
904
905     sz = sizeof(buffer);
906     r = MsiRecordGetString(hrec, 2, buffer, &sz);
907     ok(r == ERROR_SUCCESS, "MsiRecordGetString failed\n");
908     ok(!lstrcmp(buffer, "bob"), "Expected bob, got %s\n", buffer);
909
910     sz = sizeof(buffer);
911     r = MsiRecordGetString(hrec, 3, buffer, &sz);
912     ok(r == ERROR_SUCCESS, "MsiRecordGetString failed\n");
913     ok(!lstrcmp(buffer, "3141592"), "Expected 3141592, got %s\n", buffer);
914
915     r = MsiCloseHandle(hrec);
916     ok(r == ERROR_SUCCESS, "failed to close record\n");
917
918     /* use a record that doesn't come from a view fetch */
919     hrec = MsiCreateRecord(3);
920     ok(hrec != 0, "MsiCreateRecord failed\n");
921
922     r = MsiRecordSetInteger(hrec, 1, 3);
923     ok(r == ERROR_SUCCESS, "failed to set integer\n");
924     r = MsiRecordSetString(hrec, 2, "jane");
925     ok(r == ERROR_SUCCESS, "failed to set string\n");
926     r = MsiRecordSetString(hrec, 3, "112358");
927     ok(r == ERROR_SUCCESS, "failed to set string\n");
928
929     r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
930     ok(r == ERROR_FUNCTION_FAILED, "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
931
932     r = MsiCloseHandle(hrec);
933     ok(r == ERROR_SUCCESS, "failed to close record\n");
934
935     /* use a record that doesn't come from a view fetch, primary key matches */
936     hrec = MsiCreateRecord(3);
937     ok(hrec != 0, "MsiCreateRecord failed\n");
938
939     r = MsiRecordSetInteger(hrec, 1, 1);
940     ok(r == ERROR_SUCCESS, "failed to set integer\n");
941     r = MsiRecordSetString(hrec, 2, "jane");
942     ok(r == ERROR_SUCCESS, "failed to set string\n");
943     r = MsiRecordSetString(hrec, 3, "112358");
944     ok(r == ERROR_SUCCESS, "failed to set string\n");
945
946     r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
947     todo_wine
948     {
949         ok(r == ERROR_FUNCTION_FAILED, "MsiViewModify failed\n");
950     }
951
952     r = MsiCloseHandle(hrec);
953     ok(r == ERROR_SUCCESS, "failed to close record\n");
954
955     hrec = MsiCreateRecord(3);
956
957     r = MsiRecordSetInteger(hrec, 1, 2);
958     ok(r == ERROR_SUCCESS, "failed to set integer\n");
959     r = MsiRecordSetString(hrec, 2, "nick");
960     ok(r == ERROR_SUCCESS, "failed to set string\n");
961     r = MsiRecordSetString(hrec, 3, "141421");
962     ok(r == ERROR_SUCCESS, "failed to set string\n");
963
964     r = MsiViewExecute(hview, 0);
965     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
966     r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec );
967     ok(r == ERROR_SUCCESS, "MsiViewModify failed\n");
968
969     r = MsiViewClose(hview);
970     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
971     r = MsiCloseHandle(hview);
972     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
973
974     query = "SELECT * FROM `phone` WHERE `id` = 1";
975     r = MsiDatabaseOpenView(hdb, query, &hview);
976     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
977     r = MsiViewExecute(hview, 0);
978     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
979     r = MsiViewFetch(hview, &hrec);
980     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
981
982     /* change the id to match the second row */
983     r = MsiRecordSetInteger(hrec, 1, 2);
984     ok(r == ERROR_SUCCESS, "failed to set integer\n");
985     r = MsiRecordSetString(hrec, 2, "jerry");
986     ok(r == ERROR_SUCCESS, "failed to set string\n");
987
988     r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
989     ok(r == ERROR_FUNCTION_FAILED, "MsiViewModify failed\n");
990
991     r = MsiCloseHandle(hrec);
992     ok(r == ERROR_SUCCESS, "failed to close record\n");
993     r = MsiViewClose(hview);
994     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
995     r = MsiCloseHandle(hview);
996     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
997
998     /* broader search */
999     query = "SELECT * FROM `phone` ORDER BY `id`";
1000     r = MsiDatabaseOpenView(hdb, query, &hview);
1001     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
1002     r = MsiViewExecute(hview, 0);
1003     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
1004     r = MsiViewFetch(hview, &hrec);
1005     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
1006
1007     /* change the id to match the second row */
1008     r = MsiRecordSetInteger(hrec, 1, 2);
1009     ok(r == ERROR_SUCCESS, "failed to set integer\n");
1010     r = MsiRecordSetString(hrec, 2, "jerry");
1011     ok(r == ERROR_SUCCESS, "failed to set string\n");
1012
1013     r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
1014     ok(r == ERROR_FUNCTION_FAILED, "MsiViewModify failed\n");
1015
1016     r = MsiCloseHandle(hrec);
1017     ok(r == ERROR_SUCCESS, "failed to close record\n");
1018     r = MsiViewClose(hview);
1019     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
1020     r = MsiCloseHandle(hview);
1021     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
1022
1023     r = MsiCloseHandle( hdb );
1024     ok(r == ERROR_SUCCESS, "MsiOpenDatabase close failed\n");
1025 }
1026
1027 static MSIHANDLE create_db(void)
1028 {
1029     MSIHANDLE hdb = 0;
1030     UINT res;
1031
1032     DeleteFile(msifile);
1033
1034     /* create an empty database */
1035     res = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb );
1036     ok( res == ERROR_SUCCESS , "Failed to create database\n" );
1037     if( res != ERROR_SUCCESS )
1038         return hdb;
1039
1040     res = MsiDatabaseCommit( hdb );
1041     ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
1042
1043     return hdb;
1044 }
1045
1046 static void test_getcolinfo(void)
1047 {
1048     MSIHANDLE hdb, hview = 0, rec = 0;
1049     UINT r;
1050     DWORD sz;
1051     char buffer[0x20];
1052
1053     /* create an empty db */
1054     hdb = create_db();
1055     ok( hdb, "failed to create db\n");
1056
1057     /* tables should be present */
1058     r = MsiDatabaseOpenView(hdb, "select * from _Tables", &hview);
1059     ok( r == ERROR_SUCCESS, "failed to open query\n");
1060
1061     r = MsiViewExecute(hview, 0);
1062     ok( r == ERROR_SUCCESS, "failed to execute query\n");
1063
1064     /* check that NAMES works */
1065     rec = 0;
1066     r = MsiViewGetColumnInfo( hview, MSICOLINFO_NAMES, &rec );
1067     ok( r == ERROR_SUCCESS, "failed to get names\n");
1068     sz = sizeof buffer;
1069     r = MsiRecordGetString(rec, 1, buffer, &sz );
1070     ok( r == ERROR_SUCCESS, "failed to get string\n");
1071     ok( !strcmp(buffer,"Name"), "_Tables has wrong column name\n");
1072     r = MsiCloseHandle( rec );
1073     ok( r == ERROR_SUCCESS, "failed to close record handle\n");
1074
1075     /* check that TYPES works */
1076     rec = 0;
1077     r = MsiViewGetColumnInfo( hview, MSICOLINFO_TYPES, &rec );
1078     ok( r == ERROR_SUCCESS, "failed to get names\n");
1079     sz = sizeof buffer;
1080     r = MsiRecordGetString(rec, 1, buffer, &sz );
1081     ok( r == ERROR_SUCCESS, "failed to get string\n");
1082     ok( !strcmp(buffer,"s64"), "_Tables has wrong column type\n");
1083     r = MsiCloseHandle( rec );
1084     ok( r == ERROR_SUCCESS, "failed to close record handle\n");
1085
1086     /* check that invalid values fail */
1087     rec = 0;
1088     r = MsiViewGetColumnInfo( hview, 100, &rec );
1089     ok( r == ERROR_INVALID_PARAMETER, "wrong error code\n");
1090     ok( rec == 0, "returned a record\n");
1091
1092     r = MsiViewGetColumnInfo( hview, MSICOLINFO_TYPES, NULL );
1093     ok( r == ERROR_INVALID_PARAMETER, "wrong error code\n");
1094
1095     r = MsiViewGetColumnInfo( 0, MSICOLINFO_TYPES, &rec );
1096     ok( r == ERROR_INVALID_HANDLE, "wrong error code\n");
1097
1098     r = MsiViewClose(hview);
1099     ok( r == ERROR_SUCCESS, "failed to close view\n");
1100     r = MsiCloseHandle(hview);
1101     ok( r == ERROR_SUCCESS, "failed to close view handle\n");
1102     r = MsiCloseHandle(hdb);
1103     ok( r == ERROR_SUCCESS, "failed to close database\n");
1104 }
1105
1106 static MSIHANDLE get_column_info(MSIHANDLE hdb, const char *query, MSICOLINFO type)
1107 {
1108     MSIHANDLE hview = 0, rec = 0;
1109     UINT r;
1110
1111     r = MsiDatabaseOpenView(hdb, query, &hview);
1112     if( r != ERROR_SUCCESS )
1113         return r;
1114
1115     r = MsiViewExecute(hview, 0);
1116     if( r == ERROR_SUCCESS )
1117     {
1118         MsiViewGetColumnInfo( hview, type, &rec );
1119         MsiViewClose(hview);
1120     }
1121     MsiCloseHandle(hview);
1122     return rec;
1123 }
1124
1125 static UINT get_columns_table_type(MSIHANDLE hdb, const char *table, UINT field)
1126 {
1127     MSIHANDLE hview = 0, rec = 0;
1128     UINT r, type = 0;
1129     char query[0x100];
1130
1131     sprintf(query, "select * from `_Columns` where  `Table` = '%s'", table );
1132
1133     r = MsiDatabaseOpenView(hdb, query, &hview);
1134     if( r != ERROR_SUCCESS )
1135         return r;
1136
1137     r = MsiViewExecute(hview, 0);
1138     if( r == ERROR_SUCCESS )
1139     {
1140         while (1)
1141         {
1142             r = MsiViewFetch( hview, &rec );
1143             if( r != ERROR_SUCCESS)
1144                 break;
1145             r = MsiRecordGetInteger( rec, 2 );
1146             if (r == field)
1147                 type = MsiRecordGetInteger( rec, 4 );
1148             MsiCloseHandle( rec );
1149         }
1150
1151         MsiViewClose(hview);
1152     }
1153     MsiCloseHandle(hview);
1154     return type;
1155 }
1156
1157 static BOOL check_record( MSIHANDLE rec, UINT field, LPCSTR val )
1158 {
1159     CHAR buffer[0x20];
1160     UINT r;
1161     DWORD sz;
1162
1163     sz = sizeof buffer;
1164     r = MsiRecordGetString( rec, field, buffer, &sz );
1165     return (r == ERROR_SUCCESS ) && !strcmp(val, buffer);
1166 }
1167
1168 static void test_viewgetcolumninfo(void)
1169 {
1170     MSIHANDLE hdb = 0, rec;
1171     UINT r;
1172
1173     hdb = create_db();
1174     ok( hdb, "failed to create db\n");
1175
1176     r = run_query( hdb, 0,
1177             "CREATE TABLE `Properties` "
1178             "( `Property` CHAR(255), `Value` CHAR(1)  PRIMARY KEY `Property`)" );
1179     ok( r == ERROR_SUCCESS , "Failed to create table\n" );
1180
1181     /* check the column types */
1182     rec = get_column_info( hdb, "select * from `Properties`", MSICOLINFO_TYPES );
1183     ok( rec, "failed to get column info record\n" );
1184
1185     ok( check_record( rec, 1, "S255"), "wrong record type\n");
1186     ok( check_record( rec, 2, "S1"), "wrong record type\n");
1187
1188     MsiCloseHandle( rec );
1189
1190     /* check the type in _Columns */
1191     ok( 0x3dff == get_columns_table_type(hdb, "Properties", 1 ), "_columns table wrong\n");
1192     ok( 0x1d01 == get_columns_table_type(hdb, "Properties", 2 ), "_columns table wrong\n");
1193
1194     /* now try the names */
1195     rec = get_column_info( hdb, "select * from `Properties`", MSICOLINFO_NAMES );
1196     ok( rec, "failed to get column info record\n" );
1197
1198     ok( check_record( rec, 1, "Property"), "wrong record type\n");
1199     ok( check_record( rec, 2, "Value"), "wrong record type\n");
1200
1201     MsiCloseHandle( rec );
1202
1203     r = run_query( hdb, 0,
1204             "CREATE TABLE `Binary` "
1205             "( `Name` CHAR(255), `Data` OBJECT  PRIMARY KEY `Name`)" );
1206     ok( r == ERROR_SUCCESS , "Failed to create table\n" );
1207
1208     /* check the column types */
1209     rec = get_column_info( hdb, "select * from `Binary`", MSICOLINFO_TYPES );
1210     ok( rec, "failed to get column info record\n" );
1211
1212     ok( check_record( rec, 1, "S255"), "wrong record type\n");
1213     ok( check_record( rec, 2, "V0"), "wrong record type\n");
1214
1215     MsiCloseHandle( rec );
1216
1217     /* check the type in _Columns */
1218     ok( 0x3dff == get_columns_table_type(hdb, "Binary", 1 ), "_columns table wrong\n");
1219     ok( 0x1900 == get_columns_table_type(hdb, "Binary", 2 ), "_columns table wrong\n");
1220
1221     /* now try the names */
1222     rec = get_column_info( hdb, "select * from `Binary`", MSICOLINFO_NAMES );
1223     ok( rec, "failed to get column info record\n" );
1224
1225     ok( check_record( rec, 1, "Name"), "wrong record type\n");
1226     ok( check_record( rec, 2, "Data"), "wrong record type\n");
1227     MsiCloseHandle( rec );
1228
1229     r = run_query( hdb, 0,
1230             "CREATE TABLE `UIText` "
1231             "( `Key` CHAR(72) NOT NULL, `Text` CHAR(255) LOCALIZABLE PRIMARY KEY `Key`)" );
1232     ok( r == ERROR_SUCCESS , "Failed to create table\n" );
1233
1234     ok( 0x2d48 == get_columns_table_type(hdb, "UIText", 1 ), "_columns table wrong\n");
1235     ok( 0x1fff == get_columns_table_type(hdb, "UIText", 2 ), "_columns table wrong\n");
1236
1237     rec = get_column_info( hdb, "select * from `UIText`", MSICOLINFO_NAMES );
1238     ok( rec, "failed to get column info record\n" );
1239     ok( check_record( rec, 1, "Key"), "wrong record type\n");
1240     ok( check_record( rec, 2, "Text"), "wrong record type\n");
1241     MsiCloseHandle( rec );
1242
1243     rec = get_column_info( hdb, "select * from `UIText`", MSICOLINFO_TYPES );
1244     ok( rec, "failed to get column info record\n" );
1245     ok( check_record( rec, 1, "s72"), "wrong record type\n");
1246     ok( check_record( rec, 2, "L255"), "wrong record type\n");
1247     MsiCloseHandle( rec );
1248
1249     MsiCloseHandle( hdb );
1250 }
1251
1252 static void test_msiexport(void)
1253 {
1254     MSIHANDLE hdb = 0, hview = 0;
1255     UINT r;
1256     const char *query;
1257     char path[MAX_PATH];
1258     const char file[] = "phone.txt";
1259     HANDLE handle;
1260     char buffer[0x100];
1261     DWORD length;
1262     const char expected[] =
1263         "id\tname\tnumber\r\n"
1264         "I2\tS32\tS32\r\n"
1265         "phone\tid\r\n"
1266         "1\tAbe\t8675309\r\n";
1267
1268     DeleteFile(msifile);
1269
1270     /* just MsiOpenDatabase should not create a file */
1271     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
1272     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
1273
1274     /* create a table */
1275     query = "CREATE TABLE `phone` ( "
1276             "`id` INT, `name` CHAR(32), `number` CHAR(32) "
1277             "PRIMARY KEY `id`)";
1278     r = MsiDatabaseOpenView(hdb, query, &hview);
1279     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
1280     r = MsiViewExecute(hview, 0);
1281     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
1282     r = MsiViewClose(hview);
1283     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
1284     r = MsiCloseHandle(hview);
1285     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
1286
1287     /* insert a value into it */
1288     query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
1289         "VALUES('1', 'Abe', '8675309')";
1290     r = MsiDatabaseOpenView(hdb, query, &hview);
1291     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
1292     r = MsiViewExecute(hview, 0);
1293     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
1294     r = MsiViewClose(hview);
1295     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
1296     r = MsiCloseHandle(hview);
1297     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
1298
1299     GetCurrentDirectory(MAX_PATH, path);
1300
1301     r = MsiDatabaseExport(hdb, "phone", path, file);
1302     ok(r == ERROR_SUCCESS, "MsiDatabaseExport failed\n");
1303
1304     MsiCloseHandle(hdb);
1305
1306     lstrcat(path, "\\");
1307     lstrcat(path, file);
1308
1309     /* check the data that was written */
1310     length = 0;
1311     memset(buffer, 0, sizeof buffer);
1312     handle = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
1313     if (handle != INVALID_HANDLE_VALUE)
1314     {
1315         ReadFile(handle, buffer, sizeof buffer, &length, NULL);
1316         CloseHandle(handle);
1317         DeleteFile(path);
1318     }
1319     else
1320         ok(0, "failed to open file %s\n", path);
1321
1322     ok( length == strlen(expected), "length of data wrong\n");
1323     ok( !lstrcmp(buffer, expected), "data doesn't match\n");
1324     DeleteFile(msifile);
1325 }
1326
1327 static void test_longstrings(void)
1328 {
1329     const char insert_query[] = 
1330         "INSERT INTO `strings` ( `id`, `val` ) VALUES('1', 'Z')";
1331     char *str;
1332     MSIHANDLE hdb = 0, hview = 0, hrec = 0;
1333     DWORD len;
1334     UINT r;
1335     const DWORD STRING_LENGTH = 0x10005;
1336
1337     DeleteFile(msifile);
1338     /* just MsiOpenDatabase should not create a file */
1339     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
1340     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
1341
1342     /* create a table */
1343     r = try_query( hdb, 
1344         "CREATE TABLE `strings` ( `id` INT, `val` CHAR(0) PRIMARY KEY `id`)");
1345     ok(r == ERROR_SUCCESS, "query failed\n");
1346
1347     /* try a insert a very long string */
1348     str = HeapAlloc(GetProcessHeap(), 0, STRING_LENGTH+sizeof insert_query);
1349     len = strchr(insert_query, 'Z') - insert_query;
1350     strcpy(str, insert_query);
1351     memset(str+len, 'Z', STRING_LENGTH);
1352     strcpy(str+len+STRING_LENGTH, insert_query+len+1);
1353     r = try_query( hdb, str );
1354     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
1355
1356     HeapFree(GetProcessHeap(), 0, str);
1357
1358     MsiDatabaseCommit(hdb);
1359     ok(r == ERROR_SUCCESS, "MsiDatabaseCommit failed\n");
1360     MsiCloseHandle(hdb);
1361
1362     r = MsiOpenDatabase(msifile, MSIDBOPEN_READONLY, &hdb);
1363     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
1364
1365     r = MsiDatabaseOpenView(hdb, "select * from `strings` where `id` = 1", &hview);
1366     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
1367
1368     r = MsiViewExecute(hview, 0);
1369     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
1370
1371     r = MsiViewFetch(hview, &hrec);
1372     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
1373
1374     MsiCloseHandle(hview);
1375
1376     r = MsiRecordGetString(hrec, 2, NULL, &len);
1377     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
1378     ok(len == STRING_LENGTH, "string length wrong\n");
1379
1380     MsiCloseHandle(hrec);
1381     MsiCloseHandle(hdb);
1382     DeleteFile(msifile);
1383 }
1384
1385 static void create_file(const CHAR *name)
1386 {
1387     HANDLE file;
1388     DWORD written;
1389
1390     file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
1391     ok(file != INVALID_HANDLE_VALUE, "Failure to open file %s\n", name);
1392     WriteFile(file, name, strlen(name), &written, NULL);
1393     WriteFile(file, "\n", strlen("\n"), &written, NULL);
1394     CloseHandle(file);
1395 }
1396  
1397 static void test_streamtable(void)
1398 {
1399     MSIHANDLE hdb = 0, rec, view;
1400     char file[MAX_PATH];
1401     char buf[MAX_PATH];
1402     DWORD size;
1403     UINT r;
1404
1405     hdb = create_db();
1406     ok( hdb, "failed to create db\n");
1407
1408     r = run_query( hdb, 0,
1409             "CREATE TABLE `Properties` "
1410             "( `Property` CHAR(255), `Value` CHAR(1)  PRIMARY KEY `Property`)" );
1411     ok( r == ERROR_SUCCESS , "Failed to create table\n" );
1412
1413     r = run_query( hdb, 0,
1414             "INSERT INTO `Properties` "
1415             "( `Value`, `Property` ) VALUES ( 'Prop', 'value' )" );
1416     ok( r == ERROR_SUCCESS, "Failed to add to table\n" );
1417
1418     r = MsiDatabaseCommit( hdb );
1419     ok( r == ERROR_SUCCESS , "Failed to commit database\n" );
1420
1421     MsiCloseHandle( hdb );
1422
1423     r = MsiOpenDatabase(msifile, MSIDBOPEN_TRANSACT, &hdb );
1424     ok( r == ERROR_SUCCESS , "Failed to open database\n" );
1425
1426     /* check the column types */
1427     rec = get_column_info( hdb, "select * from `_Streams`", MSICOLINFO_TYPES );
1428     ok( rec, "failed to get column info record\n" );
1429
1430     ok( check_record( rec, 1, "s62"), "wrong record type\n");
1431     ok( check_record( rec, 2, "V0"), "wrong record type\n");
1432
1433     MsiCloseHandle( rec );
1434
1435     /* now try the names */
1436     rec = get_column_info( hdb, "select * from `_Streams`", MSICOLINFO_NAMES );
1437     ok( rec, "failed to get column info record\n" );
1438
1439     ok( check_record( rec, 1, "Name"), "wrong record type\n");
1440     ok( check_record( rec, 2, "Data"), "wrong record type\n");
1441
1442     MsiCloseHandle( rec );
1443
1444     /* insert a file into the _Streams table */
1445     create_file( "test.txt" );
1446
1447     rec = MsiCreateRecord( 2 );
1448     MsiRecordSetString( rec, 1, "data" );
1449
1450     r = MsiRecordSetStream( rec, 2, "test.txt" );
1451     ok( r == ERROR_SUCCESS, "Failed to add stream data to the record: %d\n", r);
1452
1453     DeleteFile("test.txt");
1454
1455     r = MsiDatabaseOpenView( hdb,
1456             "INSERT INTO `_Streams` ( `Name`, `Data` ) VALUES ( ?, ? )", &view );
1457     ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r);
1458
1459     r = MsiViewExecute( view, rec );
1460     ok( r == ERROR_SUCCESS, "Failed to execute view: %d\n", r);
1461
1462     MsiCloseHandle( rec );
1463     MsiCloseHandle( view );
1464
1465     r = MsiDatabaseOpenView( hdb,
1466             "SELECT `Name`, `Data` FROM `_Streams`", &view );
1467     ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r);
1468
1469     r = MsiViewExecute( view, 0 );
1470     ok( r == ERROR_SUCCESS, "Failed to execute view: %d\n", r);
1471
1472     r = MsiViewFetch( view, &rec );
1473     ok( r == ERROR_SUCCESS, "Failed to fetch record: %d\n", r);
1474
1475     size = MAX_PATH;
1476     r = MsiRecordGetString( rec, 1, file, &size );
1477     ok( r == ERROR_SUCCESS, "Failed to get string: %d\n", r);
1478     ok( !lstrcmp(file, "data"), "Expected 'data', got %s\n", file);
1479
1480     size = MAX_PATH;
1481     memset(buf, 0, MAX_PATH);
1482     r = MsiRecordReadStream( rec, 2, buf, &size );
1483     ok( r == ERROR_SUCCESS, "Failed to get stream: %d\n", r);
1484     ok( !lstrcmp(buf, "test.txt\n"), "Expected 'test.txt\\n', got %s\n", buf);
1485
1486     MsiCloseHandle( rec );
1487
1488     r = MsiViewFetch( view, &rec );
1489     ok( r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
1490
1491     MsiCloseHandle( view );
1492     MsiCloseHandle( hdb );
1493     DeleteFile(msifile);
1494 }
1495
1496 static void test_where(void)
1497 {
1498     MSIHANDLE hdb = 0, rec, view;
1499     LPCSTR query;
1500     UINT r;
1501     DWORD size;
1502     CHAR buf[MAX_PATH];
1503     UINT count;
1504
1505     hdb = create_db();
1506     ok( hdb, "failed to create db\n");
1507
1508     r = run_query( hdb, 0,
1509             "CREATE TABLE `Media` ("
1510             "`DiskId` SHORT NOT NULL, "
1511             "`LastSequence` LONG, "
1512             "`DiskPrompt` CHAR(64) LOCALIZABLE, "
1513             "`Cabinet` CHAR(255), "
1514             "`VolumeLabel` CHAR(32), "
1515             "`Source` CHAR(72) "
1516             "PRIMARY KEY `DiskId`)" );
1517     ok( r == S_OK, "cannot create Media table: %d\n", r );
1518
1519     r = run_query( hdb, 0, "INSERT INTO `Media` "
1520             "( `DiskId`, `LastSequence`, `DiskPrompt`, `Cabinet`, `VolumeLabel`, `Source` ) "
1521             "VALUES ( 1, 0, '', 'zero.cab', '', '' )" );
1522     ok( r == S_OK, "cannot add file to the Media table: %d\n", r );
1523
1524     r = run_query( hdb, 0, "INSERT INTO `Media` "
1525             "( `DiskId`, `LastSequence`, `DiskPrompt`, `Cabinet`, `VolumeLabel`, `Source` ) "
1526             "VALUES ( 2, 1, '', 'one.cab', '', '' )" );
1527     ok( r == S_OK, "cannot add file to the Media table: %d\n", r );
1528
1529     r = run_query( hdb, 0, "INSERT INTO `Media` "
1530             "( `DiskId`, `LastSequence`, `DiskPrompt`, `Cabinet`, `VolumeLabel`, `Source` ) "
1531             "VALUES ( 3, 2, '', 'two.cab', '', '' )" );
1532     ok( r == S_OK, "cannot add file to the Media table: %d\n", r );
1533
1534     query = "SELECT * FROM `Media`";
1535     r = do_query(hdb, query, &rec);
1536     ok(r == ERROR_SUCCESS, "MsiViewFetch failed: %d\n", r);
1537     ok( check_record( rec, 4, "zero.cab"), "wrong cabinet\n");
1538     MsiCloseHandle( rec );
1539
1540     query = "SELECT * FROM `Media` WHERE `LastSequence` >= 1";
1541     r = do_query(hdb, query, &rec);
1542     ok(r == ERROR_SUCCESS, "MsiViewFetch failed: %d\n", r);
1543     ok( check_record( rec, 4, "one.cab"), "wrong cabinet\n");
1544
1545     r = MsiRecordGetInteger(rec, 1);
1546     ok( 2 == r, "field wrong\n");
1547     r = MsiRecordGetInteger(rec, 2);
1548     ok( 1 == r, "field wrong\n");
1549     MsiCloseHandle( rec );
1550
1551     query = "SELECT `DiskId` FROM `Media` WHERE `LastSequence` >= 1 AND DiskId >= 0";
1552     r = MsiDatabaseOpenView(hdb, query, &view);
1553     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
1554
1555     r = MsiViewExecute(view, 0);
1556     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
1557
1558     r = MsiViewFetch(view, &rec);
1559     ok( r == ERROR_SUCCESS, "failed to fetch view: %d\n", r );
1560
1561     count = MsiRecordGetFieldCount( rec );
1562     ok( count == 1, "Expected 1 record fields, got %d\n", count );
1563
1564     size = MAX_PATH;
1565     r = MsiRecordGetString( rec, 1, buf, &size );
1566     ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
1567     ok( !lstrcmp( buf, "2" ),
1568         "For (row %d, column 1) expected '%d', got %s\n", 0, 2, buf );
1569     MsiCloseHandle( rec );
1570
1571     r = MsiViewFetch(view, &rec);
1572     ok( r == ERROR_SUCCESS, "failed to fetch view: %d\n", r );
1573
1574     size = MAX_PATH;
1575     r = MsiRecordGetString( rec, 1, buf, &size );
1576     ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
1577     ok( !lstrcmp( buf, "3" ),
1578         "For (row %d, column 1) expected '%d', got %s\n", 1, 3, buf );
1579     MsiCloseHandle( rec );
1580
1581     r = MsiViewFetch(view, &rec);
1582     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
1583
1584     MsiViewClose(view);
1585     MsiCloseHandle(view);
1586
1587     MsiCloseHandle( rec );
1588
1589     rec = 0;
1590     query = "SELECT * FROM `Media` WHERE `DiskPrompt` IS NULL";
1591     r = do_query(hdb, query, &rec);
1592     ok( r == ERROR_SUCCESS, "query failed: %d\n", r );
1593     MsiCloseHandle( rec );
1594
1595     rec = MsiCreateRecord(1);
1596     MsiRecordSetString(rec, 1, "");
1597
1598     query = "SELECT * FROM `Media` WHERE `DiskPrompt` = ?";
1599     r = MsiDatabaseOpenView(hdb, query, &view);
1600     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1601     r = MsiViewExecute(view, rec);
1602     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1603
1604     MsiCloseHandle(rec);
1605
1606     r = MsiViewFetch(view, &rec);
1607     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1608
1609     MsiCloseHandle(rec);
1610     MsiViewClose(view);
1611     MsiCloseHandle(view);
1612
1613     MsiCloseHandle( hdb );
1614     DeleteFile(msifile);
1615 }
1616
1617 static CHAR CURR_DIR[MAX_PATH];
1618
1619 static const CHAR test_data[] = "FirstPrimaryColumn\tSecondPrimaryColumn\tShortInt\tShortIntNullable\tLongInt\tLongIntNullable\tString\tLocalizableString\tLocalizableStringNullable\n"
1620                                 "s255\ti2\ti2\tI2\ti4\tI4\tS255\tS0\ts0\n"
1621                                 "TestTable\tFirstPrimaryColumn\n"
1622                                 "stringage\t5\t2\t\t2147483640\t-2147483640\tanother string\tlocalizable\tduh\n";
1623
1624 static const CHAR two_primary[] = "PrimaryOne\tPrimaryTwo\n"
1625                                   "s255\ts255\n"
1626                                   "TwoPrimary\tPrimaryOne\tPrimaryTwo\n"
1627                                   "papaya\tleaf\n"
1628                                   "papaya\tflower\n";
1629
1630 static const CHAR endlines1[] = "A\tB\tC\tD\tE\tF\r\n"
1631                                 "s72\ts72\ts72\ts72\ts72\ts72\n"
1632                                 "Table\tA\r\n"
1633                                 "a\tb\tc\td\te\tf\n"
1634                                 "g\th\ti\t\rj\tk\tl\r\n";
1635
1636 static const CHAR endlines2[] = "A\tB\tC\tD\tE\tF\r"
1637                                 "s72\ts72\ts72\ts72\ts72\ts72\n"
1638                                 "Table2\tA\r\n"
1639                                 "a\tb\tc\td\te\tf\n"
1640                                 "g\th\ti\tj\tk\tl\r\n";
1641
1642 static void write_file(const CHAR *filename, const char *data, int data_size)
1643 {
1644     DWORD size;
1645
1646     HANDLE hf = CreateFile(filename, GENERIC_WRITE, 0, NULL,
1647                            CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1648
1649     WriteFile(hf, data, data_size, &size, NULL);
1650     CloseHandle(hf);
1651 }
1652
1653 static UINT add_table_to_db(MSIHANDLE hdb, LPCSTR table_data)
1654 {
1655     UINT r;
1656
1657     write_file("temp_file", table_data, (lstrlen(table_data) - 1) * sizeof(char));
1658     r = MsiDatabaseImportA(hdb, CURR_DIR, "temp_file");
1659     DeleteFileA("temp_file");
1660
1661     return r;
1662 }
1663
1664 static void test_msiimport(void)
1665 {
1666     MSIHANDLE hdb, view, rec;
1667     LPCSTR query;
1668     UINT r, count;
1669     signed int i;
1670
1671     GetCurrentDirectoryA(MAX_PATH, CURR_DIR);
1672
1673     r = MsiOpenDatabaseA(msifile, MSIDBOPEN_CREATE, &hdb);
1674     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1675
1676     r = add_table_to_db(hdb, test_data);
1677     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1678
1679     r = add_table_to_db(hdb, two_primary);
1680     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1681
1682     r = add_table_to_db(hdb, endlines1);
1683     if (r == ERROR_FUNCTION_FAILED)
1684     {
1685         /* win9x doesn't handle this case */
1686         skip("endlines not handled correctly.\n");
1687         MsiCloseHandle(hdb);
1688         DeleteFileA(msifile);
1689         return;
1690     }
1691
1692     r = add_table_to_db(hdb, endlines2);
1693     ok(r == ERROR_FUNCTION_FAILED,
1694        "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
1695
1696     query = "SELECT * FROM `TestTable`";
1697     r = MsiDatabaseOpenView(hdb, query, &view);
1698     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1699
1700     r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec);
1701     count = MsiRecordGetFieldCount(rec);
1702     ok(count == 9, "Expected 9, got %d\n", count);
1703     ok(check_record(rec, 1, "FirstPrimaryColumn"), "Expected FirstPrimaryColumn\n");
1704     ok(check_record(rec, 2, "SecondPrimaryColumn"), "Expected SecondPrimaryColumn\n");
1705     ok(check_record(rec, 3, "ShortInt"), "Expected ShortInt\n");
1706     ok(check_record(rec, 4, "ShortIntNullable"), "Expected ShortIntNullalble\n");
1707     ok(check_record(rec, 5, "LongInt"), "Expected LongInt\n");
1708     ok(check_record(rec, 6, "LongIntNullable"), "Expected LongIntNullalble\n");
1709     ok(check_record(rec, 7, "String"), "Expected String\n");
1710     ok(check_record(rec, 8, "LocalizableString"), "Expected LocalizableString\n");
1711     ok(check_record(rec, 9, "LocalizableStringNullable"), "Expected LocalizableStringNullable\n");
1712     MsiCloseHandle(rec);
1713
1714     r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
1715     count = MsiRecordGetFieldCount(rec);
1716     ok(count == 9, "Expected 9, got %d\n", count);
1717     ok(check_record(rec, 1, "s255"), "Expected s255\n");
1718     ok(check_record(rec, 2, "i2"), "Expected i2\n");
1719     ok(check_record(rec, 3, "i2"), "Expected i2\n");
1720     ok(check_record(rec, 4, "I2"), "Expected I2\n");
1721     ok(check_record(rec, 5, "i4"), "Expected i4\n");
1722     ok(check_record(rec, 6, "I4"), "Expected I4\n");
1723     ok(check_record(rec, 7, "S255"), "Expected S255\n");
1724     ok(check_record(rec, 8, "S0"), "Expected S0\n");
1725     ok(check_record(rec, 9, "s0"), "Expected s0\n");
1726     MsiCloseHandle(rec);
1727
1728     query = "SELECT * FROM `TestTable`";
1729     r = do_query(hdb, query, &rec);
1730     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1731     ok(check_record(rec, 1, "stringage"), "Expected 'stringage'\n");
1732     ok(check_record(rec, 7, "another string"), "Expected 'another string'\n");
1733     ok(check_record(rec, 8, "localizable"), "Expected 'localizable'\n");
1734     ok(check_record(rec, 9, "duh"), "Expected 'duh'\n");
1735
1736     i = MsiRecordGetInteger(rec, 2);
1737     ok(i == 5, "Expected 5, got %d\n", i);
1738
1739     i = MsiRecordGetInteger(rec, 3);
1740     ok(i == 2, "Expected 2, got %d\n", i);
1741
1742     i = MsiRecordGetInteger(rec, 4);
1743     ok(i == MSI_NULL_INTEGER, "Expected MSI_NULL_INTEGER, got %d\n", i);
1744
1745     i = MsiRecordGetInteger(rec, 5);
1746     ok(i == 2147483640, "Expected 2147483640, got %d\n", i);
1747
1748     i = MsiRecordGetInteger(rec, 6);
1749     ok(i == -2147483640, "Expected -2147483640, got %d\n", i);
1750
1751     MsiCloseHandle(rec);
1752     MsiCloseHandle(view);
1753
1754     query = "SELECT * FROM `TwoPrimary`";
1755     r = MsiDatabaseOpenView(hdb, query, &view);
1756     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1757
1758     r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec);
1759     count = MsiRecordGetFieldCount(rec);
1760     ok(count == 2, "Expected 2, got %d\n", count);
1761     ok(check_record(rec, 1, "PrimaryOne"), "Expected PrimaryOne\n");
1762     ok(check_record(rec, 2, "PrimaryTwo"), "Expected PrimaryTwo\n");
1763
1764     MsiCloseHandle(rec);
1765
1766     r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
1767     count = MsiRecordGetFieldCount(rec);
1768     ok(count == 2, "Expected 2, got %d\n", count);
1769     ok(check_record(rec, 1, "s255"), "Expected s255\n");
1770     ok(check_record(rec, 2, "s255"), "Expected s255\n");
1771     MsiCloseHandle(rec);
1772
1773     r = MsiViewExecute(view, 0);
1774     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1775
1776     r = MsiViewFetch(view, &rec);
1777     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1778
1779     ok(check_record(rec, 1, "papaya"), "Expected 'papaya'\n");
1780     ok(check_record(rec, 2, "leaf"), "Expected 'leaf'\n");
1781
1782     MsiCloseHandle(rec);
1783
1784     r = MsiViewFetch(view, &rec);
1785     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1786
1787     ok(check_record(rec, 1, "papaya"), "Expected 'papaya'\n");
1788     ok(check_record(rec, 2, "flower"), "Expected 'flower'\n");
1789
1790     MsiCloseHandle(rec);
1791
1792     r = MsiViewFetch(view, &rec);
1793     ok(r == ERROR_NO_MORE_ITEMS,
1794        "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
1795
1796     r = MsiViewClose(view);
1797     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1798
1799     MsiCloseHandle(view);
1800
1801     query = "SELECT * FROM `Table`";
1802     r = MsiDatabaseOpenView(hdb, query, &view);
1803     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1804
1805     r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec);
1806     count = MsiRecordGetFieldCount(rec);
1807     ok(count == 6, "Expected 6, got %d\n", count);
1808     ok(check_record(rec, 1, "A"), "Expected A\n");
1809     ok(check_record(rec, 2, "B"), "Expected B\n");
1810     ok(check_record(rec, 3, "C"), "Expected C\n");
1811     ok(check_record(rec, 4, "D"), "Expected D\n");
1812     ok(check_record(rec, 5, "E"), "Expected E\n");
1813     ok(check_record(rec, 6, "F"), "Expected F\n");
1814     MsiCloseHandle(rec);
1815
1816     r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
1817     count = MsiRecordGetFieldCount(rec);
1818     ok(count == 6, "Expected 6, got %d\n", count);
1819     ok(check_record(rec, 1, "s72"), "Expected s72\n");
1820     ok(check_record(rec, 2, "s72"), "Expected s72\n");
1821     ok(check_record(rec, 3, "s72"), "Expected s72\n");
1822     ok(check_record(rec, 4, "s72"), "Expected s72\n");
1823     ok(check_record(rec, 5, "s72"), "Expected s72\n");
1824     ok(check_record(rec, 6, "s72"), "Expected s72\n");
1825     MsiCloseHandle(rec);
1826
1827     MsiViewClose(view);
1828     MsiCloseHandle(view);
1829
1830     query = "SELECT * FROM `Table`";
1831     r = MsiDatabaseOpenView(hdb, query, &view);
1832     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1833
1834     r = MsiViewExecute(view, 0);
1835     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1836
1837     r = MsiViewFetch(view, &rec);
1838     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1839     ok(check_record(rec, 1, "a"), "Expected 'a'\n");
1840     ok(check_record(rec, 2, "b"), "Expected 'b'\n");
1841     ok(check_record(rec, 3, "c"), "Expected 'c'\n");
1842     ok(check_record(rec, 4, "d"), "Expected 'd'\n");
1843     ok(check_record(rec, 5, "e"), "Expected 'e'\n");
1844     ok(check_record(rec, 6, "f"), "Expected 'f'\n");
1845
1846     MsiCloseHandle(rec);
1847
1848     r = MsiViewFetch(view, &rec);
1849     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1850     ok(check_record(rec, 1, "g"), "Expected 'g'\n");
1851     ok(check_record(rec, 2, "h"), "Expected 'h'\n");
1852     ok(check_record(rec, 3, "i"), "Expected 'i'\n");
1853     ok(check_record(rec, 4, "j"), "Expected 'j'\n");
1854     ok(check_record(rec, 5, "k"), "Expected 'k'\n");
1855     ok(check_record(rec, 6, "l"), "Expected 'l'\n");
1856
1857     MsiCloseHandle(rec);
1858
1859     r = MsiViewFetch(view, &rec);
1860     ok(r == ERROR_NO_MORE_ITEMS,
1861        "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
1862
1863     MsiViewClose(view);
1864     MsiCloseHandle(view);
1865     MsiCloseHandle(hdb);
1866     DeleteFileA(msifile);
1867 }
1868
1869 static void test_markers(void)
1870 {
1871     MSIHANDLE hdb, rec;
1872     LPCSTR query;
1873     UINT r;
1874
1875     hdb = create_db();
1876     ok( hdb, "failed to create db\n");
1877
1878     rec = MsiCreateRecord(3);
1879     MsiRecordSetString(rec, 1, "Table");
1880     MsiRecordSetString(rec, 2, "Apples");
1881     MsiRecordSetString(rec, 3, "Oranges");
1882
1883     /* try a legit create */
1884     query = "CREATE TABLE `Table` ( `One` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`)";
1885     r = run_query(hdb, 0, query);
1886     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1887     MsiCloseHandle(rec);
1888
1889     /* try table name as marker */
1890     rec = MsiCreateRecord(1);
1891     MsiRecordSetString(rec, 1, "Fable");
1892     query = "CREATE TABLE `?` ( `One` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`)";
1893     r = run_query(hdb, rec, query);
1894     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1895
1896     /* verify that we just created a table called '?', not 'Fable' */
1897     r = try_query(hdb, "SELECT * from `Fable`");
1898     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
1899
1900     r = try_query(hdb, "SELECT * from `?`");
1901     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1902
1903     /* try table name as marker without backticks */
1904     MsiRecordSetString(rec, 1, "Mable");
1905     query = "CREATE TABLE ? ( `One` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`)";
1906     r = run_query(hdb, rec, query);
1907     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
1908
1909     /* try one column name as marker */
1910     MsiRecordSetString(rec, 1, "One");
1911     query = "CREATE TABLE `Mable` ( `?` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`)";
1912     r = run_query(hdb, rec, query);
1913     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
1914     MsiCloseHandle(rec);
1915
1916     /* try column names as markers */
1917     rec = MsiCreateRecord(2);
1918     MsiRecordSetString(rec, 1, "One");
1919     MsiRecordSetString(rec, 2, "Two");
1920     query = "CREATE TABLE `Mable` ( `?` SHORT NOT NULL, `?` CHAR(255) PRIMARY KEY `One`)";
1921     r = run_query(hdb, rec, query);
1922     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
1923     MsiCloseHandle(rec);
1924
1925     /* try names with backticks */
1926     rec = MsiCreateRecord(3);
1927     MsiRecordSetString(rec, 1, "One");
1928     MsiRecordSetString(rec, 2, "Two");
1929     MsiRecordSetString(rec, 3, "One");
1930     query = "CREATE TABLE `Mable` ( `?` SHORT NOT NULL, `?` CHAR(255) PRIMARY KEY `?`)";
1931     r = run_query(hdb, rec, query);
1932     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
1933
1934     /* try names with backticks, minus definitions */
1935     query = "CREATE TABLE `Mable` ( `?`, `?` PRIMARY KEY `?`)";
1936     r = run_query(hdb, rec, query);
1937     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
1938
1939     /* try names without backticks */
1940     query = "CREATE TABLE `Mable` ( ? SHORT NOT NULL, ? CHAR(255) PRIMARY KEY ?)";
1941     r = run_query(hdb, rec, query);
1942     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
1943     MsiCloseHandle(rec);
1944
1945     /* try one long marker */
1946     rec = MsiCreateRecord(1);
1947     MsiRecordSetString(rec, 1, "`One` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`");
1948     query = "CREATE TABLE `Mable` ( ? )";
1949     r = run_query(hdb, rec, query);
1950     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
1951     MsiCloseHandle(rec);
1952
1953     /* try all names as markers */
1954     rec = MsiCreateRecord(4);
1955     MsiRecordSetString(rec, 1, "Mable");
1956     MsiRecordSetString(rec, 2, "One");
1957     MsiRecordSetString(rec, 3, "Two");
1958     MsiRecordSetString(rec, 4, "One");
1959     query = "CREATE TABLE `?` ( `?` SHORT NOT NULL, `?` CHAR(255) PRIMARY KEY `?`)";
1960     r = run_query(hdb, rec, query);
1961     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
1962     MsiCloseHandle(rec);
1963
1964     /* try a legit insert */
1965     query = "INSERT INTO `Table` ( `One`, `Two` ) VALUES ( 5, 'hello' )";
1966     r = run_query(hdb, 0, query);
1967     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1968
1969     r = try_query(hdb, "SELECT * from `Table`");
1970     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1971
1972     /* try values as markers */
1973     rec = MsiCreateRecord(2);
1974     MsiRecordSetInteger(rec, 1, 4);
1975     MsiRecordSetString(rec, 2, "hi");
1976     query = "INSERT INTO `Table` ( `One`, `Two` ) VALUES ( ?, '?' )";
1977     r = run_query(hdb, rec, query);
1978     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1979     MsiCloseHandle(rec);
1980
1981     /* try column names and values as markers */
1982     rec = MsiCreateRecord(4);
1983     MsiRecordSetString(rec, 1, "One");
1984     MsiRecordSetString(rec, 2, "Two");
1985     MsiRecordSetInteger(rec, 3, 5);
1986     MsiRecordSetString(rec, 4, "hi");
1987     query = "INSERT INTO `Table` ( `?`, `?` ) VALUES ( ?, '?' )";
1988     r = run_query(hdb, rec, query);
1989     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
1990     MsiCloseHandle(rec);
1991
1992     /* try column names as markers */
1993     rec = MsiCreateRecord(2);
1994     MsiRecordSetString(rec, 1, "One");
1995     MsiRecordSetString(rec, 2, "Two");
1996     query = "INSERT INTO `Table` ( `?`, `?` ) VALUES ( 3, 'yellow' )";
1997     r = run_query(hdb, rec, query);
1998     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
1999     MsiCloseHandle(rec);
2000
2001     /* try table name as a marker */
2002     rec = MsiCreateRecord(1);
2003     MsiRecordSetString(rec, 1, "Table");
2004     query = "INSERT INTO `?` ( `One`, `Two` ) VALUES ( 2, 'green' )";
2005     r = run_query(hdb, rec, query);
2006     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2007     MsiCloseHandle(rec);
2008
2009     /* try table name and values as markers */
2010     rec = MsiCreateRecord(3);
2011     MsiRecordSetString(rec, 1, "Table");
2012     MsiRecordSetInteger(rec, 2, 10);
2013     MsiRecordSetString(rec, 3, "haha");
2014     query = "INSERT INTO `?` ( `One`, `Two` ) VALUES ( ?, '?' )";
2015     r = run_query(hdb, rec, query);
2016     ok(r == ERROR_FUNCTION_FAILED, "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
2017     MsiCloseHandle(rec);
2018
2019     /* try all markers */
2020     rec = MsiCreateRecord(5);
2021     MsiRecordSetString(rec, 1, "Table");
2022     MsiRecordSetString(rec, 1, "One");
2023     MsiRecordSetString(rec, 1, "Two");
2024     MsiRecordSetInteger(rec, 2, 10);
2025     MsiRecordSetString(rec, 3, "haha");
2026     query = "INSERT INTO `?` ( `?`, `?` ) VALUES ( ?, '?' )";
2027     r = run_query(hdb, rec, query);
2028     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2029     MsiCloseHandle(rec);
2030
2031     /* insert an integer as a string */
2032     rec = MsiCreateRecord(2);
2033     MsiRecordSetString(rec, 1, "11");
2034     MsiRecordSetString(rec, 2, "hi");
2035     query = "INSERT INTO `Table` ( `One`, `Two` ) VALUES ( ?, '?' )";
2036     r = run_query(hdb, rec, query);
2037     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2038     MsiCloseHandle(rec);
2039
2040     /* leave off the '' for the string */
2041     rec = MsiCreateRecord(2);
2042     MsiRecordSetInteger(rec, 1, 12);
2043     MsiRecordSetString(rec, 2, "hi");
2044     query = "INSERT INTO `Table` ( `One`, `Two` ) VALUES ( ?, ? )";
2045     r = run_query(hdb, rec, query);
2046     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2047     MsiCloseHandle(rec);
2048
2049     MsiCloseHandle(hdb);
2050     DeleteFileA(msifile);
2051 }
2052
2053 #define MY_NVIEWS 4000    /* Largest installer I've seen uses < 2k */
2054 static void test_handle_limit(void)
2055 {
2056     int i;
2057     MSIHANDLE hdb;
2058     MSIHANDLE hviews[MY_NVIEWS];
2059     UINT r;
2060
2061     /* create an empty db */
2062     hdb = create_db();
2063     ok( hdb, "failed to create db\n");
2064
2065     memset(hviews, 0, sizeof(hviews));
2066
2067     for (i=0; i<MY_NVIEWS; i++) {
2068         static char szQueryBuf[256] = "SELECT * from `_Tables`";
2069         hviews[i] = 0xdeadbeeb;
2070         r = MsiDatabaseOpenView(hdb, szQueryBuf, &hviews[i]);
2071         if( r != ERROR_SUCCESS || hviews[i] == 0xdeadbeeb || 
2072             hviews[i] == 0 || (i && (hviews[i] == hviews[i-1])))
2073             break;
2074     }
2075
2076     ok( i == MY_NVIEWS, "problem opening views\n");
2077
2078     for (i=0; i<MY_NVIEWS; i++) {
2079         if (hviews[i] != 0 && hviews[i] != 0xdeadbeeb) {
2080             r = MsiCloseHandle(hviews[i]);
2081             if (r != ERROR_SUCCESS)
2082                 break;
2083         }
2084     }
2085
2086     ok( i == MY_NVIEWS, "problem closing views\n");
2087
2088     r = MsiCloseHandle(hdb);
2089     ok( r == ERROR_SUCCESS, "failed to close database\n");
2090 }
2091
2092 static void generate_transform(void)
2093 {
2094     MSIHANDLE hdb1, hdb2, hrec;
2095     LPCSTR query;
2096     UINT r;
2097
2098     /* start with two identical databases */
2099     CopyFile(msifile2, msifile, FALSE);
2100
2101     r = MsiOpenDatabase(msifile, MSIDBOPEN_TRANSACT, &hdb1 );
2102     ok( r == ERROR_SUCCESS , "Failed to create database\n" );
2103
2104     r = MsiDatabaseCommit( hdb1 );
2105     ok( r == ERROR_SUCCESS , "Failed to commit database\n" );
2106
2107     r = MsiOpenDatabase(msifile2, MSIDBOPEN_READONLY, &hdb2 );
2108     ok( r == ERROR_SUCCESS , "Failed to create database\n" );
2109
2110     /* the transform between two identical database should be empty */
2111     r = MsiDatabaseGenerateTransform(hdb1, hdb2, NULL, 0, 0);
2112     todo_wine {
2113     ok( r == ERROR_NO_DATA, "return code %d, should be ERROR_NO_DATA\n", r );
2114     }
2115
2116     query = "CREATE TABLE `AAR` ( `BAR` SHORT NOT NULL, `CAR` CHAR(255) PRIMARY KEY `CAR`)";
2117     r = run_query(hdb1, 0, query);
2118     ok(r == ERROR_SUCCESS, "failed to add table\n");
2119
2120     query = "INSERT INTO `AAR` ( `BAR`, `CAR` ) VALUES ( 1, 'vw' )";
2121     r = run_query(hdb1, 0, query);
2122     ok(r == ERROR_SUCCESS, "failed to add row 1\n");
2123
2124     query = "INSERT INTO `AAR` ( `BAR`, `CAR` ) VALUES ( 2, 'bmw' )";
2125     r = run_query(hdb1, 0, query);
2126     ok(r == ERROR_SUCCESS, "failed to add row 2\n");
2127
2128     query = "UPDATE `MOO` SET `OOO` = 'c' WHERE `NOO` = 1";
2129     r = run_query(hdb1, 0, query);
2130     ok(r == ERROR_SUCCESS, "failed to modify row\n");
2131
2132     query = "DELETE FROM `MOO` WHERE `NOO` = 3";
2133     r = run_query(hdb1, 0, query);
2134     ok(r == ERROR_SUCCESS, "failed to delete row\n");
2135
2136     hrec = MsiCreateRecord(2);
2137     r = MsiRecordSetInteger(hrec, 1, 1);
2138     ok(r == ERROR_SUCCESS, "failed to set integer\n");
2139
2140     write_file("testdata.bin", "naengmyon", 9);
2141     r = MsiRecordSetStream(hrec, 2, "testdata.bin");
2142     ok(r == ERROR_SUCCESS, "failed to set stream\n");
2143
2144     query = "INSERT INTO `BINARY` ( `ID`, `BLOB` ) VALUES ( ?, ? )";
2145     r = run_query(hdb1, hrec, query);
2146     ok(r == ERROR_SUCCESS, "failed to add row with blob\n");
2147
2148     MsiCloseHandle(hrec);
2149
2150     query = "ALTER TABLE `MOO` ADD `COW` INTEGER";
2151     r = run_query(hdb1, 0, query);
2152     ok(r == ERROR_SUCCESS, "failed to add column\n");
2153
2154     query = "ALTER TABLE `MOO` ADD `PIG` INTEGER";
2155     r = run_query(hdb1, 0, query);
2156     ok(r == ERROR_SUCCESS, "failed to add column\n");
2157
2158     query = "UPDATE `MOO` SET `PIG` = 5 WHERE `NOO` = 1";
2159     r = run_query(hdb1, 0, query);
2160     ok(r == ERROR_SUCCESS, "failed to modify row\n");
2161
2162     query = "CREATE TABLE `Property` ( `Property` CHAR(72) NOT NULL, "
2163             "`Value` CHAR(0) PRIMARY KEY `Property`)";
2164     r = run_query(hdb1, 0, query);
2165     ok(r == ERROR_SUCCESS, "failed to add property table\n");
2166
2167     query = "INSERT INTO `Property` ( `Property`, `Value` ) VALUES ( 'prop', 'val' )";
2168     r = run_query(hdb1, 0, query);
2169     ok(r == ERROR_SUCCESS, "failed to add property\n");
2170
2171     /* database needs to be committed */
2172     MsiDatabaseCommit(hdb1);
2173
2174     r = MsiDatabaseGenerateTransform(hdb1, hdb2, mstfile, 0, 0);
2175     ok( r == ERROR_SUCCESS, "return code %d, should be ERROR_SUCCESS\n", r );
2176
2177     MsiCloseHandle( hdb1 );
2178     MsiCloseHandle( hdb2 );
2179
2180     DeleteFile("testdata.bin");
2181 }
2182
2183 /* data for generating a transform */
2184
2185 /* tables transform names - encoded as they would be in an msi database file */
2186 static const WCHAR name1[] = { 0x4840, 0x3a8a, 0x481b, 0 }; /* AAR */
2187 static const WCHAR name2[] = { 0x4840, 0x3b3f, 0x43f2, 0x4438, 0x45b1, 0 }; /* _Columns */
2188 static const WCHAR name3[] = { 0x4840, 0x3f7f, 0x4164, 0x422f, 0x4836, 0 }; /* _Tables */
2189 static const WCHAR name4[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0 }; /* _StringData */
2190 static const WCHAR name5[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0 }; /* _StringPool */
2191 static const WCHAR name6[] = { 0x4840, 0x3e16, 0x4818, 0}; /* MOO */
2192 static const WCHAR name7[] = { 0x4840, 0x3c8b, 0x3a97, 0x409b, 0 }; /* BINARY */
2193 static const WCHAR name8[] = { 0x3c8b, 0x3a97, 0x409b, 0x387e, 0 }; /* BINARY.1 */
2194 static const WCHAR name9[] = { 0x4840, 0x4559, 0x44f2, 0x4568, 0x4737, 0 }; /* Property */
2195
2196 /* data in each table */
2197 static const WCHAR data1[] = { /* AAR */
2198     0x0201, 0x0008, 0x8001,  /* 0x0201 = add row (1), two shorts */
2199     0x0201, 0x0009, 0x8002,
2200 };
2201 static const WCHAR data2[] = { /* _Columns */
2202     0x0401, 0x0001, 0x8003, 0x0002, 0x9502,
2203     0x0401, 0x0001, 0x8004, 0x0003, 0x9502,
2204     0x0401, 0x0005, 0x0000, 0x0006, 0xbdff,  /* 0x0401 = add row (1), 4 shorts */
2205     0x0401, 0x0005, 0x0000, 0x0007, 0x8502,
2206     0x0401, 0x000a, 0x0000, 0x000a, 0xad48,
2207     0x0401, 0x000a, 0x0000, 0x000b, 0x9d00,
2208 };
2209 static const WCHAR data3[] = { /* _Tables */
2210     0x0101, 0x0005, /* 0x0101 = add row (1), 1 short */
2211     0x0101, 0x000a,
2212 };
2213 static const char data4[] = /* _StringData */
2214     "MOOCOWPIGcAARCARBARvwbmwPropertyValuepropval";  /* all the strings squashed together */
2215 static const WCHAR data5[] = { /* _StringPool */
2216 /*  len, refs */
2217     0,   0,    /* string 0 ''    */
2218     3,   2,    /* string 1 'MOO' */
2219     3,   1,    /* string 2 'COW' */
2220     3,   1,    /* string 3 'PIG' */
2221     1,   1,    /* string 4 'c'   */
2222     3,   3,    /* string 5 'AAR' */
2223     3,   1,    /* string 6 'CAR' */
2224     3,   1,    /* string 7 'BAR' */
2225     2,   1,    /* string 8 'vw'  */
2226     3,   1,    /* string 9 'bmw' */
2227     8,   4,    /* string 10 'Property' */
2228     5,   1,    /* string 11 'Value' */
2229     4,   1,    /* string 12 'prop' */
2230     3,   1,    /* string 13 'val' */
2231 };
2232 /* update row, 0x0002 is a bitmask of present column data, keys are excluded */
2233 static const WCHAR data6[] = { /* MOO */
2234     0x000a, 0x8001, 0x0004, 0x8005, /* update row */
2235     0x0000, 0x8003,         /* delete row */
2236 };
2237
2238 static const WCHAR data7[] = { /* BINARY */
2239     0x0201, 0x8001, 0x0001,
2240 };
2241
2242 static const char data8[] =  /* stream data for the BINARY table */
2243     "naengmyon";
2244
2245 static const WCHAR data9[] = { /* Property */
2246     0x0201, 0x000c, 0x000d,
2247 };
2248
2249 static const struct {
2250     LPCWSTR name;
2251     const void *data;
2252     DWORD size;
2253 } table_transform_data[] =
2254 {
2255     { name1, data1, sizeof data1 },
2256     { name2, data2, sizeof data2 },
2257     { name3, data3, sizeof data3 },
2258     { name4, data4, sizeof data4 - 1 },
2259     { name5, data5, sizeof data5 },
2260     { name6, data6, sizeof data6 },
2261     { name7, data7, sizeof data7 },
2262     { name8, data8, sizeof data8 - 1 },
2263     { name9, data9, sizeof data9 },
2264 };
2265
2266 #define NUM_TRANSFORM_TABLES (sizeof table_transform_data/sizeof table_transform_data[0])
2267
2268 static void generate_transform_manual(void)
2269 {
2270     IStorage *stg = NULL;
2271     IStream *stm;
2272     WCHAR name[0x20];
2273     HRESULT r;
2274     DWORD i, count;
2275     const DWORD mode = STGM_CREATE|STGM_READWRITE|STGM_DIRECT|STGM_SHARE_EXCLUSIVE;
2276
2277     const CLSID CLSID_MsiTransform = { 0xc1082,0,0,{0xc0,0,0,0,0,0,0,0x46}};
2278
2279     MultiByteToWideChar(CP_ACP, 0, mstfile, -1, name, 0x20);
2280
2281     r = StgCreateDocfile(name, mode, 0, &stg);
2282     ok(r == S_OK, "failed to create storage\n");
2283     if (!stg)
2284         return;
2285
2286     r = IStorage_SetClass( stg, &CLSID_MsiTransform );
2287     ok(r == S_OK, "failed to set storage type\n");
2288
2289     for (i=0; i<NUM_TRANSFORM_TABLES; i++)
2290     {
2291         r = IStorage_CreateStream( stg, table_transform_data[i].name,
2292                             STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stm );
2293         if (FAILED(r))
2294         {
2295             ok(0, "failed to create stream %08x\n", r);
2296             continue;
2297         }
2298
2299         r = IStream_Write( stm, table_transform_data[i].data,
2300                           table_transform_data[i].size, &count );
2301         if (FAILED(r) || count != table_transform_data[i].size)
2302             ok(0, "failed to write stream\n");
2303         IStream_Release(stm);
2304     }
2305
2306     IStorage_Release(stg);
2307 }
2308
2309 static UINT set_summary_info(MSIHANDLE hdb)
2310 {
2311     UINT res;
2312     MSIHANDLE suminfo;
2313
2314     /* build summary info */
2315     res = MsiGetSummaryInformation(hdb, NULL, 7, &suminfo);
2316     ok( res == ERROR_SUCCESS , "Failed to open summaryinfo\n" );
2317
2318     res = MsiSummaryInfoSetProperty(suminfo,2, VT_LPSTR, 0,NULL,
2319                         "Installation Database");
2320     ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
2321
2322     res = MsiSummaryInfoSetProperty(suminfo,3, VT_LPSTR, 0,NULL,
2323                         "Installation Database");
2324     ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
2325
2326     res = MsiSummaryInfoSetProperty(suminfo,4, VT_LPSTR, 0,NULL,
2327                         "Wine Hackers");
2328     ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
2329
2330     res = MsiSummaryInfoSetProperty(suminfo,7, VT_LPSTR, 0,NULL,
2331                     ";1033");
2332     ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
2333
2334     res = MsiSummaryInfoSetProperty(suminfo,9, VT_LPSTR, 0,NULL,
2335                     "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}");
2336     ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
2337
2338     res = MsiSummaryInfoSetProperty(suminfo, 14, VT_I4, 100, NULL, NULL);
2339     ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
2340
2341     res = MsiSummaryInfoSetProperty(suminfo, 15, VT_I4, 0, NULL, NULL);
2342     ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
2343
2344     res = MsiSummaryInfoPersist(suminfo);
2345     ok( res == ERROR_SUCCESS , "Failed to make summary info persist\n" );
2346
2347     res = MsiCloseHandle( suminfo);
2348     ok( res == ERROR_SUCCESS , "Failed to close suminfo\n" );
2349
2350     return res;
2351 }
2352
2353 static MSIHANDLE create_package_db(LPCSTR filename)
2354 {
2355     MSIHANDLE hdb = 0;
2356     UINT res;
2357
2358     DeleteFile(msifile);
2359
2360     /* create an empty database */
2361     res = MsiOpenDatabase(filename, MSIDBOPEN_CREATE, &hdb );
2362     ok( res == ERROR_SUCCESS , "Failed to create database\n" );
2363     if( res != ERROR_SUCCESS )
2364         return hdb;
2365
2366     res = MsiDatabaseCommit( hdb );
2367     ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
2368
2369     res = set_summary_info(hdb);
2370
2371     res = create_directory_table(hdb);
2372     ok( res == ERROR_SUCCESS , "Failed to create directory table\n" );
2373
2374     return hdb;
2375 }
2376
2377 static MSIHANDLE package_from_db(MSIHANDLE hdb)
2378 {
2379     UINT res;
2380     CHAR szPackage[10];
2381     MSIHANDLE hPackage;
2382
2383     sprintf(szPackage,"#%li",hdb);
2384     res = MsiOpenPackage(szPackage,&hPackage);
2385     if (res != ERROR_SUCCESS)
2386         return 0;
2387
2388     res = MsiCloseHandle(hdb);
2389     if (res != ERROR_SUCCESS)
2390         return 0;
2391
2392     return hPackage;
2393 }
2394
2395 static void test_try_transform(void)
2396 {
2397     MSIHANDLE hdb, hview, hrec, hpkg;
2398     LPCSTR query;
2399     UINT r;
2400     DWORD sz;
2401     char buffer[MAX_PATH];
2402
2403     DeleteFile(msifile);
2404     DeleteFile(mstfile);
2405
2406     /* create the database */
2407     hdb = create_package_db(msifile);
2408     ok(hdb, "Failed to create package db\n");
2409
2410     query = "CREATE TABLE `MOO` ( `NOO` SHORT NOT NULL, `OOO` CHAR(255) PRIMARY KEY `NOO`)";
2411     r = run_query(hdb, 0, query);
2412     ok(r == ERROR_SUCCESS, "failed to add table\n");
2413
2414     query = "INSERT INTO `MOO` ( `NOO`, `OOO` ) VALUES ( 1, 'a' )";
2415     r = run_query(hdb, 0, query);
2416     ok(r == ERROR_SUCCESS, "failed to add row\n");
2417
2418     query = "INSERT INTO `MOO` ( `NOO`, `OOO` ) VALUES ( 2, 'b' )";
2419     r = run_query(hdb, 0, query);
2420     ok(r == ERROR_SUCCESS, "failed to add row\n");
2421
2422     query = "INSERT INTO `MOO` ( `NOO`, `OOO` ) VALUES ( 3, 'c' )";
2423     r = run_query(hdb, 0, query);
2424     ok(r == ERROR_SUCCESS, "failed to add row\n");
2425
2426     query = "CREATE TABLE `BINARY` ( `ID` SHORT NOT NULL, `BLOB` OBJECT PRIMARY KEY `ID`)";
2427     r = run_query(hdb, 0, query);
2428     ok(r == ERROR_SUCCESS, "failed to add table\n");
2429
2430     hrec = MsiCreateRecord(2);
2431     r = MsiRecordSetInteger(hrec, 1, 2);
2432     ok(r == ERROR_SUCCESS, "failed to set integer\n");
2433
2434     write_file("testdata.bin", "lamyon", 6);
2435     r = MsiRecordSetStream(hrec, 2, "testdata.bin");
2436     ok(r == ERROR_SUCCESS, "failed to set stream\n");
2437
2438     query = "INSERT INTO `BINARY` ( `ID`, `BLOB` ) VALUES ( ?, ? )";
2439     r = run_query(hdb, hrec, query);
2440     ok(r == ERROR_SUCCESS, "failed to add row with blob\n");
2441
2442     MsiCloseHandle(hrec);
2443
2444     r = MsiDatabaseCommit( hdb );
2445     ok( r == ERROR_SUCCESS , "Failed to commit database\n" );
2446
2447     MsiCloseHandle( hdb );
2448     DeleteFileA("testdata.bin");
2449
2450     /*
2451      * Both these generate an equivalent transform,
2452      *  but the first doesn't work in Wine yet
2453      *  because MsiDatabaseGenerateTransform is unimplemented.
2454      */
2455     if (0)
2456         generate_transform();
2457     else
2458         generate_transform_manual();
2459
2460     r = MsiOpenDatabase(msifile, MSIDBOPEN_DIRECT, &hdb );
2461     ok( r == ERROR_SUCCESS , "Failed to create database\n" );
2462
2463     r = MsiDatabaseApplyTransform( hdb, mstfile, 0 );
2464     ok( r == ERROR_SUCCESS, "return code %d, should be ERROR_SUCCESS\n", r );
2465
2466     MsiDatabaseCommit( hdb );
2467
2468     /* check new values */
2469     hrec = 0;
2470     query = "select `BAR`,`CAR` from `AAR` where `BAR` = 1 AND `CAR` = 'vw'";
2471     r = do_query(hdb, query, &hrec);
2472     ok(r == ERROR_SUCCESS, "select query failed\n");
2473     MsiCloseHandle(hrec);
2474
2475     query = "select `BAR`,`CAR` from `AAR` where `BAR` = 2 AND `CAR` = 'bmw'";
2476     hrec = 0;
2477     r = do_query(hdb, query, &hrec);
2478     ok(r == ERROR_SUCCESS, "select query failed\n");
2479     MsiCloseHandle(hrec);
2480
2481     /* check updated values */
2482     hrec = 0;
2483     query = "select `NOO`,`OOO` from `MOO` where `NOO` = 1 AND `OOO` = 'c'";
2484     r = do_query(hdb, query, &hrec);
2485     ok(r == ERROR_SUCCESS, "select query failed\n");
2486     MsiCloseHandle(hrec);
2487
2488     /* check unchanged value */
2489     hrec = 0;
2490     query = "select `NOO`,`OOO` from `MOO` where `NOO` = 2 AND `OOO` = 'b'";
2491     r = do_query(hdb, query, &hrec);
2492     ok(r == ERROR_SUCCESS, "select query failed\n");
2493     MsiCloseHandle(hrec);
2494
2495     /* check deleted value */
2496     hrec = 0;
2497     query = "select * from `MOO` where `NOO` = 3";
2498     r = do_query(hdb, query, &hrec);
2499     ok(r == ERROR_NO_MORE_ITEMS, "select query failed\n");
2500     if (hrec) MsiCloseHandle(hrec);
2501
2502     /* check added stream */
2503     hrec = 0;
2504     query = "select `BLOB` from `BINARY` where `ID` = 1";
2505     r = do_query(hdb, query, &hrec);
2506     ok(r == ERROR_SUCCESS, "select query failed\n");
2507
2508     /* check the contents of the stream */
2509     sz = sizeof buffer;
2510     r = MsiRecordReadStream( hrec, 1, buffer, &sz );
2511     ok(r == ERROR_SUCCESS, "read stream failed\n");
2512     ok(!memcmp(buffer, "naengmyon", 9), "stream data was wrong\n");
2513     ok(sz == 9, "stream data was wrong size\n");
2514     if (hrec) MsiCloseHandle(hrec);
2515
2516     /* check the validity of the table with a deleted row */
2517     hrec = 0;
2518     query = "select * from `MOO`";
2519     r = MsiDatabaseOpenView(hdb, query, &hview);
2520     ok(r == ERROR_SUCCESS, "open view failed\n");
2521
2522     r = MsiViewExecute(hview, 0);
2523     ok(r == ERROR_SUCCESS, "view execute failed\n");
2524
2525     r = MsiViewFetch(hview, &hrec);
2526     ok(r == ERROR_SUCCESS, "view fetch failed\n");
2527
2528     r = MsiRecordGetInteger(hrec, 1);
2529     ok(r == 1, "Expected 1, got %d\n", r);
2530
2531     sz = sizeof buffer;
2532     r = MsiRecordGetString(hrec, 2, buffer, &sz);
2533     ok(r == ERROR_SUCCESS, "record get string failed\n");
2534     ok(!lstrcmpA(buffer, "c"), "Expected c, got %s\n", buffer);
2535
2536     r = MsiRecordGetInteger(hrec, 3);
2537     ok(r == 0x80000000, "Expected 0x80000000, got %d\n", r);
2538
2539     r = MsiRecordGetInteger(hrec, 4);
2540     ok(r == 5, "Expected 5, got %d\n", r);
2541
2542     MsiCloseHandle(hrec);
2543
2544     r = MsiViewFetch(hview, &hrec);
2545     ok(r == ERROR_SUCCESS, "view fetch failed\n");
2546
2547     r = MsiRecordGetInteger(hrec, 1);
2548     ok(r == 2, "Expected 2, got %d\n", r);
2549
2550     sz = sizeof buffer;
2551     r = MsiRecordGetString(hrec, 2, buffer, &sz);
2552     ok(r == ERROR_SUCCESS, "record get string failed\n");
2553     ok(!lstrcmpA(buffer, "b"), "Expected b, got %s\n", buffer);
2554
2555     r = MsiRecordGetInteger(hrec, 3);
2556     ok(r == 0x80000000, "Expected 0x80000000, got %d\n", r);
2557
2558     r = MsiRecordGetInteger(hrec, 4);
2559     ok(r == 0x80000000, "Expected 0x80000000, got %d\n", r);
2560
2561     MsiCloseHandle(hrec);
2562
2563     r = MsiViewFetch(hview, &hrec);
2564     ok(r == ERROR_NO_MORE_ITEMS, "view fetch succeeded\n");
2565
2566     MsiCloseHandle(hrec);
2567     MsiCloseHandle(hview);
2568
2569     /* check that the property was added */
2570     hpkg = package_from_db(hdb);
2571     ok(hpkg != 0, "Expected non-NULL hpkg\n");
2572
2573     sz = MAX_PATH;
2574     r = MsiGetProperty(hpkg, "prop", buffer, &sz);
2575     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2576     ok(!lstrcmp(buffer, "val"), "Expected val, got %s\n", buffer);
2577
2578     MsiCloseHandle(hpkg);
2579     MsiCloseHandle(hdb);
2580
2581     DeleteFile(msifile);
2582     DeleteFile(mstfile);
2583 }
2584
2585 struct join_res
2586 {
2587     const CHAR one[MAX_PATH];
2588     const CHAR two[MAX_PATH];
2589 };
2590
2591 struct join_res_4col
2592 {
2593     const CHAR one[MAX_PATH];
2594     const CHAR two[MAX_PATH];
2595     const CHAR three[MAX_PATH];
2596     const CHAR four[MAX_PATH];
2597 };
2598
2599 struct join_res_uint
2600 {
2601     UINT one;
2602     UINT two;
2603     UINT three;
2604     UINT four;
2605     UINT five;
2606     UINT six;
2607 };
2608
2609 static const struct join_res join_res_first[] =
2610 {
2611     { "alveolar", "procerus" },
2612     { "septum", "procerus" },
2613     { "septum", "nasalis" },
2614     { "ramus", "nasalis" },
2615     { "malar", "mentalis" },
2616 };
2617
2618 static const struct join_res join_res_second[] =
2619 {
2620     { "nasal", "septum" },
2621     { "mandible", "ramus" },
2622 };
2623
2624 static const struct join_res join_res_third[] =
2625 {
2626     { "msvcp.dll", "abcdefgh" },
2627     { "msvcr.dll", "ijklmnop" },
2628 };
2629
2630 static const struct join_res join_res_fourth[] =
2631 {
2632     { "msvcp.dll.01234", "single.dll.31415" },
2633 };
2634
2635 static const struct join_res join_res_fifth[] =
2636 {
2637     { "malar", "procerus" },
2638 };
2639
2640 static const struct join_res join_res_sixth[] =
2641 {
2642     { "malar", "procerus" },
2643     { "malar", "procerus" },
2644     { "malar", "nasalis" },
2645     { "malar", "nasalis" },
2646     { "malar", "nasalis" },
2647     { "malar", "mentalis" },
2648 };
2649
2650 static const struct join_res join_res_seventh[] =
2651 {
2652     { "malar", "nasalis" },
2653     { "malar", "nasalis" },
2654     { "malar", "nasalis" },
2655 };
2656
2657 static const struct join_res_4col join_res_eighth[] =
2658 {
2659     { "msvcp.dll", "msvcp.dll.01234", "msvcp.dll.01234", "abcdefgh" },
2660     { "msvcr.dll", "msvcr.dll.56789", "msvcp.dll.01234", "abcdefgh" },
2661     { "msvcp.dll", "msvcp.dll.01234", "msvcr.dll.56789", "ijklmnop" },
2662     { "msvcr.dll", "msvcr.dll.56789", "msvcr.dll.56789", "ijklmnop" },
2663     { "msvcp.dll", "msvcp.dll.01234", "single.dll.31415", "msvcp.dll" },
2664     { "msvcr.dll", "msvcr.dll.56789", "single.dll.31415", "msvcp.dll" },
2665 };
2666
2667 static const struct join_res_uint join_res_ninth[] =
2668 {
2669     { 1, 2, 3, 4, 7, 8 },
2670     { 1, 2, 5, 6, 7, 8 },
2671     { 1, 2, 3, 4, 9, 10 },
2672     { 1, 2, 5, 6, 9, 10 },
2673     { 1, 2, 3, 4, 11, 12 },
2674     { 1, 2, 5, 6, 11, 12 },
2675 };
2676
2677 static void test_join(void)
2678 {
2679     MSIHANDLE hdb, hview, hrec;
2680     LPCSTR query;
2681     CHAR buf[MAX_PATH];
2682     UINT r, count;
2683     DWORD size, i;
2684     BOOL data_correct;
2685
2686     hdb = create_db();
2687     ok( hdb, "failed to create db\n");
2688
2689     r = create_component_table( hdb );
2690     ok( r == ERROR_SUCCESS, "cannot create Component table: %d\n", r );
2691
2692     r = add_component_entry( hdb, "'zygomatic', 'malar', 'INSTALLDIR', 0, '', ''" );
2693     ok( r == ERROR_SUCCESS, "cannot add component: %d\n", r );
2694
2695     r = add_component_entry( hdb, "'maxilla', 'alveolar', 'INSTALLDIR', 0, '', ''" );
2696     ok( r == ERROR_SUCCESS, "cannot add component: %d\n", r );
2697
2698     r = add_component_entry( hdb, "'nasal', 'septum', 'INSTALLDIR', 0, '', ''" );
2699     ok( r == ERROR_SUCCESS, "cannot add component: %d\n", r );
2700
2701     r = add_component_entry( hdb, "'mandible', 'ramus', 'INSTALLDIR', 0, '', ''" );
2702     ok( r == ERROR_SUCCESS, "cannot add component: %d\n", r );
2703
2704     r = create_feature_components_table( hdb );
2705     ok( r == ERROR_SUCCESS, "cannot create FeatureComponents table: %d\n", r );
2706
2707     r = add_feature_components_entry( hdb, "'procerus', 'maxilla'" );
2708     ok( r == ERROR_SUCCESS, "cannot add feature components: %d\n", r );
2709
2710     r = add_feature_components_entry( hdb, "'procerus', 'nasal'" );
2711     ok( r == ERROR_SUCCESS, "cannot add feature components: %d\n", r );
2712
2713     r = add_feature_components_entry( hdb, "'nasalis', 'nasal'" );
2714     ok( r == ERROR_SUCCESS, "cannot add feature components: %d\n", r );
2715
2716     r = add_feature_components_entry( hdb, "'nasalis', 'mandible'" );
2717     ok( r == ERROR_SUCCESS, "cannot add feature components: %d\n", r );
2718
2719     r = add_feature_components_entry( hdb, "'nasalis', 'notacomponent'" );
2720     ok( r == ERROR_SUCCESS, "cannot add feature components: %d\n", r );
2721
2722     r = add_feature_components_entry( hdb, "'mentalis', 'zygomatic'" );
2723     ok( r == ERROR_SUCCESS, "cannot add feature components: %d\n", r );
2724
2725     r = create_std_dlls_table( hdb );
2726     ok( r == ERROR_SUCCESS, "cannot create StdDlls table: %d\n", r );
2727
2728     r = add_std_dlls_entry( hdb, "'msvcp.dll', 'msvcp.dll.01234'" );
2729     ok( r == ERROR_SUCCESS, "cannot add std dlls: %d\n", r );
2730
2731     r = add_std_dlls_entry( hdb, "'msvcr.dll', 'msvcr.dll.56789'" );
2732     ok( r == ERROR_SUCCESS, "cannot add std dlls: %d\n", r );
2733
2734     r = create_binary_table( hdb );
2735     ok( r == ERROR_SUCCESS, "cannot create Binary table: %d\n", r );
2736
2737     r = add_binary_entry( hdb, "'msvcp.dll.01234', 'abcdefgh'" );
2738     ok( r == ERROR_SUCCESS, "cannot add binary: %d\n", r );
2739
2740     r = add_binary_entry( hdb, "'msvcr.dll.56789', 'ijklmnop'" );
2741     ok( r == ERROR_SUCCESS, "cannot add binary: %d\n", r );
2742
2743     r = add_binary_entry( hdb, "'single.dll.31415', 'msvcp.dll'" );
2744     ok( r == ERROR_SUCCESS, "cannot add binary: %d\n", r );
2745
2746     query = "CREATE TABLE `One` (`A` SHORT, `B` SHORT PRIMARY KEY `A`)";
2747     r = run_query( hdb, 0, query);
2748     ok(r == ERROR_SUCCESS, "cannot create table: %d\n", r );
2749
2750     query = "CREATE TABLE `Two` (`C` SHORT, `D` SHORT PRIMARY KEY `C`)";
2751     r = run_query( hdb, 0, query);
2752     ok(r == ERROR_SUCCESS, "cannot create table: %d\n", r );
2753
2754     query = "CREATE TABLE `Three` (`E` SHORT, `F` SHORT PRIMARY KEY `E`)";
2755     r = run_query( hdb, 0, query);
2756     ok(r == ERROR_SUCCESS, "cannot create table: %d\n", r );
2757
2758     query = "INSERT INTO `One` (`A`, `B`) VALUES (1, 2)";
2759     r = run_query( hdb, 0, query);
2760     ok(r == ERROR_SUCCESS, "cannot insert into table: %d\n", r );
2761
2762     query = "INSERT INTO `Two` (`C`, `D`) VALUES (3, 4)";
2763     r = run_query( hdb, 0, query);
2764     ok(r == ERROR_SUCCESS, "cannot insert into table: %d\n", r );
2765
2766     query = "INSERT INTO `Two` (`C`, `D`) VALUES (5, 6)";
2767     r = run_query( hdb, 0, query);
2768     ok(r == ERROR_SUCCESS, "cannot insert into table: %d\n", r );
2769
2770     query = "INSERT INTO `Three` (`E`, `F`) VALUES (7, 8)";
2771     r = run_query( hdb, 0, query);
2772     ok(r == ERROR_SUCCESS, "cannot insert into table: %d\n", r );
2773
2774     query = "INSERT INTO `Three` (`E`, `F`) VALUES (9, 10)";
2775     r = run_query( hdb, 0, query);
2776     ok(r == ERROR_SUCCESS, "cannot insert into table: %d\n", r );
2777
2778     query = "INSERT INTO `Three` (`E`, `F`) VALUES (11, 12)";
2779     r = run_query( hdb, 0, query);
2780     ok(r == ERROR_SUCCESS, "cannot insert into table: %d\n", r );
2781
2782     query = "CREATE TABLE `Four` (`G` SHORT, `H` SHORT PRIMARY KEY `G`)";
2783     r = run_query( hdb, 0, query);
2784     ok(r == ERROR_SUCCESS, "cannot create table: %d\n", r );
2785
2786     query = "CREATE TABLE `Five` (`I` SHORT, `J` SHORT PRIMARY KEY `I`)";
2787     r = run_query( hdb, 0, query);
2788     ok(r == ERROR_SUCCESS, "cannot create table: %d\n", r );
2789
2790     query = "INSERT INTO `Five` (`I`, `J`) VALUES (13, 14)";
2791     r = run_query( hdb, 0, query);
2792     ok(r == ERROR_SUCCESS, "cannot insert into table: %d\n", r );
2793
2794     query = "INSERT INTO `Five` (`I`, `J`) VALUES (15, 16)";
2795     r = run_query( hdb, 0, query);
2796     ok(r == ERROR_SUCCESS, "cannot insert into table: %d\n", r );
2797
2798     query = "SELECT `Component`.`ComponentId`, `FeatureComponents`.`Feature_` "
2799             "FROM `Component`, `FeatureComponents` "
2800             "WHERE `Component`.`Component` = `FeatureComponents`.`Component_` "
2801             "ORDER BY `Feature_`";
2802     r = MsiDatabaseOpenView(hdb, query, &hview);
2803     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
2804
2805     r = MsiViewExecute(hview, 0);
2806     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
2807
2808     i = 0;
2809     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
2810     {
2811         count = MsiRecordGetFieldCount( hrec );
2812         ok( count == 2, "Expected 2 record fields, got %d\n", count );
2813
2814         size = MAX_PATH;
2815         r = MsiRecordGetString( hrec, 1, buf, &size );
2816         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
2817         ok( !lstrcmp( buf, join_res_first[i].one ),
2818             "For (row %d, column 1) expected '%s', got %s\n", i, join_res_first[i].one, buf );
2819
2820         size = MAX_PATH;
2821         r = MsiRecordGetString( hrec, 2, buf, &size );
2822         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
2823         ok( !lstrcmp( buf, join_res_first[i].two ),
2824             "For (row %d, column 2) expected '%s', got %s\n", i, join_res_first[i].two, buf );
2825
2826         i++;
2827         MsiCloseHandle(hrec);
2828     }
2829
2830     ok( i == 5, "Expected 5 rows, got %d\n", i );
2831     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
2832
2833     MsiViewClose(hview);
2834     MsiCloseHandle(hview);
2835
2836     /* try a join without a WHERE condition */
2837     query = "SELECT `Component`.`ComponentId`, `FeatureComponents`.`Feature_` "
2838             "FROM `Component`, `FeatureComponents` ";
2839     r = MsiDatabaseOpenView(hdb, query, &hview);
2840     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
2841
2842     r = MsiViewExecute(hview, 0);
2843     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
2844
2845     i = 0;
2846     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
2847     {
2848         i++;
2849         MsiCloseHandle(hrec);
2850     }
2851     ok( i == 24, "Expected 24 rows, got %d\n", i );
2852
2853     MsiViewClose(hview);
2854     MsiCloseHandle(hview);
2855
2856     query = "SELECT DISTINCT Component, ComponentId FROM FeatureComponents, Component "
2857             "WHERE FeatureComponents.Component_=Component.Component "
2858             "AND (Feature_='nasalis') ORDER BY Feature_";
2859     r = MsiDatabaseOpenView(hdb, query, &hview);
2860     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
2861
2862     r = MsiViewExecute(hview, 0);
2863     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
2864
2865     i = 0;
2866     data_correct = TRUE;
2867     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
2868     {
2869         count = MsiRecordGetFieldCount( hrec );
2870         ok( count == 2, "Expected 2 record fields, got %d\n", count );
2871
2872         size = MAX_PATH;
2873         r = MsiRecordGetString( hrec, 1, buf, &size );
2874         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
2875         if( lstrcmp( buf, join_res_second[i].one ))
2876             data_correct = FALSE;
2877
2878         size = MAX_PATH;
2879         r = MsiRecordGetString( hrec, 2, buf, &size );
2880         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
2881         if( lstrcmp( buf, join_res_second[i].two ))
2882             data_correct = FALSE;
2883
2884         i++;
2885         MsiCloseHandle(hrec);
2886     }
2887
2888     ok( data_correct, "data returned in the wrong order\n");
2889
2890     ok( i == 2, "Expected 2 rows, got %d\n", i );
2891     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
2892
2893     MsiViewClose(hview);
2894     MsiCloseHandle(hview);
2895
2896     query = "SELECT `StdDlls`.`File`, `Binary`.`Data` "
2897             "FROM `StdDlls`, `Binary` "
2898             "WHERE `StdDlls`.`Binary_` = `Binary`.`Name` "
2899             "ORDER BY `File`";
2900     r = MsiDatabaseOpenView(hdb, query, &hview);
2901     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
2902
2903     r = MsiViewExecute(hview, 0);
2904     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
2905
2906     i = 0;
2907     data_correct = TRUE;
2908     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
2909     {
2910         count = MsiRecordGetFieldCount( hrec );
2911         ok( count == 2, "Expected 2 record fields, got %d\n", count );
2912
2913         size = MAX_PATH;
2914         r = MsiRecordGetString( hrec, 1, buf, &size );
2915         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
2916         if( lstrcmp( buf, join_res_third[i].one ) )
2917             data_correct = FALSE;
2918
2919         size = MAX_PATH;
2920         r = MsiRecordGetString( hrec, 2, buf, &size );
2921         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
2922         if( lstrcmp( buf, join_res_third[i].two ) )
2923             data_correct = FALSE;
2924
2925         i++;
2926         MsiCloseHandle(hrec);
2927     }
2928     ok( data_correct, "data returned in the wrong order\n");
2929
2930     ok( i == 2, "Expected 2 rows, got %d\n", i );
2931
2932     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
2933
2934     MsiViewClose(hview);
2935     MsiCloseHandle(hview);
2936
2937     query = "SELECT `StdDlls`.`Binary_`, `Binary`.`Name` "
2938             "FROM `StdDlls`, `Binary` "
2939             "WHERE `StdDlls`.`File` = `Binary`.`Data` "
2940             "ORDER BY `Name`";
2941     r = MsiDatabaseOpenView(hdb, query, &hview);
2942     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
2943
2944     r = MsiViewExecute(hview, 0);
2945     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
2946
2947     i = 0;
2948     data_correct = TRUE;
2949     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
2950     {
2951         count = MsiRecordGetFieldCount( hrec );
2952         ok( count == 2, "Expected 2 record fields, got %d\n", count );
2953
2954         size = MAX_PATH;
2955         r = MsiRecordGetString( hrec, 1, buf, &size );
2956         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
2957         if( lstrcmp( buf, join_res_fourth[i].one ))
2958             data_correct = FALSE;
2959
2960         size = MAX_PATH;
2961         r = MsiRecordGetString( hrec, 2, buf, &size );
2962         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
2963         if( lstrcmp( buf, join_res_fourth[i].two ))
2964             data_correct = FALSE;
2965
2966         i++;
2967         MsiCloseHandle(hrec);
2968     }
2969     ok( data_correct, "data returned in the wrong order\n");
2970
2971     ok( i == 1, "Expected 1 rows, got %d\n", i );
2972     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
2973
2974     MsiViewClose(hview);
2975     MsiCloseHandle(hview);
2976
2977     query = "SELECT `Component`.`ComponentId`, `FeatureComponents`.`Feature_` "
2978             "FROM `Component`, `FeatureComponents` "
2979             "WHERE `Component`.`Component` = 'zygomatic' "
2980             "AND `FeatureComponents`.`Component_` = 'maxilla' "
2981             "ORDER BY `Feature_`";
2982     r = MsiDatabaseOpenView(hdb, query, &hview);
2983     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
2984
2985     r = MsiViewExecute(hview, 0);
2986     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
2987
2988     i = 0;
2989     data_correct = TRUE;
2990     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
2991     {
2992         count = MsiRecordGetFieldCount( hrec );
2993         ok( count == 2, "Expected 2 record fields, got %d\n", count );
2994
2995         size = MAX_PATH;
2996         r = MsiRecordGetString( hrec, 1, buf, &size );
2997         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
2998         if( lstrcmp( buf, join_res_fifth[i].one ))
2999             data_correct = FALSE;
3000
3001         size = MAX_PATH;
3002         r = MsiRecordGetString( hrec, 2, buf, &size );
3003         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3004         if( lstrcmp( buf, join_res_fifth[i].two ))
3005             data_correct = FALSE;
3006
3007         i++;
3008         MsiCloseHandle(hrec);
3009     }
3010     ok( data_correct, "data returned in the wrong order\n");
3011
3012     ok( i == 1, "Expected 1 rows, got %d\n", i );
3013     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3014
3015     MsiViewClose(hview);
3016     MsiCloseHandle(hview);
3017
3018     query = "SELECT `Component`.`ComponentId`, `FeatureComponents`.`Feature_` "
3019             "FROM `Component`, `FeatureComponents` "
3020             "WHERE `Component` = 'zygomatic' "
3021             "ORDER BY `Feature_`";
3022     r = MsiDatabaseOpenView(hdb, query, &hview);
3023     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3024
3025     r = MsiViewExecute(hview, 0);
3026     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3027
3028     i = 0;
3029     data_correct = TRUE;
3030     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3031     {
3032         count = MsiRecordGetFieldCount( hrec );
3033         ok( count == 2, "Expected 2 record fields, got %d\n", count );
3034
3035         size = MAX_PATH;
3036         r = MsiRecordGetString( hrec, 1, buf, &size );
3037         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3038         if( lstrcmp( buf, join_res_sixth[i].one ))
3039             data_correct = FALSE;
3040
3041         size = MAX_PATH;
3042         r = MsiRecordGetString( hrec, 2, buf, &size );
3043         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3044         if( lstrcmp( buf, join_res_sixth[i].two ))
3045             data_correct = FALSE;
3046
3047         i++;
3048         MsiCloseHandle(hrec);
3049     }
3050     ok( data_correct, "data returned in the wrong order\n");
3051
3052     ok( i == 6, "Expected 6 rows, got %d\n", i );
3053     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3054
3055     MsiViewClose(hview);
3056     MsiCloseHandle(hview);
3057
3058     query = "SELECT `Component`.`ComponentId`, `FeatureComponents`.`Feature_` "
3059             "FROM `Component`, `FeatureComponents` "
3060             "WHERE `Component` = 'zygomatic' "
3061             "AND `Feature_` = 'nasalis' "
3062             "ORDER BY `Feature_`";
3063     r = MsiDatabaseOpenView(hdb, query, &hview);
3064     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3065
3066     r = MsiViewExecute(hview, 0);
3067     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3068
3069     i = 0;
3070     data_correct = TRUE;
3071     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3072     {
3073         count = MsiRecordGetFieldCount( hrec );
3074         ok( count == 2, "Expected 2 record fields, got %d\n", count );
3075
3076         size = MAX_PATH;
3077         r = MsiRecordGetString( hrec, 1, buf, &size );
3078         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3079         if( lstrcmp( buf, join_res_seventh[i].one ))
3080             data_correct = FALSE;
3081
3082         size = MAX_PATH;
3083         r = MsiRecordGetString( hrec, 2, buf, &size );
3084         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3085         if( lstrcmp( buf, join_res_seventh[i].two ))
3086             data_correct = FALSE;
3087
3088         i++;
3089         MsiCloseHandle(hrec);
3090     }
3091
3092     ok( data_correct, "data returned in the wrong order\n");
3093     ok( i == 3, "Expected 3 rows, got %d\n", i );
3094     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3095
3096     MsiViewClose(hview);
3097     MsiCloseHandle(hview);
3098
3099     query = "SELECT `StdDlls`.`File`, `Binary`.`Data` "
3100             "FROM `StdDlls`, `Binary` ";
3101     r = MsiDatabaseOpenView(hdb, query, &hview);
3102     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3103
3104     r = MsiViewExecute(hview, 0);
3105     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3106
3107     i = 0;
3108     data_correct = TRUE;
3109     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3110     {
3111         count = MsiRecordGetFieldCount( hrec );
3112         ok( count == 2, "Expected 2 record fields, got %d\n", count );
3113
3114         size = MAX_PATH;
3115         r = MsiRecordGetString( hrec, 1, buf, &size );
3116         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3117         if( lstrcmp( buf, join_res_eighth[i].one ))
3118             data_correct = FALSE;
3119
3120         size = MAX_PATH;
3121         r = MsiRecordGetString( hrec, 2, buf, &size );
3122         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3123         if( lstrcmp( buf, join_res_eighth[i].four ))
3124             data_correct = FALSE;
3125
3126         i++;
3127         MsiCloseHandle(hrec);
3128     }
3129
3130     ok( data_correct, "data returned in the wrong order\n");
3131     ok( i == 6, "Expected 6 rows, got %d\n", i );
3132     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3133
3134     MsiViewClose(hview);
3135     MsiCloseHandle(hview);
3136
3137     query = "SELECT * FROM `StdDlls`, `Binary` ";
3138     r = MsiDatabaseOpenView(hdb, query, &hview);
3139     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3140
3141     r = MsiViewExecute(hview, 0);
3142     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3143
3144     i = 0;
3145     data_correct = TRUE;
3146     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3147     {
3148         count = MsiRecordGetFieldCount( hrec );
3149         ok( count == 4, "Expected 4 record fields, got %d\n", count );
3150
3151         size = MAX_PATH;
3152         r = MsiRecordGetString( hrec, 1, buf, &size );
3153         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3154         if( lstrcmp( buf, join_res_eighth[i].one ))
3155             data_correct = FALSE;
3156
3157         size = MAX_PATH;
3158         r = MsiRecordGetString( hrec, 2, buf, &size );
3159         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3160         if( lstrcmp( buf, join_res_eighth[i].two ))
3161             data_correct = FALSE;
3162
3163         size = MAX_PATH;
3164         r = MsiRecordGetString( hrec, 3, buf, &size );
3165         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3166         if( lstrcmp( buf, join_res_eighth[i].three ))
3167             data_correct = FALSE;
3168
3169         size = MAX_PATH;
3170         r = MsiRecordGetString( hrec, 4, buf, &size );
3171         ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3172         if( lstrcmp( buf, join_res_eighth[i].four ))
3173             data_correct = FALSE;
3174
3175         i++;
3176         MsiCloseHandle(hrec);
3177     }
3178     ok( data_correct, "data returned in the wrong order\n");
3179
3180     ok( i == 6, "Expected 6 rows, got %d\n", i );
3181     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3182
3183     MsiViewClose(hview);
3184     MsiCloseHandle(hview);
3185
3186     query = "SELECT * FROM `One`, `Two`, `Three` ";
3187     r = MsiDatabaseOpenView(hdb, query, &hview);
3188     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3189
3190     r = MsiViewExecute(hview, 0);
3191     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3192
3193     i = 0;
3194     data_correct = TRUE;
3195     while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3196     {
3197         count = MsiRecordGetFieldCount( hrec );
3198         ok( count == 6, "Expected 6 record fields, got %d\n", count );
3199
3200         r = MsiRecordGetInteger( hrec, 1 );
3201         if( r != join_res_ninth[i].one )
3202             data_correct = FALSE;
3203
3204         r = MsiRecordGetInteger( hrec, 2 );
3205         if( r != join_res_ninth[i].two )
3206             data_correct = FALSE;
3207
3208         r = MsiRecordGetInteger( hrec, 3 );
3209         if( r != join_res_ninth[i].three )
3210             data_correct = FALSE;
3211
3212         r = MsiRecordGetInteger( hrec, 4 );
3213         if( r != join_res_ninth[i].four )
3214             data_correct = FALSE;
3215
3216         r = MsiRecordGetInteger( hrec, 5 );
3217         if( r != join_res_ninth[i].five )
3218             data_correct = FALSE;
3219
3220         r = MsiRecordGetInteger( hrec, 6);
3221         if( r != join_res_ninth[i].six )
3222             data_correct = FALSE;
3223
3224         i++;
3225         MsiCloseHandle(hrec);
3226     }
3227     ok( data_correct, "data returned in the wrong order\n");
3228
3229     ok( i == 6, "Expected 6 rows, got %d\n", i );
3230     ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3231
3232     MsiViewClose(hview);
3233     MsiCloseHandle(hview);
3234
3235     query = "SELECT * FROM `Four`, `Five`";
3236     r = MsiDatabaseOpenView(hdb, query, &hview);
3237     ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3238
3239     r = MsiViewExecute(hview, 0);
3240     ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3241
3242     r = MsiViewFetch(hview, &hrec);
3243     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
3244
3245     MsiViewClose(hview);
3246     MsiCloseHandle(hview);
3247
3248     query = "SELECT * FROM `Nonexistent`, `One`";
3249     r = MsiDatabaseOpenView(hdb, query, &hview);
3250     ok( r == ERROR_BAD_QUERY_SYNTAX,
3251         "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r );
3252
3253     MsiCloseHandle(hdb);
3254     DeleteFile(msifile);
3255 }
3256
3257 static void test_temporary_table(void)
3258 {
3259     MSICONDITION cond;
3260     MSIHANDLE hdb = 0, view = 0, rec;
3261     const char *query;
3262     UINT r;
3263     char buf[0x10];
3264     DWORD sz;
3265
3266     cond = MsiDatabaseIsTablePersistent(0, NULL);
3267     ok( cond == MSICONDITION_ERROR, "wrong return condition\n");
3268
3269     hdb = create_db();
3270     ok( hdb, "failed to create db\n");
3271
3272     cond = MsiDatabaseIsTablePersistent(hdb, NULL);
3273     ok( cond == MSICONDITION_ERROR, "wrong return condition\n");
3274
3275     todo_wine {
3276     cond = MsiDatabaseIsTablePersistent(hdb, "_Tables");
3277     ok( cond == MSICONDITION_NONE, "wrong return condition\n");
3278
3279     cond = MsiDatabaseIsTablePersistent(hdb, "_Columns");
3280     ok( cond == MSICONDITION_NONE, "wrong return condition\n");
3281     }
3282
3283     cond = MsiDatabaseIsTablePersistent(hdb, "_Storages");
3284     ok( cond == MSICONDITION_NONE, "wrong return condition\n");
3285
3286     cond = MsiDatabaseIsTablePersistent(hdb, "_Streams");
3287     ok( cond == MSICONDITION_NONE, "wrong return condition\n");
3288
3289     query = "CREATE TABLE `P` ( `B` SHORT NOT NULL, `C` CHAR(255) PRIMARY KEY `C`)";
3290     r = run_query(hdb, 0, query);
3291     ok(r == ERROR_SUCCESS, "failed to add table\n");
3292
3293     cond = MsiDatabaseIsTablePersistent(hdb, "P");
3294     ok( cond == MSICONDITION_TRUE, "wrong return condition\n");
3295
3296     query = "CREATE TABLE `P2` ( `B` SHORT NOT NULL, `C` CHAR(255) PRIMARY KEY `C`) HOLD";
3297     r = run_query(hdb, 0, query);
3298     ok(r == ERROR_SUCCESS, "failed to add table\n");
3299
3300     cond = MsiDatabaseIsTablePersistent(hdb, "P2");
3301     ok( cond == MSICONDITION_TRUE, "wrong return condition\n");
3302
3303     query = "CREATE TABLE `T` ( `B` SHORT NOT NULL TEMPORARY, `C` CHAR(255) TEMPORARY PRIMARY KEY `C`) HOLD";
3304     r = run_query(hdb, 0, query);
3305     ok(r == ERROR_SUCCESS, "failed to add table\n");
3306
3307     cond = MsiDatabaseIsTablePersistent(hdb, "T");
3308     ok( cond == MSICONDITION_FALSE, "wrong return condition\n");
3309
3310     query = "CREATE TABLE `T2` ( `B` SHORT NOT NULL TEMPORARY, `C` CHAR(255) TEMPORARY PRIMARY KEY `C`)";
3311     r = run_query(hdb, 0, query);
3312     ok(r == ERROR_SUCCESS, "failed to add table\n");
3313
3314     todo_wine {
3315     cond = MsiDatabaseIsTablePersistent(hdb, "T2");
3316     ok( cond == MSICONDITION_NONE, "wrong return condition\n");
3317     }
3318
3319     query = "CREATE TABLE `T3` ( `B` SHORT NOT NULL TEMPORARY, `C` CHAR(255) PRIMARY KEY `C`)";
3320     r = run_query(hdb, 0, query);
3321     ok(r == ERROR_SUCCESS, "failed to add table\n");
3322
3323     cond = MsiDatabaseIsTablePersistent(hdb, "T3");
3324     ok( cond == MSICONDITION_TRUE, "wrong return condition\n");
3325
3326     todo_wine {
3327     query = "CREATE TABLE `T4` ( `B` SHORT NOT NULL, `C` CHAR(255) TEMPORARY PRIMARY KEY `C`)";
3328     r = run_query(hdb, 0, query);
3329     ok(r == ERROR_FUNCTION_FAILED, "failed to add table\n");
3330
3331     cond = MsiDatabaseIsTablePersistent(hdb, "T4");
3332     ok( cond == MSICONDITION_NONE, "wrong return condition\n");
3333     }
3334
3335     query = "CREATE TABLE `T5` ( `B` SHORT NOT NULL TEMP, `C` CHAR(255) TEMP PRIMARY KEY `C`) HOLD";
3336     r = run_query(hdb, 0, query);
3337     ok(r == ERROR_BAD_QUERY_SYNTAX, "failed to add table\n");
3338
3339     query = "select * from `T`";
3340     r = MsiDatabaseOpenView(hdb, query, &view);
3341     ok(r == ERROR_SUCCESS, "failed to query table\n");
3342     r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
3343     ok(r == ERROR_SUCCESS, "failed to get column info\n");
3344
3345     sz = sizeof buf;
3346     r = MsiRecordGetString(rec, 1, buf, &sz);
3347     ok(r == ERROR_SUCCESS, "failed to get string\n");
3348     todo_wine ok( 0 == strcmp("G255", buf), "wrong column type\n");
3349
3350     sz = sizeof buf;
3351     r = MsiRecordGetString(rec, 2, buf, &sz);
3352     ok(r == ERROR_SUCCESS, "failed to get string\n");
3353     todo_wine ok( 0 == strcmp("j2", buf), "wrong column type\n");
3354
3355     MsiCloseHandle( rec );
3356     MsiCloseHandle( view );
3357
3358     /* query the table data */
3359     rec = 0;
3360     r = do_query(hdb, "select * from `_Tables` where `Name` = 'T'", &rec);
3361     ok( r == ERROR_SUCCESS, "temporary table exists in _Tables\n");
3362     MsiCloseHandle( rec );
3363
3364     /* query the column data */
3365     rec = 0;
3366     r = do_query(hdb, "select * from `_Columns` where `Table` = 'T' AND `Name` = 'B'", &rec);
3367     ok( r == ERROR_NO_MORE_ITEMS, "temporary table exists in _Columns\n");
3368     if (rec) MsiCloseHandle( rec );
3369
3370     r = do_query(hdb, "select * from `_Columns` where `Table` = 'T' AND `Name` = 'C'", &rec);
3371     ok( r == ERROR_NO_MORE_ITEMS, "temporary table exists in _Columns\n");
3372     if (rec) MsiCloseHandle( rec );
3373
3374     MsiCloseHandle( hdb );
3375
3376     DeleteFile(msifile);
3377 }
3378
3379 static void test_alter(void)
3380 {
3381     MSICONDITION cond;
3382     MSIHANDLE hdb = 0;
3383     const char *query;
3384     UINT r;
3385
3386     hdb = create_db();
3387     ok( hdb, "failed to create db\n");
3388
3389     query = "CREATE TABLE `T` ( `B` SHORT NOT NULL TEMPORARY, `C` CHAR(255) TEMPORARY PRIMARY KEY `C`) HOLD";
3390     r = run_query(hdb, 0, query);
3391     ok(r == ERROR_SUCCESS, "failed to add table\n");
3392
3393     cond = MsiDatabaseIsTablePersistent(hdb, "T");
3394     ok( cond == MSICONDITION_FALSE, "wrong return condition\n");
3395
3396     query = "ALTER TABLE `T` HOLD";
3397     r = run_query(hdb, 0, query);
3398     ok(r == ERROR_SUCCESS, "failed to hold table %d\n", r);
3399
3400     query = "ALTER TABLE `T` FREE";
3401     r = run_query(hdb, 0, query);
3402     ok(r == ERROR_SUCCESS, "failed to free table\n");
3403
3404     query = "ALTER TABLE `T` FREE";
3405     r = run_query(hdb, 0, query);
3406     ok(r == ERROR_SUCCESS, "failed to free table\n");
3407
3408     query = "ALTER TABLE `T` FREE";
3409     r = run_query(hdb, 0, query);
3410     ok(r == ERROR_BAD_QUERY_SYNTAX, "failed to free table\n");
3411
3412     query = "ALTER TABLE `T` HOLD";
3413     r = run_query(hdb, 0, query);
3414     ok(r == ERROR_BAD_QUERY_SYNTAX, "failed to hold table %d\n", r);
3415
3416     /* table T is removed */
3417     query = "SELECT * FROM `T`";
3418     r = run_query(hdb, 0, query);
3419     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
3420
3421     /* create the table again */
3422     query = "CREATE TABLE `U` ( `A` INTEGER, `B` INTEGER PRIMARY KEY `B`)";
3423     r = run_query(hdb, 0, query);
3424     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3425
3426     /* up the ref count */
3427     query = "ALTER TABLE `U` HOLD";
3428     r = run_query(hdb, 0, query);
3429     ok(r == ERROR_SUCCESS, "failed to free table\n");
3430
3431     /* add column, no data type */
3432     query = "ALTER TABLE `U` ADD `C`";
3433     r = run_query(hdb, 0, query);
3434     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
3435
3436     query = "ALTER TABLE `U` ADD `C` INTEGER";
3437     r = run_query(hdb, 0, query);
3438     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3439
3440     /* add column C again */
3441     query = "ALTER TABLE `U` ADD `C` INTEGER";
3442     r = run_query(hdb, 0, query);
3443     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
3444
3445     query = "ALTER TABLE `U` ADD `D` INTEGER TEMPORARY";
3446     r = run_query(hdb, 0, query);
3447     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3448
3449     query = "INSERT INTO `U` ( `A`, `B`, `C`, `D` ) VALUES ( 1, 2, 3, 4 )";
3450     r = run_query(hdb, 0, query);
3451     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3452
3453     query = "ALTER TABLE `U` ADD `D` INTEGER TEMPORARY HOLD";
3454     r = run_query(hdb, 0, query);
3455     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
3456
3457     query = "INSERT INTO `U` ( `A`, `B`, `C`, `D` ) VALUES ( 5, 6, 7, 8 )";
3458     r = run_query(hdb, 0, query);
3459     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3460
3461     query = "SELECT * FROM `U` WHERE `D` = 8";
3462     r = run_query(hdb, 0, query);
3463     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3464
3465     query = "ALTER TABLE `U` ADD `D` INTEGER TEMPORARY FREE";
3466     r = run_query(hdb, 0, query);
3467     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
3468
3469     query = "ALTER COLUMN `D` FREE";
3470     r = run_query(hdb, 0, query);
3471     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
3472
3473     /* drop the ref count */
3474     query = "ALTER TABLE `U` FREE";
3475     r = run_query(hdb, 0, query);
3476     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3477
3478     /* table is not empty */
3479     query = "SELECT * FROM `U`";
3480     r = run_query(hdb, 0, query);
3481     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3482
3483     /* column D is removed */
3484     query = "SELECT * FROM `U` WHERE `D` = 8";
3485     r = run_query(hdb, 0, query);
3486     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
3487
3488     query = "INSERT INTO `U` ( `A`, `B`, `C`, `D` ) VALUES ( 9, 10, 11, 12 )";
3489     r = run_query(hdb, 0, query);
3490     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
3491
3492     /* add the column again */
3493     query = "ALTER TABLE `U` ADD `E` INTEGER TEMPORARY HOLD";
3494     r = run_query(hdb, 0, query);
3495     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3496
3497     /* up the ref count */
3498     query = "ALTER TABLE `U` HOLD";
3499     r = run_query(hdb, 0, query);
3500     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3501
3502     query = "INSERT INTO `U` ( `A`, `B`, `C`, `E` ) VALUES ( 13, 14, 15, 16 )";
3503     r = run_query(hdb, 0, query);
3504     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3505
3506     query = "SELECT * FROM `U` WHERE `E` = 16";
3507     r = run_query(hdb, 0, query);
3508     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3509
3510     /* drop the ref count */
3511     query = "ALTER TABLE `U` FREE";
3512     r = run_query(hdb, 0, query);
3513     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3514
3515     query = "INSERT INTO `U` ( `A`, `B`, `C`, `E` ) VALUES ( 17, 18, 19, 20 )";
3516     r = run_query(hdb, 0, query);
3517     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3518
3519     query = "SELECT * FROM `U` WHERE `E` = 20";
3520     r = run_query(hdb, 0, query);
3521     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3522
3523     /* drop the ref count */
3524     query = "ALTER TABLE `U` FREE";
3525     r = run_query(hdb, 0, query);
3526     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3527
3528     /* table still exists */
3529     query = "SELECT * FROM `U`";
3530     r = run_query(hdb, 0, query);
3531     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3532
3533     /* col E is removed */
3534     query = "SELECT * FROM `U` WHERE `E` = 20";
3535     r = run_query(hdb, 0, query);
3536     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
3537
3538     query = "INSERT INTO `U` ( `A`, `B`, `C`, `E` ) VALUES ( 20, 21, 22, 23 )";
3539     r = run_query(hdb, 0, query);
3540     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
3541
3542     /* drop the ref count once more */
3543     query = "ALTER TABLE `U` FREE";
3544     r = run_query(hdb, 0, query);
3545     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3546
3547     /* table still exists */
3548     query = "SELECT * FROM `U`";
3549     r = run_query(hdb, 0, query);
3550     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3551
3552     MsiCloseHandle( hdb );
3553     DeleteFile(msifile);
3554 }
3555
3556 static void test_integers(void)
3557 {
3558     MSIHANDLE hdb = 0, view = 0, rec = 0;
3559     DWORD count, i;
3560     const char *query;
3561     UINT r;
3562
3563     /* just MsiOpenDatabase should not create a file */
3564     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
3565     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
3566
3567     /* create a table */
3568     query = "CREATE TABLE `integers` ( "
3569             "`one` SHORT, `two` INT, `three` INTEGER, `four` LONG, "
3570             "`five` SHORT NOT NULL, `six` INT NOT NULL, "
3571             "`seven` INTEGER NOT NULL, `eight` LONG NOT NULL "
3572             "PRIMARY KEY `one`)";
3573     r = MsiDatabaseOpenView(hdb, query, &view);
3574     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
3575     r = MsiViewExecute(view, 0);
3576     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
3577     r = MsiViewClose(view);
3578     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
3579     r = MsiCloseHandle(view);
3580     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
3581
3582     query = "SELECT * FROM `integers`";
3583     r = MsiDatabaseOpenView(hdb, query, &view);
3584     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3585
3586     r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec);
3587     count = MsiRecordGetFieldCount(rec);
3588     ok(count == 8, "Expected 8, got %d\n", count);
3589     ok(check_record(rec, 1, "one"), "Expected one\n");
3590     ok(check_record(rec, 2, "two"), "Expected two\n");
3591     ok(check_record(rec, 3, "three"), "Expected three\n");
3592     ok(check_record(rec, 4, "four"), "Expected four\n");
3593     ok(check_record(rec, 5, "five"), "Expected five\n");
3594     ok(check_record(rec, 6, "six"), "Expected six\n");
3595     ok(check_record(rec, 7, "seven"), "Expected seven\n");
3596     ok(check_record(rec, 8, "eight"), "Expected eight\n");
3597     MsiCloseHandle(rec);
3598
3599     r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
3600     count = MsiRecordGetFieldCount(rec);
3601     ok(count == 8, "Expected 8, got %d\n", count);
3602     ok(check_record(rec, 1, "I2"), "Expected I2\n");
3603     ok(check_record(rec, 2, "I2"), "Expected I2\n");
3604     ok(check_record(rec, 3, "I2"), "Expected I2\n");
3605     ok(check_record(rec, 4, "I4"), "Expected I4\n");
3606     ok(check_record(rec, 5, "i2"), "Expected i2\n");
3607     ok(check_record(rec, 6, "i2"), "Expected i2\n");
3608     ok(check_record(rec, 7, "i2"), "Expected i2\n");
3609     ok(check_record(rec, 8, "i4"), "Expected i4\n");
3610     MsiCloseHandle(rec);
3611
3612     MsiViewClose(view);
3613     MsiCloseHandle(view);
3614
3615     /* insert values into it, NULL where NOT NULL is specified */
3616     query = "INSERT INTO `integers` ( `one`, `two`, `three`, `four`, `five`, `six`, `seven`, `eight` )"
3617         "VALUES('', '', '', '', '', '', '', '')";
3618     r = MsiDatabaseOpenView(hdb, query, &view);
3619     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3620     r = MsiViewExecute(view, 0);
3621     ok(r == ERROR_FUNCTION_FAILED, "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
3622
3623     MsiViewClose(view);
3624     MsiCloseHandle(view);
3625
3626     query = "SELECT * FROM `integers`";
3627     r = do_query(hdb, query, &rec);
3628     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
3629
3630     r = MsiRecordGetFieldCount(rec);
3631     ok(r == -1, "record count wrong: %d\n", r);
3632
3633     MsiCloseHandle(rec);
3634
3635     /* insert legitimate values into it */
3636     query = "INSERT INTO `integers` ( `one`, `two`, `three`, `four`, `five`, `six`, `seven`, `eight` )"
3637         "VALUES('', '2', '', '4', '5', '6', '7', '8')";
3638     r = MsiDatabaseOpenView(hdb, query, &view);
3639     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3640     r = MsiViewExecute(view, 0);
3641     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3642
3643     query = "SELECT * FROM `integers`";
3644     r = do_query(hdb, query, &rec);
3645     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3646
3647     r = MsiRecordGetFieldCount(rec);
3648     ok(r == 8, "record count wrong: %d\n", r);
3649
3650     i = MsiRecordGetInteger(rec, 1);
3651     ok(i == MSI_NULL_INTEGER, "Expected MSI_NULL_INTEGER, got %d\n", i);
3652     i = MsiRecordGetInteger(rec, 3);
3653     ok(i == MSI_NULL_INTEGER, "Expected MSI_NULL_INTEGER, got %d\n", i);
3654     i = MsiRecordGetInteger(rec, 2);
3655     ok(i == 2, "Expected 2, got %d\n", i);
3656     i = MsiRecordGetInteger(rec, 4);
3657     ok(i == 4, "Expected 4, got %d\n", i);
3658     i = MsiRecordGetInteger(rec, 5);
3659     ok(i == 5, "Expected 5, got %d\n", i);
3660     i = MsiRecordGetInteger(rec, 6);
3661     ok(i == 6, "Expected 6, got %d\n", i);
3662     i = MsiRecordGetInteger(rec, 7);
3663     ok(i == 7, "Expected 7, got %d\n", i);
3664     i = MsiRecordGetInteger(rec, 8);
3665     ok(i == 8, "Expected 8, got %d\n", i);
3666
3667     MsiCloseHandle(rec);
3668     MsiViewClose(view);
3669     MsiCloseHandle(view);
3670
3671     r = MsiDatabaseCommit(hdb);
3672     ok(r == ERROR_SUCCESS, "MsiDatabaseCommit failed\n");
3673
3674     r = MsiCloseHandle(hdb);
3675     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
3676
3677     r = DeleteFile(msifile);
3678     ok(r == TRUE, "file didn't exist after commit\n");
3679 }
3680
3681 static void test_update(void)
3682 {
3683     MSIHANDLE hdb = 0, view = 0, rec = 0;
3684     CHAR result[MAX_PATH];
3685     const char *query;
3686     DWORD size;
3687     UINT r;
3688
3689     /* just MsiOpenDatabase should not create a file */
3690     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
3691     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
3692
3693     /* create the Control table */
3694     query = "CREATE TABLE `Control` ( "
3695         "`Dialog_` CHAR(72) NOT NULL, `Control` CHAR(50) NOT NULL, `Type` SHORT NOT NULL, "
3696         "`X` SHORT NOT NULL, `Y` SHORT NOT NULL, `Width` SHORT NOT NULL, `Height` SHORT NOT NULL,"
3697         "`Attributes` LONG, `Property` CHAR(50), `Text` CHAR(0) LOCALIZABLE, "
3698         "`Control_Next` CHAR(50), `Help` CHAR(50) LOCALIZABLE PRIMARY KEY `Dialog_`, `Control`)";
3699     r = MsiDatabaseOpenView(hdb, query, &view);
3700     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
3701     r = MsiViewExecute(view, 0);
3702     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
3703     r = MsiViewClose(view);
3704     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
3705     r = MsiCloseHandle(view);
3706     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
3707
3708     /* add a control */
3709     query = "INSERT INTO `Control` ( "
3710         "`Dialog_`, `Control`, `Type`, `X`, `Y`, `Width`, `Height`, "
3711         "`Property`, `Text`, `Control_Next`, `Help` )"
3712         "VALUES('ErrorDialog', 'ErrorText', '1', '5', '5', '5', '5', '', '', '', '')";
3713     r = MsiDatabaseOpenView(hdb, query, &view);
3714     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3715     r = MsiViewExecute(view, 0);
3716     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3717     r = MsiViewClose(view);
3718     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
3719     r = MsiCloseHandle(view);
3720     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
3721
3722     /* add a second control */
3723     query = "INSERT INTO `Control` ( "
3724         "`Dialog_`, `Control`, `Type`, `X`, `Y`, `Width`, `Height`, "
3725         "`Property`, `Text`, `Control_Next`, `Help` )"
3726         "VALUES('ErrorDialog', 'Button', '1', '5', '5', '5', '5', '', '', '', '')";
3727     r = MsiDatabaseOpenView(hdb, query, &view);
3728     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3729     r = MsiViewExecute(view, 0);
3730     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3731     r = MsiViewClose(view);
3732     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
3733     r = MsiCloseHandle(view);
3734     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
3735
3736     /* add a third control */
3737     query = "INSERT INTO `Control` ( "
3738         "`Dialog_`, `Control`, `Type`, `X`, `Y`, `Width`, `Height`, "
3739         "`Property`, `Text`, `Control_Next`, `Help` )"
3740         "VALUES('AnotherDialog', 'ErrorText', '1', '5', '5', '5', '5', '', '', '', '')";
3741     r = MsiDatabaseOpenView(hdb, query, &view);
3742     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3743     r = MsiViewExecute(view, 0);
3744     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3745     r = MsiViewClose(view);
3746     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
3747     r = MsiCloseHandle(view);
3748     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
3749
3750     /* bad table */
3751     query = "UPDATE `NotATable` SET `Text` = 'this is text' WHERE `Dialog_` = 'ErrorDialog'";
3752     r = MsiDatabaseOpenView(hdb, query, &view);
3753     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
3754
3755     /* bad set column */
3756     query = "UPDATE `Control` SET `NotAColumn` = 'this is text' WHERE `Dialog_` = 'ErrorDialog'";
3757     r = MsiDatabaseOpenView(hdb, query, &view);
3758     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
3759
3760     /* bad where condition */
3761     query = "UPDATE `Control` SET `Text` = 'this is text' WHERE `NotAColumn` = 'ErrorDialog'";
3762     r = MsiDatabaseOpenView(hdb, query, &view);
3763     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
3764
3765     /* just the dialog_ specified */
3766     query = "UPDATE `Control` SET `Text` = 'this is text' WHERE `Dialog_` = 'ErrorDialog'";
3767     r = MsiDatabaseOpenView(hdb, query, &view);
3768     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3769     r = MsiViewExecute(view, 0);
3770     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3771     r = MsiViewClose(view);
3772     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
3773     r = MsiCloseHandle(view);
3774     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
3775
3776     /* check the modified text */
3777     query = "SELECT `Text` FROM `Control` WHERE `Control` = 'ErrorText'";
3778     r = MsiDatabaseOpenView(hdb, query, &view);
3779     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3780     r = MsiViewExecute(view, 0);
3781     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3782
3783     r = MsiViewFetch(view, &rec);
3784     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3785
3786     size = MAX_PATH;
3787     r = MsiRecordGetString(rec, 1, result, &size);
3788     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3789     ok(!lstrcmp(result, "this is text"), "Expected `this is text`, got %s\n", result);
3790
3791     MsiCloseHandle(rec);
3792
3793     r = MsiViewFetch(view, &rec);
3794     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3795
3796     size = MAX_PATH;
3797     r = MsiRecordGetString(rec, 1, result, &size);
3798     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3799     ok(!lstrlen(result), "Expected an empty string, got %s\n", result);
3800
3801     MsiCloseHandle(rec);
3802
3803     r = MsiViewFetch(view, &rec);
3804     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
3805
3806     r = MsiViewClose(view);
3807     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
3808     r = MsiCloseHandle(view);
3809     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
3810
3811     /* dialog_ and control specified */
3812     query = "UPDATE `Control` SET `Text` = 'this is text' WHERE `Dialog_` = 'ErrorDialog' AND `Control` = 'ErrorText'";
3813     r = MsiDatabaseOpenView(hdb, query, &view);
3814     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3815     r = MsiViewExecute(view, 0);
3816     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3817     r = MsiViewClose(view);
3818     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
3819     r = MsiCloseHandle(view);
3820     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
3821
3822     /* check the modified text */
3823     query = "SELECT `Text` FROM `Control` WHERE `Control` = 'ErrorText'";
3824     r = MsiDatabaseOpenView(hdb, query, &view);
3825     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3826     r = MsiViewExecute(view, 0);
3827     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3828
3829     r = MsiViewFetch(view, &rec);
3830     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3831
3832     size = MAX_PATH;
3833     r = MsiRecordGetString(rec, 1, result, &size);
3834     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3835     ok(!lstrcmp(result, "this is text"), "Expected `this is text`, got %s\n", result);
3836
3837     MsiCloseHandle(rec);
3838
3839     r = MsiViewFetch(view, &rec);
3840     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3841
3842     size = MAX_PATH;
3843     r = MsiRecordGetString(rec, 1, result, &size);
3844     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3845     ok(!lstrlen(result), "Expected an empty string, got %s\n", result);
3846
3847     MsiCloseHandle(rec);
3848
3849     r = MsiViewFetch(view, &rec);
3850     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
3851
3852     r = MsiViewClose(view);
3853     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
3854     r = MsiCloseHandle(view);
3855     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
3856
3857     /* no where condition */
3858     query = "UPDATE `Control` SET `Text` = 'this is text'";
3859     r = MsiDatabaseOpenView(hdb, query, &view);
3860     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3861     r = MsiViewExecute(view, 0);
3862     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3863     r = MsiViewClose(view);
3864     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
3865     r = MsiCloseHandle(view);
3866     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
3867
3868     /* check the modified text */
3869     query = "SELECT `Text` FROM `Control`";
3870     r = MsiDatabaseOpenView(hdb, query, &view);
3871     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3872     r = MsiViewExecute(view, 0);
3873     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3874
3875     r = MsiViewFetch(view, &rec);
3876     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3877
3878     size = MAX_PATH;
3879     r = MsiRecordGetString(rec, 1, result, &size);
3880     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3881     ok(!lstrcmp(result, "this is text"), "Expected `this is text`, got %s\n", result);
3882
3883     MsiCloseHandle(rec);
3884
3885     r = MsiViewFetch(view, &rec);
3886     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3887
3888     size = MAX_PATH;
3889     r = MsiRecordGetString(rec, 1, result, &size);
3890     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3891     ok(!lstrcmp(result, "this is text"), "Expected `this is text`, got %s\n", result);
3892
3893     MsiCloseHandle(rec);
3894
3895     r = MsiViewFetch(view, &rec);
3896     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3897
3898     size = MAX_PATH;
3899     r = MsiRecordGetString(rec, 1, result, &size);
3900     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3901     ok(!lstrcmp(result, "this is text"), "Expected `this is text`, got %s\n", result);
3902
3903     MsiCloseHandle(rec);
3904
3905     r = MsiViewFetch(view, &rec);
3906     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
3907
3908     r = MsiViewClose(view);
3909     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
3910     r = MsiCloseHandle(view);
3911     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
3912
3913     query = "CREATE TABLE `Apple` ( `Banana` CHAR(72) NOT NULL, "
3914         "`Orange` CHAR(72),  `Pear` INT PRIMARY KEY `Banana`)";
3915     r = run_query(hdb, 0, query);
3916     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3917
3918     query = "INSERT INTO `Apple` ( `Banana`, `Orange`, `Pear` )"
3919         "VALUES('one', 'two', 3)";
3920     r = run_query(hdb, 0, query);
3921     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3922
3923     query = "INSERT INTO `Apple` ( `Banana`, `Orange`, `Pear` )"
3924         "VALUES('three', 'four', 5)";
3925     r = run_query(hdb, 0, query);
3926     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3927
3928     query = "INSERT INTO `Apple` ( `Banana`, `Orange`, `Pear` )"
3929         "VALUES('six', 'two', 7)";
3930     r = run_query(hdb, 0, query);
3931     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3932
3933     rec = MsiCreateRecord(2);
3934     MsiRecordSetInteger(rec, 1, 8);
3935     MsiRecordSetString(rec, 2, "two");
3936
3937     query = "UPDATE `Apple` SET `Pear` = ? WHERE `Orange` = ?";
3938     r = run_query(hdb, rec, query);
3939     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3940
3941     MsiCloseHandle(rec);
3942
3943     query = "SELECT `Pear` FROM `Apple` ORDER BY `Orange`";
3944     r = MsiDatabaseOpenView(hdb, query, &view);
3945     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3946     r = MsiViewExecute(view, 0);
3947     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3948
3949     r = MsiViewFetch(view, &rec);
3950     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3951
3952     r = MsiRecordGetInteger(rec, 1);
3953     ok(r == 8, "Expected 8, got %d\n", r);
3954
3955     MsiCloseHandle(rec);
3956
3957     r = MsiViewFetch(view, &rec);
3958     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3959
3960     r = MsiRecordGetInteger(rec, 1);
3961     ok(r == 8, "Expected 8, got %d\n", r);
3962
3963     MsiCloseHandle(rec);
3964
3965     r = MsiViewFetch(view, &rec);
3966     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3967
3968     r = MsiRecordGetInteger(rec, 1);
3969     ok(r == 5, "Expected 5, got %d\n", r);
3970
3971     MsiCloseHandle(rec);
3972
3973     r = MsiViewFetch(view, &rec);
3974     ok(r == ERROR_NO_MORE_ITEMS, "Expectd ERROR_NO_MORE_ITEMS, got %d\n", r);
3975
3976     MsiViewClose(view);
3977     MsiCloseHandle(view);
3978
3979     r = MsiDatabaseCommit(hdb);
3980     ok(r == ERROR_SUCCESS, "MsiDatabaseCommit failed\n");
3981     r = MsiCloseHandle(hdb);
3982     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
3983
3984     DeleteFile(msifile);
3985 }
3986
3987 static void test_special_tables(void)
3988 {
3989     const char *query;
3990     MSIHANDLE hdb = 0;
3991     UINT r;
3992
3993     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
3994     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
3995
3996     query = "CREATE TABLE `_Properties` ( "
3997         "`foo` INT NOT NULL, `bar` INT LOCALIZABLE PRIMARY KEY `foo`)";
3998     r = run_query(hdb, 0, query);
3999     ok(r == ERROR_SUCCESS, "failed to create table\n");
4000
4001     query = "CREATE TABLE `_Storages` ( "
4002         "`foo` INT NOT NULL, `bar` INT LOCALIZABLE PRIMARY KEY `foo`)";
4003     r = run_query(hdb, 0, query);
4004     todo_wine ok(r == ERROR_BAD_QUERY_SYNTAX, "created _Streams table\n");
4005
4006     query = "CREATE TABLE `_Streams` ( "
4007         "`foo` INT NOT NULL, `bar` INT LOCALIZABLE PRIMARY KEY `foo`)";
4008     r = run_query(hdb, 0, query);
4009     todo_wine ok(r == ERROR_BAD_QUERY_SYNTAX, "created _Streams table\n");
4010
4011     query = "CREATE TABLE `_Tables` ( "
4012         "`foo` INT NOT NULL, `bar` INT LOCALIZABLE PRIMARY KEY `foo`)";
4013     r = run_query(hdb, 0, query);
4014     ok(r == ERROR_BAD_QUERY_SYNTAX, "created _Tables table\n");
4015
4016     query = "CREATE TABLE `_Columns` ( "
4017         "`foo` INT NOT NULL, `bar` INT LOCALIZABLE PRIMARY KEY `foo`)";
4018     r = run_query(hdb, 0, query);
4019     ok(r == ERROR_BAD_QUERY_SYNTAX, "created _Columns table\n");
4020
4021     r = MsiCloseHandle(hdb);
4022     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4023 }
4024
4025 static void test_select_markers(void)
4026 {
4027     MSIHANDLE hdb = 0, rec, view, res;
4028     LPCSTR query;
4029     UINT r;
4030     DWORD size;
4031     CHAR buf[MAX_PATH];
4032
4033     hdb = create_db();
4034     ok( hdb, "failed to create db\n");
4035
4036     r = run_query(hdb, 0,
4037             "CREATE TABLE `Table` (`One` CHAR(72), `Two` CHAR(72), `Three` SHORT PRIMARY KEY `One`, `Two`, `Three`)");
4038     ok(r == S_OK, "cannot create table: %d\n", r);
4039
4040     r = run_query(hdb, 0, "INSERT INTO `Table` "
4041             "( `One`, `Two`, `Three` ) VALUES ( 'apple', 'one', 1 )");
4042     ok(r == S_OK, "cannot add file to the Media table: %d\n", r);
4043
4044     r = run_query(hdb, 0, "INSERT INTO `Table` "
4045             "( `One`, `Two`, `Three` ) VALUES ( 'apple', 'two', 1 )");
4046     ok(r == S_OK, "cannot add file to the Media table: %d\n", r);
4047
4048     r = run_query(hdb, 0, "INSERT INTO `Table` "
4049             "( `One`, `Two`, `Three` ) VALUES ( 'apple', 'two', 2 )");
4050     ok(r == S_OK, "cannot add file to the Media table: %d\n", r);
4051
4052     r = run_query(hdb, 0, "INSERT INTO `Table` "
4053             "( `One`, `Two`, `Three` ) VALUES ( 'banana', 'three', 3 )");
4054     ok(r == S_OK, "cannot add file to the Media table: %d\n", r);
4055
4056     rec = MsiCreateRecord(2);
4057     MsiRecordSetString(rec, 1, "apple");
4058     MsiRecordSetString(rec, 2, "two");
4059
4060     query = "SELECT * FROM `Table` WHERE `One`=? AND `Two`=? ORDER BY `Three`";
4061     r = MsiDatabaseOpenView(hdb, query, &view);
4062     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4063
4064     r = MsiViewExecute(view, rec);
4065     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4066
4067     r = MsiViewFetch(view, &res);
4068     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4069
4070     size = MAX_PATH;
4071     r = MsiRecordGetString(res, 1, buf, &size);
4072     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4073     ok(!lstrcmp(buf, "apple"), "Expected apple, got %s\n", buf);
4074
4075     size = MAX_PATH;
4076     r = MsiRecordGetString(res, 2, buf, &size);
4077     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4078     ok(!lstrcmp(buf, "two"), "Expected two, got %s\n", buf);
4079
4080     r = MsiRecordGetInteger(res, 3);
4081     ok(r == 1, "Expected 1, got %d\n", r);
4082
4083     MsiCloseHandle(res);
4084
4085     r = MsiViewFetch(view, &res);
4086     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4087
4088     size = MAX_PATH;
4089     r = MsiRecordGetString(res, 1, buf, &size);
4090     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4091     ok(!lstrcmp(buf, "apple"), "Expected apple, got %s\n", buf);
4092
4093     size = MAX_PATH;
4094     r = MsiRecordGetString(res, 2, buf, &size);
4095     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4096     ok(!lstrcmp(buf, "two"), "Expected two, got %s\n", buf);
4097
4098     r = MsiRecordGetInteger(res, 3);
4099     ok(r == 2, "Expected 2, got %d\n", r);
4100
4101     MsiCloseHandle(res);
4102
4103     r = MsiViewFetch(view, &res);
4104     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
4105
4106     MsiCloseHandle(rec);
4107     MsiViewClose(view);
4108     MsiCloseHandle(view);
4109
4110     rec = MsiCreateRecord(2);
4111     MsiRecordSetString(rec, 1, "one");
4112     MsiRecordSetInteger(rec, 2, 1);
4113
4114     query = "SELECT * FROM `Table` WHERE `Two`<>? AND `Three`>? ORDER BY `Three`";
4115     r = MsiDatabaseOpenView(hdb, query, &view);
4116     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4117     r = MsiViewExecute(view, rec);
4118     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4119
4120     r = MsiViewFetch(view, &res);
4121     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4122
4123     size = MAX_PATH;
4124     r = MsiRecordGetString(res, 1, buf, &size);
4125     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4126     ok(!lstrcmp(buf, "apple"), "Expected apple, got %s\n", buf);
4127
4128     size = MAX_PATH;
4129     r = MsiRecordGetString(res, 2, buf, &size);
4130     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4131     ok(!lstrcmp(buf, "two"), "Expected two, got %s\n", buf);
4132
4133     r = MsiRecordGetInteger(res, 3);
4134     ok(r == 2, "Expected 2, got %d\n", r);
4135
4136     MsiCloseHandle(res);
4137
4138     r = MsiViewFetch(view, &res);
4139     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4140
4141     size = MAX_PATH;
4142     r = MsiRecordGetString(res, 1, buf, &size);
4143     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4144     ok(!lstrcmp(buf, "banana"), "Expected banana, got %s\n", buf);
4145
4146     size = MAX_PATH;
4147     r = MsiRecordGetString(res, 2, buf, &size);
4148     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4149     ok(!lstrcmp(buf, "three"), "Expected three, got %s\n", buf);
4150
4151     r = MsiRecordGetInteger(res, 3);
4152     ok(r == 3, "Expected 3, got %d\n", r);
4153
4154     MsiCloseHandle(res);
4155
4156     r = MsiViewFetch(view, &res);
4157     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
4158
4159     MsiCloseHandle(rec);
4160     MsiViewClose(view);
4161     MsiCloseHandle(view);
4162     MsiCloseHandle(hdb);
4163     DeleteFile(msifile);
4164 }
4165
4166 static void test_viewmodify_update(void)
4167 {
4168     MSIHANDLE hdb = 0, hview = 0, hrec = 0;
4169     const char *query;
4170     UINT r;
4171
4172     DeleteFile(msifile);
4173
4174     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
4175     ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
4176
4177     query = "CREATE TABLE `table` (`A` INT, `B` INT PRIMARY KEY `A`)";
4178     r = run_query( hdb, 0, query );
4179     ok(r == ERROR_SUCCESS, "query failed\n");
4180
4181     query = "INSERT INTO `table` (`A`, `B`) VALUES (1, 2)";
4182     r = run_query( hdb, 0, query );
4183     ok(r == ERROR_SUCCESS, "query failed\n");
4184
4185     query = "INSERT INTO `table` (`A`, `B`) VALUES (3, 4)";
4186     r = run_query( hdb, 0, query );
4187     ok(r == ERROR_SUCCESS, "query failed\n");
4188
4189     query = "INSERT INTO `table` (`A`, `B`) VALUES (5, 6)";
4190     r = run_query( hdb, 0, query );
4191     ok(r == ERROR_SUCCESS, "query failed\n");
4192
4193     query = "SELECT `B` FROM `table`";
4194     r = MsiDatabaseOpenView(hdb, query, &hview);
4195     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
4196     r = MsiViewExecute(hview, 0);
4197     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
4198     r = MsiViewFetch(hview, &hrec);
4199     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4200
4201     r = MsiRecordSetInteger(hrec, 1, 0);
4202     ok(r == ERROR_SUCCESS, "failed to set integer\n");
4203
4204     r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
4205     ok(r == ERROR_SUCCESS, "MsiViewModify failed: %d\n", r);
4206
4207     r = MsiCloseHandle(hrec);
4208     ok(r == ERROR_SUCCESS, "failed to close record\n");
4209
4210     r = MsiViewClose(hview);
4211     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4212     r = MsiCloseHandle(hview);
4213     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4214
4215     query = "SELECT * FROM `table`";
4216     r = MsiDatabaseOpenView(hdb, query, &hview);
4217     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
4218     r = MsiViewExecute(hview, 0);
4219     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
4220     r = MsiViewFetch(hview, &hrec);
4221     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4222
4223     r = MsiRecordGetInteger(hrec, 1);
4224     ok(r == 1, "Expected 1, got %d\n", r);
4225     r = MsiRecordGetInteger(hrec, 2);
4226     ok(r == 0, "Expected 0, got %d\n", r);
4227
4228     r = MsiCloseHandle(hrec);
4229     ok(r == ERROR_SUCCESS, "failed to close record\n");
4230
4231     r = MsiViewFetch(hview, &hrec);
4232     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4233
4234     r = MsiRecordGetInteger(hrec, 1);
4235     ok(r == 3, "Expected 3, got %d\n", r);
4236     r = MsiRecordGetInteger(hrec, 2);
4237     ok(r == 4, "Expected 4, got %d\n", r);
4238
4239     r = MsiCloseHandle(hrec);
4240     ok(r == ERROR_SUCCESS, "failed to close record\n");
4241
4242     r = MsiViewFetch(hview, &hrec);
4243     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4244
4245     r = MsiRecordGetInteger(hrec, 1);
4246     ok(r == 5, "Expected 5, got %d\n", r);
4247     r = MsiRecordGetInteger(hrec, 2);
4248     ok(r == 6, "Expected 6, got %d\n", r);
4249
4250     r = MsiCloseHandle(hrec);
4251     ok(r == ERROR_SUCCESS, "failed to close record\n");
4252
4253     r = MsiViewFetch(hview, &hrec);
4254     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
4255
4256     r = MsiViewClose(hview);
4257     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4258     r = MsiCloseHandle(hview);
4259     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4260
4261     /* loop through all elements */
4262     query = "SELECT `B` FROM `table`";
4263     r = MsiDatabaseOpenView(hdb, query, &hview);
4264     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
4265     r = MsiViewExecute(hview, 0);
4266     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
4267
4268     while (TRUE)
4269     {
4270         r = MsiViewFetch(hview, &hrec);
4271         if (r != ERROR_SUCCESS)
4272             break;
4273
4274         r = MsiRecordSetInteger(hrec, 1, 0);
4275         ok(r == ERROR_SUCCESS, "failed to set integer\n");
4276
4277         r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
4278         ok(r == ERROR_SUCCESS, "MsiViewModify failed: %d\n", r);
4279
4280         r = MsiCloseHandle(hrec);
4281         ok(r == ERROR_SUCCESS, "failed to close record\n");
4282     }
4283
4284     r = MsiViewClose(hview);
4285     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4286     r = MsiCloseHandle(hview);
4287     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4288
4289     query = "SELECT * FROM `table`";
4290     r = MsiDatabaseOpenView(hdb, query, &hview);
4291     ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
4292     r = MsiViewExecute(hview, 0);
4293     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
4294     r = MsiViewFetch(hview, &hrec);
4295     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4296
4297     r = MsiRecordGetInteger(hrec, 1);
4298     ok(r == 1, "Expected 1, got %d\n", r);
4299     r = MsiRecordGetInteger(hrec, 2);
4300     ok(r == 0, "Expected 0, got %d\n", r);
4301
4302     r = MsiCloseHandle(hrec);
4303     ok(r == ERROR_SUCCESS, "failed to close record\n");
4304
4305     r = MsiViewFetch(hview, &hrec);
4306     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4307
4308     r = MsiRecordGetInteger(hrec, 1);
4309     ok(r == 3, "Expected 3, got %d\n", r);
4310     r = MsiRecordGetInteger(hrec, 2);
4311     ok(r == 0, "Expected 0, got %d\n", r);
4312
4313     r = MsiCloseHandle(hrec);
4314     ok(r == ERROR_SUCCESS, "failed to close record\n");
4315
4316     r = MsiViewFetch(hview, &hrec);
4317     ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
4318
4319     r = MsiRecordGetInteger(hrec, 1);
4320     ok(r == 5, "Expected 5, got %d\n", r);
4321     r = MsiRecordGetInteger(hrec, 2);
4322     ok(r == 0, "Expected 0, got %d\n", r);
4323
4324     r = MsiCloseHandle(hrec);
4325     ok(r == ERROR_SUCCESS, "failed to close record\n");
4326
4327     r = MsiViewFetch(hview, &hrec);
4328     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
4329
4330     r = MsiViewClose(hview);
4331     ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
4332     r = MsiCloseHandle(hview);
4333     ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
4334
4335     r = MsiCloseHandle( hdb );
4336     ok(r == ERROR_SUCCESS, "MsiOpenDatabase close failed\n");
4337 }
4338
4339 static const WCHAR data10[] = { /* MOO */
4340     0x8001, 0x000b,
4341 };
4342 static const WCHAR data11[] = { /* AAR */
4343     0x8002, 0x8005,
4344     0x000c, 0x000f,
4345 };
4346 static const char data12[] = /* _StringData */
4347     "MOOABAARCDonetwofourfive";
4348 static const WCHAR data13[] = { /* _StringPool */
4349 /*  len, refs */
4350     0,   0,    /* string 0 ''     */
4351     0,   0,    /* string 1 ''     */
4352     0,   0,    /* string 2 ''     */
4353     0,   0,    /* string 3 ''     */
4354     0,   0,    /* string 4 ''     */
4355     3,   3,    /* string 5 'MOO'  */
4356     1,   1,    /* string 6 'A'    */
4357     1,   1,    /* string 7 'B'    */
4358     3,   3,    /* string 8 'AAR'  */
4359     1,   1,    /* string 9 'C'    */
4360     1,   1,    /* string a 'D'    */
4361     3,   1,    /* string b 'one'  */
4362     3,   1,    /* string c 'two'  */
4363     0,   0,    /* string d ''     */
4364     4,   1,    /* string e 'four' */
4365     4,   1,    /* string f 'five' */
4366 };
4367
4368 static void test_stringtable(void)
4369 {
4370     MSIHANDLE hdb = 0, hview = 0, hrec = 0;
4371     IStorage *stg = NULL;
4372     IStream *stm;
4373     WCHAR name[0x20];
4374     HRESULT hr;
4375     const char *query;
4376     char buffer[MAX_PATH];
4377     WCHAR data[MAX_PATH];
4378     DWORD sz, read;
4379     UINT r;
4380
4381     static const DWORD mode = STGM_DIRECT | STGM_READ | STGM_SHARE_DENY_WRITE;
4382     static const WCHAR stringdata[] = {0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0}; /* _StringData */
4383     static const WCHAR stringpool[] = {0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0}; /* _StringPool */
4384     static const WCHAR moo[] = {0x4840, 0x3e16, 0x4818, 0}; /* MOO */
4385     static const WCHAR aar[] = {0x4840, 0x3a8a, 0x481b, 0}; /* AAR */
4386
4387     DeleteFile(msifile);
4388
4389     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
4390     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4391
4392     query = "CREATE TABLE `MOO` (`A` INT, `B` CHAR(72) PRIMARY KEY `A`)";
4393     r = run_query(hdb, 0, query);
4394     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4395
4396     query = "CREATE TABLE `AAR` (`C` INT, `D` CHAR(72) PRIMARY KEY `C`)";
4397     r = run_query(hdb, 0, query);
4398     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4399
4400     /* insert persistent row */
4401     query = "INSERT INTO `MOO` (`A`, `B`) VALUES (1, 'one')";
4402     r = run_query(hdb, 0, query);
4403     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4404
4405     /* insert persistent row */
4406     query = "INSERT INTO `AAR` (`C`, `D`) VALUES (2, 'two')";
4407     r = run_query(hdb, 0, query);
4408     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4409
4410     /* open a view */
4411     query = "SELECT * FROM `MOO`";
4412     r = MsiDatabaseOpenView(hdb, query, &hview);
4413     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4414     r = MsiViewExecute(hview, 0);
4415     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4416
4417     hrec = MsiCreateRecord(2);
4418
4419     r = MsiRecordSetInteger(hrec, 1, 3);
4420     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4421     r = MsiRecordSetString(hrec, 2, "three");
4422     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4423
4424     /* insert a nonpersistent row */
4425     r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec);
4426     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4427
4428     r = MsiCloseHandle(hrec);
4429     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4430     r = MsiViewClose(hview);
4431     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4432     r = MsiCloseHandle(hview);
4433     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4434
4435     /* insert persistent row */
4436     query = "INSERT INTO `MOO` (`A`, `B`) VALUES (4, 'four')";
4437     r = run_query(hdb, 0, query);
4438     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4439
4440     /* insert persistent row */
4441     query = "INSERT INTO `AAR` (`C`, `D`) VALUES (5, 'five')";
4442     r = run_query(hdb, 0, query);
4443     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4444
4445     r = MsiDatabaseCommit(hdb);
4446     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4447
4448     r = MsiCloseHandle(hdb);
4449     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4450
4451     r = MsiOpenDatabase(msifile, MSIDBOPEN_READONLY, &hdb);
4452     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4453
4454     query = "SELECT * FROM `MOO`";
4455     r = MsiDatabaseOpenView(hdb, query, &hview);
4456     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4457
4458     r = MsiViewExecute(hview, 0);
4459     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4460
4461     r = MsiViewFetch(hview, &hrec);
4462     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4463
4464     r = MsiRecordGetFieldCount(hrec);
4465     ok(r == 2, "Expected 2, got %d\n", r);
4466
4467     r = MsiRecordGetInteger(hrec, 1);
4468     ok(r == 1, "Expected 1, got %d\n", r);
4469
4470     sz = sizeof(buffer);
4471     r = MsiRecordGetString(hrec, 2, buffer, &sz);
4472     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4473     ok(!lstrcmp(buffer, "one"), "Expected one, got %s\n", buffer);
4474
4475     r = MsiCloseHandle(hrec);
4476     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4477
4478     r = MsiViewFetch(hview, &hrec);
4479     todo_wine
4480     {
4481         ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
4482     }
4483
4484     r = MsiViewClose(hview);
4485     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4486     r = MsiCloseHandle(hview);
4487     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4488     r = MsiCloseHandle(hrec);
4489     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4490
4491     query = "SELECT * FROM `AAR`";
4492     r = MsiDatabaseOpenView(hdb, query, &hview);
4493     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4494
4495     r = MsiViewExecute(hview, 0);
4496     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4497
4498     r = MsiViewFetch(hview, &hrec);
4499     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4500
4501     r = MsiRecordGetFieldCount(hrec);
4502     ok(r == 2, "Expected 2, got %d\n", r);
4503
4504     r = MsiRecordGetInteger(hrec, 1);
4505     ok(r == 2, "Expected 2, got %d\n", r);
4506
4507     sz = sizeof(buffer);
4508     r = MsiRecordGetString(hrec, 2, buffer, &sz);
4509     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4510     ok(!lstrcmp(buffer, "two"), "Expected two, got %s\n", buffer);
4511
4512     r = MsiCloseHandle(hrec);
4513     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4514
4515     r = MsiViewFetch(hview, &hrec);
4516     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4517
4518     r = MsiRecordGetFieldCount(hrec);
4519     ok(r == 2, "Expected 2, got %d\n", r);
4520
4521     r = MsiRecordGetInteger(hrec, 1);
4522     ok(r == 5, "Expected 5, got %d\n", r);
4523
4524     sz = sizeof(buffer);
4525     r = MsiRecordGetString(hrec, 2, buffer, &sz);
4526     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4527     ok(!lstrcmp(buffer, "five"), "Expected five, got %s\n", buffer);
4528
4529     r = MsiCloseHandle(hrec);
4530     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4531
4532     r = MsiViewFetch(hview, &hrec);
4533     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
4534
4535     r = MsiViewClose(hview);
4536     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4537     r = MsiCloseHandle(hview);
4538     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4539     r = MsiCloseHandle(hrec);
4540     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4541     r = MsiCloseHandle(hdb);
4542     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4543
4544     MultiByteToWideChar(CP_ACP, 0, msifile, -1, name, 0x20);
4545     hr = StgOpenStorage(name, NULL, mode, NULL, 0, &stg);
4546     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
4547     ok(stg != NULL, "Expected non-NULL storage\n");
4548
4549     hr = IStorage_OpenStream(stg, moo, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm);
4550     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
4551     ok(stm != NULL, "Expected non-NULL stream\n");
4552
4553     hr = IStream_Read(stm, data, MAX_PATH, &read);
4554     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
4555     todo_wine
4556     {
4557         ok(read == 4, "Expected 4, got %d\n", read);
4558         ok(!memcmp(data, data10, read), "Unexpected data\n");
4559     }
4560
4561     hr = IStream_Release(stm);
4562     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
4563
4564     hr = IStorage_OpenStream(stg, aar, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm);
4565     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
4566     ok(stm != NULL, "Expected non-NULL stream\n");
4567
4568     hr = IStream_Read(stm, data, MAX_PATH, &read);
4569     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
4570     ok(read == 8, "Expected 8, got %d\n", read);
4571     todo_wine
4572     {
4573         ok(!memcmp(data, data11, read), "Unexpected data\n");
4574     }
4575
4576     hr = IStream_Release(stm);
4577     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
4578
4579     hr = IStorage_OpenStream(stg, stringdata, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm);
4580     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
4581     ok(stm != NULL, "Expected non-NULL stream\n");
4582
4583     hr = IStream_Read(stm, buffer, MAX_PATH, &read);
4584     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
4585     ok(read == 24, "Expected 24, got %d\n", read);
4586     ok(!memcmp(buffer, data12, read), "Unexpected data\n");
4587
4588     hr = IStream_Release(stm);
4589     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
4590
4591     hr = IStorage_OpenStream(stg, stringpool, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm);
4592     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
4593     ok(stm != NULL, "Expected non-NULL stream\n");
4594
4595     hr = IStream_Read(stm, data, MAX_PATH, &read);
4596     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
4597     todo_wine
4598     {
4599         ok(read == 64, "Expected 64, got %d\n", read);
4600         ok(!memcmp(data, data13, read), "Unexpected data\n");
4601     }
4602
4603     hr = IStream_Release(stm);
4604     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
4605
4606     hr = IStorage_Release(stg);
4607     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
4608
4609     DeleteFileA(msifile);
4610 }
4611
4612 static void test_viewmodify_delete(void)
4613 {
4614     MSIHANDLE hdb = 0, hview = 0, hrec = 0;
4615     UINT r;
4616     const char *query;
4617     char buffer[0x100];
4618     DWORD sz;
4619
4620     DeleteFile(msifile);
4621
4622     /* just MsiOpenDatabase should not create a file */
4623     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
4624     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4625
4626     query = "CREATE TABLE `phone` ( "
4627             "`id` INT, `name` CHAR(32), `number` CHAR(32) "
4628             "PRIMARY KEY `id`)";
4629     r = run_query(hdb, 0, query);
4630     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4631
4632     query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
4633         "VALUES('1', 'Alan', '5030581')";
4634     r = run_query(hdb, 0, query);
4635     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4636
4637     query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
4638         "VALUES('2', 'Barry', '928440')";
4639     r = run_query(hdb, 0, query);
4640     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4641
4642     query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
4643         "VALUES('3', 'Cindy', '2937550')";
4644     r = run_query(hdb, 0, query);
4645     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4646
4647     query = "SELECT * FROM `phone` WHERE `id` <= 2";
4648     r = MsiDatabaseOpenView(hdb, query, &hview);
4649     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4650     r = MsiViewExecute(hview, 0);
4651     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4652     r = MsiViewFetch(hview, &hrec);
4653     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4654
4655     /* delete 1 */
4656     r = MsiViewModify(hview, MSIMODIFY_DELETE, hrec);
4657     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4658
4659     r = MsiCloseHandle(hrec);
4660     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4661     r = MsiViewFetch(hview, &hrec);
4662     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4663
4664     /* delete 2 */
4665     r = MsiViewModify(hview, MSIMODIFY_DELETE, hrec);
4666     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4667
4668     r = MsiCloseHandle(hrec);
4669     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4670     r = MsiViewClose(hview);
4671     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4672     r = MsiCloseHandle(hview);
4673     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4674
4675     query = "SELECT * FROM `phone`";
4676     r = MsiDatabaseOpenView(hdb, query, &hview);
4677     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4678     r = MsiViewExecute(hview, 0);
4679     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4680     r = MsiViewFetch(hview, &hrec);
4681     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4682
4683     r = MsiRecordGetInteger(hrec, 1);
4684     ok(r == 3, "Expected 3, got %d\n", r);
4685
4686     sz = sizeof(buffer);
4687     r = MsiRecordGetString(hrec, 2, buffer, &sz);
4688     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4689     ok(!lstrcmp(buffer, "Cindy"), "Expected Cindy, got %s\n", buffer);
4690
4691     sz = sizeof(buffer);
4692     r = MsiRecordGetString(hrec, 3, buffer, &sz);
4693     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4694     ok(!lstrcmp(buffer, "2937550"), "Expected 2937550, got %s\n", buffer);
4695
4696     r = MsiCloseHandle(hrec);
4697     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4698
4699     r = MsiViewFetch(hview, &hrec);
4700     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
4701
4702     r = MsiViewClose(hview);
4703     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4704     r = MsiCloseHandle(hview);
4705     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4706     r = MsiCloseHandle(hdb);
4707     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4708 }
4709
4710 static const WCHAR _Tables[] = {0x4840, 0x3f7f, 0x4164, 0x422f, 0x4836, 0};
4711 static const WCHAR _StringData[] = {0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0};
4712 static const WCHAR _StringPool[] = {0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0};
4713
4714 static const WCHAR data14[] = { /* _StringPool */
4715 /*  len, refs */
4716     0,   0,    /* string 0 ''    */
4717 };
4718
4719 static const struct {
4720     LPCWSTR name;
4721     const void *data;
4722     DWORD size;
4723 } database_table_data[] =
4724 {
4725     {_Tables, NULL, 0},
4726     {_StringData, NULL, 0},
4727     {_StringPool, data14, sizeof data14},
4728 };
4729
4730 void enum_stream_names(IStorage *stg)
4731 {
4732     IEnumSTATSTG *stgenum = NULL;
4733     IStream *stm;
4734     HRESULT hr;
4735     STATSTG stat;
4736     ULONG n, count;
4737     BYTE data[MAX_PATH];
4738     BYTE check[MAX_PATH];
4739     DWORD sz;
4740
4741     memset(check, 'a', MAX_PATH);
4742
4743     hr = IStorage_EnumElements(stg, 0, NULL, 0, &stgenum);
4744     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
4745
4746     n = 0;
4747     while(TRUE)
4748     {
4749         count = 0;
4750         hr = IEnumSTATSTG_Next(stgenum, 1, &stat, &count);
4751         if(FAILED(hr) || !count)
4752             break;
4753
4754         ok(!lstrcmpW(stat.pwcsName, database_table_data[n].name),
4755            "Expected table %d name to match\n", n);
4756
4757         stm = NULL;
4758         hr = IStorage_OpenStream(stg, stat.pwcsName, NULL,
4759                                  STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm);
4760         ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
4761         ok(stm != NULL, "Expected non-NULL stream\n");
4762
4763         sz = MAX_PATH;
4764         memset(data, 'a', MAX_PATH);
4765         hr = IStream_Read(stm, data, sz, &count);
4766         ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
4767
4768         ok(count == database_table_data[n].size,
4769            "Expected %d, got %d\n", database_table_data[n].size, count);
4770
4771         if (!database_table_data[n].size)
4772             ok(!memcmp(data, check, MAX_PATH), "data should not be changed\n");
4773         else
4774             ok(!memcmp(data, database_table_data[n].data, database_table_data[n].size),
4775                "Expected table %d data to match\n", n);
4776
4777         IStream_Release(stm);
4778         n++;
4779     }
4780
4781     ok(n == 3, "Expected 3, got %d\n", n);
4782
4783     IEnumSTATSTG_Release(stgenum);
4784 }
4785
4786 static void test_defaultdatabase(void)
4787 {
4788     UINT r;
4789     HRESULT hr;
4790     MSIHANDLE hdb;
4791     IStorage *stg = NULL;
4792
4793     static const WCHAR msifileW[] = {'w','i','n','e','t','e','s','t','.','m','s','i',0};
4794
4795     DeleteFile(msifile);
4796
4797     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
4798     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4799
4800     r = MsiDatabaseCommit(hdb);
4801     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4802
4803     MsiCloseHandle(hdb);
4804
4805     hr = StgOpenStorage(msifileW, NULL, STGM_READ | STGM_SHARE_DENY_WRITE, NULL, 0, &stg);
4806     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
4807     ok(stg != NULL, "Expected non-NULL stg\n");
4808
4809     enum_stream_names(stg);
4810
4811     IStorage_Release(stg);
4812     DeleteFileA(msifile);
4813 }
4814
4815 static void test_order(void)
4816 {
4817     MSIHANDLE hdb, hview, hrec;
4818     CHAR buffer[MAX_PATH];
4819     LPCSTR query;
4820     UINT r, sz;
4821     int val;
4822
4823     hdb = create_db();
4824     ok(hdb, "failed to create db\n");
4825
4826     query = "CREATE TABLE `Empty` ( `A` SHORT NOT NULL PRIMARY KEY `A`)";
4827     r = run_query(hdb, 0, query);
4828     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4829
4830     query = "CREATE TABLE `Mesa` ( `A` SHORT NOT NULL, `B` SHORT, `C` SHORT PRIMARY KEY `A`)";
4831     r = run_query(hdb, 0, query);
4832     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4833
4834     query = "INSERT INTO `Mesa` ( `A`, `B`, `C` ) VALUES ( 1, 2, 9 )";
4835     r = run_query(hdb, 0, query);
4836     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4837
4838     query = "INSERT INTO `Mesa` ( `A`, `B`, `C` ) VALUES ( 3, 4, 7 )";
4839     r = run_query(hdb, 0, query);
4840     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4841
4842     query = "INSERT INTO `Mesa` ( `A`, `B`, `C` ) VALUES ( 5, 6, 8 )";
4843     r = run_query(hdb, 0, query);
4844     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4845
4846     query = "CREATE TABLE `Sideboard` ( `D` SHORT NOT NULL, `E` SHORT, `F` SHORT PRIMARY KEY `D`)";
4847     r = run_query(hdb, 0, query);
4848     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4849
4850     query = "INSERT INTO `Sideboard` ( `D`, `E`, `F` ) VALUES ( 10, 11, 18 )";
4851     r = run_query(hdb, 0, query);
4852     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4853
4854     query = "INSERT INTO `Sideboard` ( `D`, `E`, `F` ) VALUES ( 12, 13, 16 )";
4855     r = run_query(hdb, 0, query);
4856     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4857
4858     query = "INSERT INTO `Sideboard` ( `D`, `E`, `F` ) VALUES ( 14, 15, 17 )";
4859     r = run_query(hdb, 0, query);
4860     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4861
4862     query = "SELECT `A`, `B` FROM `Mesa` ORDER BY `C`";
4863     r = MsiDatabaseOpenView(hdb, query, &hview);
4864     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4865     r = MsiViewExecute(hview, 0);
4866     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4867
4868     r = MsiViewFetch(hview, &hrec);
4869     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4870
4871     val = MsiRecordGetInteger(hrec, 1);
4872     ok(val == 3, "Expected 3, got %d\n", val);
4873
4874     val = MsiRecordGetInteger(hrec, 2);
4875     ok(val == 4, "Expected 3, got %d\n", val);
4876
4877     MsiCloseHandle(hrec);
4878
4879     r = MsiViewFetch(hview, &hrec);
4880     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4881
4882     val = MsiRecordGetInteger(hrec, 1);
4883     ok(val == 5, "Expected 5, got %d\n", val);
4884
4885     val = MsiRecordGetInteger(hrec, 2);
4886     ok(val == 6, "Expected 6, got %d\n", val);
4887
4888     MsiCloseHandle(hrec);
4889
4890     r = MsiViewFetch(hview, &hrec);
4891     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4892
4893     val = MsiRecordGetInteger(hrec, 1);
4894     ok(val == 1, "Expected 1, got %d\n", val);
4895
4896     val = MsiRecordGetInteger(hrec, 2);
4897     ok(val == 2, "Expected 2, got %d\n", val);
4898
4899     MsiCloseHandle(hrec);
4900
4901     r = MsiViewFetch(hview, &hrec);
4902     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
4903
4904     MsiViewClose(hview);
4905     MsiCloseHandle(hview);
4906
4907     query = "SELECT `A`, `D` FROM `Mesa`, `Sideboard` ORDER BY `F`";
4908     r = MsiDatabaseOpenView(hdb, query, &hview);
4909     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4910     r = MsiViewExecute(hview, 0);
4911     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4912
4913     r = MsiViewFetch(hview, &hrec);
4914     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4915
4916     val = MsiRecordGetInteger(hrec, 1);
4917     ok(val == 1, "Expected 1, got %d\n", val);
4918
4919     val = MsiRecordGetInteger(hrec, 2);
4920     ok(val == 12, "Expected 12, got %d\n", val);
4921
4922     MsiCloseHandle(hrec);
4923
4924     r = MsiViewFetch(hview, &hrec);
4925     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4926
4927     val = MsiRecordGetInteger(hrec, 1);
4928     ok(val == 3, "Expected 3, got %d\n", val);
4929
4930     val = MsiRecordGetInteger(hrec, 2);
4931     ok(val == 12, "Expected 12, got %d\n", val);
4932
4933     MsiCloseHandle(hrec);
4934
4935     r = MsiViewFetch(hview, &hrec);
4936     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4937
4938     val = MsiRecordGetInteger(hrec, 1);
4939     ok(val == 5, "Expected 5, got %d\n", val);
4940
4941     val = MsiRecordGetInteger(hrec, 2);
4942     ok(val == 12, "Expected 12, got %d\n", val);
4943
4944     MsiCloseHandle(hrec);
4945
4946     r = MsiViewFetch(hview, &hrec);
4947     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4948
4949     val = MsiRecordGetInteger(hrec, 1);
4950     ok(val == 1, "Expected 1, got %d\n", val);
4951
4952     val = MsiRecordGetInteger(hrec, 2);
4953     ok(val == 14, "Expected 14, got %d\n", val);
4954
4955     MsiCloseHandle(hrec);
4956
4957     r = MsiViewFetch(hview, &hrec);
4958     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4959
4960     val = MsiRecordGetInteger(hrec, 1);
4961     ok(val == 3, "Expected 3, got %d\n", val);
4962
4963     val = MsiRecordGetInteger(hrec, 2);
4964     ok(val == 14, "Expected 14, got %d\n", val);
4965
4966     MsiCloseHandle(hrec);
4967
4968     r = MsiViewFetch(hview, &hrec);
4969     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4970
4971     val = MsiRecordGetInteger(hrec, 1);
4972     ok(val == 5, "Expected 5, got %d\n", val);
4973
4974     val = MsiRecordGetInteger(hrec, 2);
4975     ok(val == 14, "Expected 14, got %d\n", val);
4976
4977     MsiCloseHandle(hrec);
4978
4979     r = MsiViewFetch(hview, &hrec);
4980     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4981
4982     val = MsiRecordGetInteger(hrec, 1);
4983     ok(val == 1, "Expected 1, got %d\n", val);
4984
4985     val = MsiRecordGetInteger(hrec, 2);
4986     ok(val == 10, "Expected 10, got %d\n", val);
4987
4988     MsiCloseHandle(hrec);
4989
4990     r = MsiViewFetch(hview, &hrec);
4991     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
4992
4993     val = MsiRecordGetInteger(hrec, 1);
4994     ok(val == 3, "Expected 3, got %d\n", val);
4995
4996     val = MsiRecordGetInteger(hrec, 2);
4997     ok(val == 10, "Expected 10, got %d\n", val);
4998
4999     MsiCloseHandle(hrec);
5000
5001     r = MsiViewFetch(hview, &hrec);
5002     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5003
5004     val = MsiRecordGetInteger(hrec, 1);
5005     ok(val == 5, "Expected 5, got %d\n", val);
5006
5007     val = MsiRecordGetInteger(hrec, 2);
5008     ok(val == 10, "Expected 10, got %d\n", val);
5009
5010     MsiCloseHandle(hrec);
5011
5012     r = MsiViewFetch(hview, &hrec);
5013     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5014
5015     MsiViewClose(hview);
5016     MsiCloseHandle(hview);
5017
5018     query = "SELECT * FROM `Empty` ORDER BY `A`";
5019     r = MsiDatabaseOpenView(hdb, query, &hview);
5020     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5021     r = MsiViewExecute(hview, 0);
5022     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5023
5024     r = MsiViewFetch(hview, &hrec);
5025     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5026
5027     MsiViewClose(hview);
5028     MsiCloseHandle(hview);
5029
5030     query = "CREATE TABLE `Buffet` ( `One` CHAR(72), `Two` SHORT PRIMARY KEY `One`)";
5031     r = run_query(hdb, 0, query);
5032     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5033
5034     query = "INSERT INTO `Buffet` ( `One`, `Two` ) VALUES ( 'uno',  2)";
5035     r = run_query(hdb, 0, query);
5036     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5037
5038     query = "INSERT INTO `Buffet` ( `One`, `Two` ) VALUES ( 'dos',  3)";
5039     r = run_query(hdb, 0, query);
5040     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5041
5042     query = "INSERT INTO `Buffet` ( `One`, `Two` ) VALUES ( 'tres',  1)";
5043     r = run_query(hdb, 0, query);
5044     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5045
5046     query = "SELECT * FROM `Buffet` WHERE `One` = 'dos' ORDER BY `Two`";
5047     r = MsiDatabaseOpenView(hdb, query, &hview);
5048     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5049     r = MsiViewExecute(hview, 0);
5050     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5051
5052     r = MsiViewFetch(hview, &hrec);
5053     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5054
5055     sz = sizeof(buffer);
5056     r = MsiRecordGetString(hrec, 1, buffer, &sz);
5057     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5058     ok(!lstrcmp(buffer, "dos"), "Expected \"dos\", got \"%s\"\n", buffer);
5059
5060     r = MsiRecordGetInteger(hrec, 2);
5061     ok(r == 3, "Expected 3, got %d\n", r);
5062
5063     MsiCloseHandle(hrec);
5064
5065     r = MsiViewFetch(hview, &hrec);
5066     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5067
5068     MsiViewClose(hview);
5069     MsiCloseHandle(hview);
5070     MsiCloseHandle(hdb);
5071 }
5072
5073 static void test_viewmodify_delete_temporary(void)
5074 {
5075     MSIHANDLE hdb, hview, hrec;
5076     const char *query;
5077     UINT r;
5078
5079     DeleteFile(msifile);
5080
5081     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
5082     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5083
5084     query = "CREATE TABLE `Table` ( `A` SHORT PRIMARY KEY `A` )";
5085     r = run_query(hdb, 0, query);
5086     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5087
5088     query = "SELECT * FROM `Table`";
5089     r = MsiDatabaseOpenView(hdb, query, &hview);
5090     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5091     r = MsiViewExecute(hview, 0);
5092     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5093
5094     hrec = MsiCreateRecord(1);
5095     MsiRecordSetInteger(hrec, 1, 1);
5096
5097     r = MsiViewModify(hview, MSIMODIFY_INSERT, hrec);
5098     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5099
5100     MsiCloseHandle(hrec);
5101
5102     hrec = MsiCreateRecord(1);
5103     MsiRecordSetInteger(hrec, 1, 2);
5104
5105     r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec);
5106     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5107
5108     MsiCloseHandle(hrec);
5109
5110     hrec = MsiCreateRecord(1);
5111     MsiRecordSetInteger(hrec, 1, 3);
5112
5113     r = MsiViewModify(hview, MSIMODIFY_INSERT, hrec);
5114     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5115
5116     MsiCloseHandle(hrec);
5117
5118     hrec = MsiCreateRecord(1);
5119     MsiRecordSetInteger(hrec, 1, 4);
5120
5121     r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec);
5122     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5123
5124     MsiCloseHandle(hrec);
5125     MsiViewClose(hview);
5126     MsiCloseHandle(hview);
5127
5128     query = "SELECT * FROM `Table` WHERE  `A` = 2";
5129     r = MsiDatabaseOpenView(hdb, query, &hview);
5130     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5131     r = MsiViewExecute(hview, 0);
5132     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5133     r = MsiViewFetch(hview, &hrec);
5134     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5135
5136     r = MsiViewModify(hview, MSIMODIFY_DELETE, hrec);
5137     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5138
5139     MsiCloseHandle(hrec);
5140     MsiViewClose(hview);
5141     MsiCloseHandle(hview);
5142
5143     query = "SELECT * FROM `Table` WHERE  `A` = 3";
5144     r = MsiDatabaseOpenView(hdb, query, &hview);
5145     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5146     r = MsiViewExecute(hview, 0);
5147     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5148     r = MsiViewFetch(hview, &hrec);
5149     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5150
5151     r = MsiViewModify(hview, MSIMODIFY_DELETE, hrec);
5152     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5153
5154     MsiCloseHandle(hrec);
5155     MsiViewClose(hview);
5156     MsiCloseHandle(hview);
5157
5158     query = "SELECT * FROM `Table` ORDER BY `A`";
5159     r = MsiDatabaseOpenView(hdb, query, &hview);
5160     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5161     r = MsiViewExecute(hview, 0);
5162     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5163
5164     r = MsiViewFetch(hview, &hrec);
5165     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5166
5167     r = MsiRecordGetInteger(hrec, 1);
5168     ok(r == 1, "Expected 1, got %d\n", r);
5169
5170     MsiCloseHandle(hrec);
5171
5172     r = MsiViewFetch(hview, &hrec);
5173     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5174
5175     r = MsiRecordGetInteger(hrec, 1);
5176     ok(r == 4, "Expected 4, got %d\n", r);
5177
5178     MsiCloseHandle(hrec);
5179
5180     r = MsiViewFetch(hview, &hrec);
5181     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5182
5183     MsiViewClose(hview);
5184     MsiCloseHandle(hview);
5185     MsiCloseHandle(hdb);
5186     DeleteFileA(msifile);
5187 }
5188
5189 static void test_deleterow()
5190 {
5191     MSIHANDLE hdb, hview, hrec;
5192     const char *query;
5193     char buf[MAX_PATH];
5194     UINT r;
5195     DWORD size;
5196
5197     DeleteFile(msifile);
5198
5199     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
5200     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5201
5202     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
5203     r = run_query(hdb, 0, query);
5204     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5205
5206     query = "INSERT INTO `Table` (`A`) VALUES ('one')";
5207     r = run_query(hdb, 0, query);
5208     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5209
5210     query = "INSERT INTO `Table` (`A`) VALUES ('two')";
5211     r = run_query(hdb, 0, query);
5212     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5213
5214     query = "DELETE FROM `Table` WHERE `A` = 'one'";
5215     r = run_query(hdb, 0, query);
5216     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5217
5218     r = MsiDatabaseCommit(hdb);
5219     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5220
5221     MsiCloseHandle(hdb);
5222
5223     r = MsiOpenDatabase(msifile, MSIDBOPEN_READONLY, &hdb);
5224     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5225
5226     query = "SELECT * FROM `Table`";
5227     r = MsiDatabaseOpenView(hdb, query, &hview);
5228     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5229     r = MsiViewExecute(hview, 0);
5230     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5231
5232     r = MsiViewFetch(hview, &hrec);
5233     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5234
5235     size = MAX_PATH;
5236     r = MsiRecordGetStringA(hrec, 1, buf, &size);
5237     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5238     ok(!lstrcmpA(buf, "two"), "Expected two, got %s\n", buf);
5239
5240     MsiCloseHandle(hrec);
5241
5242     r = MsiViewFetch(hview, &hrec);
5243     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5244
5245     MsiViewClose(hview);
5246     MsiCloseHandle(hview);
5247     MsiCloseHandle(hdb);
5248     DeleteFileA(msifile);
5249 }
5250
5251 static const CHAR import_dat[] = "A\n"
5252                                  "s72\n"
5253                                  "Table\tA\n"
5254                                  "This is a new 'string' ok\n";
5255
5256 static void test_quotes(void)
5257 {
5258     MSIHANDLE hdb, hview, hrec;
5259     const char *query;
5260     char buf[MAX_PATH];
5261     UINT r;
5262     DWORD size;
5263
5264     DeleteFile(msifile);
5265
5266     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
5267     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5268
5269     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
5270     r = run_query(hdb, 0, query);
5271     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5272
5273     query = "INSERT INTO `Table` ( `A` ) VALUES ( 'This is a 'string' ok' )";
5274     r = run_query(hdb, 0, query);
5275     ok(r == ERROR_BAD_QUERY_SYNTAX,
5276        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5277
5278     query = "INSERT INTO `Table` ( `A` ) VALUES ( \"This is a 'string' ok\" )";
5279     r = run_query(hdb, 0, query);
5280     ok(r == ERROR_BAD_QUERY_SYNTAX,
5281        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5282
5283     query = "INSERT INTO `Table` ( `A` ) VALUES ( \"test\" )";
5284     r = run_query(hdb, 0, query);
5285     ok(r == ERROR_BAD_QUERY_SYNTAX,
5286        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5287
5288     query = "INSERT INTO `Table` ( `A` ) VALUES ( 'This is a ''string'' ok' )";
5289     r = run_query(hdb, 0, query);
5290     todo_wine
5291     {
5292         ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5293     }
5294
5295     query = "INSERT INTO `Table` ( `A` ) VALUES ( 'This is a '''string''' ok' )";
5296     r = run_query(hdb, 0, query);
5297     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5298
5299     query = "INSERT INTO `Table` ( `A` ) VALUES ( 'This is a \'string\' ok' )";
5300     r = run_query(hdb, 0, query);
5301     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5302
5303     query = "INSERT INTO `Table` ( `A` ) VALUES ( 'This is a \"string\" ok' )";
5304     r = run_query(hdb, 0, query);
5305     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5306
5307     query = "SELECT * FROM `Table`";
5308     r = MsiDatabaseOpenView(hdb, query, &hview);
5309     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5310
5311     r = MsiViewExecute(hview, 0);
5312     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5313
5314     r = MsiViewFetch(hview, &hrec);
5315     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5316
5317     size = MAX_PATH;
5318     r = MsiRecordGetString(hrec, 1, buf, &size);
5319     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5320     todo_wine
5321     {
5322         ok(!lstrcmp(buf, "This is a \"string\" ok"),
5323            "Expected \"This is a \"string\" ok\", got %s\n", buf);
5324     }
5325
5326     MsiCloseHandle(hrec);
5327
5328     r = MsiViewFetch(hview, &hrec);
5329     todo_wine
5330     {
5331         ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5332     }
5333
5334     MsiCloseHandle(hview);
5335
5336     write_file("import.idt", import_dat, (sizeof(import_dat) - 1) * sizeof(char));
5337
5338     r = MsiDatabaseImportA(hdb, CURR_DIR, "import.idt");
5339     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5340
5341     DeleteFileA("import.idt");
5342
5343     query = "SELECT * FROM `Table`";
5344     r = MsiDatabaseOpenView(hdb, query, &hview);
5345     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5346
5347     r = MsiViewExecute(hview, 0);
5348     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5349
5350     r = MsiViewFetch(hview, &hrec);
5351     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5352
5353     size = MAX_PATH;
5354     r = MsiRecordGetString(hrec, 1, buf, &size);
5355     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5356     ok(!lstrcmp(buf, "This is a new 'string' ok"),
5357        "Expected \"This is a new 'string' ok\", got %s\n", buf);
5358
5359     MsiCloseHandle(hrec);
5360
5361     r = MsiViewFetch(hview, &hrec);
5362     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5363
5364     MsiCloseHandle(hview);
5365
5366     MsiCloseHandle(hdb);
5367     DeleteFileA(msifile);
5368 }
5369
5370 static void test_carriagereturn(void)
5371 {
5372     MSIHANDLE hdb, hview, hrec;
5373     const char *query;
5374     char buf[MAX_PATH];
5375     UINT r;
5376     DWORD size;
5377
5378     DeleteFile(msifile);
5379
5380     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
5381     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5382
5383     query = "CREATE TABLE `Table`\r ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
5384     r = run_query(hdb, 0, query);
5385     todo_wine
5386     {
5387         ok(r == ERROR_BAD_QUERY_SYNTAX,
5388            "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5389     }
5390
5391     query = "CREATE TABLE `Table` \r( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
5392     r = run_query(hdb, 0, query);
5393     ok(r == ERROR_BAD_QUERY_SYNTAX,
5394        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5395
5396     query = "CREATE\r TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
5397     r = run_query(hdb, 0, query);
5398     ok(r == ERROR_BAD_QUERY_SYNTAX,
5399        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5400
5401     query = "CREATE TABLE\r `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
5402     r = run_query(hdb, 0, query);
5403     ok(r == ERROR_BAD_QUERY_SYNTAX,
5404        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5405
5406     query = "CREATE TABLE `Table` (\r `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
5407     r = run_query(hdb, 0, query);
5408     ok(r == ERROR_BAD_QUERY_SYNTAX,
5409        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5410
5411     query = "CREATE TABLE `Table` ( `A`\r CHAR(72) NOT NULL PRIMARY KEY `A` )";
5412     r = run_query(hdb, 0, query);
5413     ok(r == ERROR_BAD_QUERY_SYNTAX,
5414        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5415
5416     query = "CREATE TABLE `Table` ( `A` CHAR(72)\r NOT NULL PRIMARY KEY `A` )";
5417     r = run_query(hdb, 0, query);
5418     ok(r == ERROR_BAD_QUERY_SYNTAX,
5419        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5420
5421     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT\r NULL PRIMARY KEY `A` )";
5422     r = run_query(hdb, 0, query);
5423     ok(r == ERROR_BAD_QUERY_SYNTAX,
5424        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5425
5426     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT \rNULL PRIMARY KEY `A` )";
5427     r = run_query(hdb, 0, query);
5428     ok(r == ERROR_BAD_QUERY_SYNTAX,
5429        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5430
5431     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL\r PRIMARY KEY `A` )";
5432     r = run_query(hdb, 0, query);
5433     ok(r == ERROR_BAD_QUERY_SYNTAX,
5434        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5435
5436     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL \rPRIMARY KEY `A` )";
5437     r = run_query(hdb, 0, query);
5438     ok(r == ERROR_BAD_QUERY_SYNTAX,
5439        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5440
5441     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY\r KEY `A` )";
5442     r = run_query(hdb, 0, query);
5443     ok(r == ERROR_BAD_QUERY_SYNTAX,
5444        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5445
5446     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY \rKEY `A` )";
5447     r = run_query(hdb, 0, query);
5448     ok(r == ERROR_BAD_QUERY_SYNTAX,
5449        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5450
5451     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY\r `A` )";
5452     r = run_query(hdb, 0, query);
5453     ok(r == ERROR_BAD_QUERY_SYNTAX,
5454        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5455
5456     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A`\r )";
5457     r = run_query(hdb, 0, query);
5458     ok(r == ERROR_BAD_QUERY_SYNTAX,
5459        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5460
5461     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )\r";
5462     r = run_query(hdb, 0, query);
5463     ok(r == ERROR_BAD_QUERY_SYNTAX,
5464        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5465
5466     query = "CREATE TABLE `\rOne` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
5467     r = run_query(hdb, 0, query);
5468     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5469
5470     query = "CREATE TABLE `Tw\ro` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
5471     r = run_query(hdb, 0, query);
5472     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5473
5474     query = "CREATE TABLE `Three\r` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
5475     r = run_query(hdb, 0, query);
5476     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5477
5478     query = "CREATE TABLE `Four` ( `A\r` CHAR(72) NOT NULL PRIMARY KEY `A` )";
5479     r = run_query(hdb, 0, query);
5480     ok(r == ERROR_BAD_QUERY_SYNTAX,
5481        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5482
5483     query = "CREATE TABLE `Four` ( `\rA` CHAR(72) NOT NULL PRIMARY KEY `A` )";
5484     r = run_query(hdb, 0, query);
5485     ok(r == ERROR_BAD_QUERY_SYNTAX,
5486        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5487
5488     query = "CREATE TABLE `Four` ( `A` CHAR(72\r) NOT NULL PRIMARY KEY `A` )";
5489     r = run_query(hdb, 0, query);
5490     todo_wine
5491     {
5492         ok(r == ERROR_BAD_QUERY_SYNTAX,
5493            "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5494     }
5495
5496     query = "CREATE TABLE `Four` ( `A` CHAR(\r72) NOT NULL PRIMARY KEY `A` )";
5497     r = run_query(hdb, 0, query);
5498     ok(r == ERROR_BAD_QUERY_SYNTAX,
5499        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5500
5501     query = "CREATE TABLE `Four` ( `A` CHAR(72) NOT NULL PRIMARY KEY `\rA` )";
5502     r = run_query(hdb, 0, query);
5503     ok(r == ERROR_BAD_QUERY_SYNTAX,
5504        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5505
5506     query = "CREATE TABLE `Four` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A\r` )";
5507     r = run_query(hdb, 0, query);
5508     ok(r == ERROR_BAD_QUERY_SYNTAX,
5509        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5510
5511     query = "CREATE TABLE `Four` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A\r` )";
5512     r = run_query(hdb, 0, query);
5513     ok(r == ERROR_BAD_QUERY_SYNTAX,
5514        "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5515
5516     query = "SELECT * FROM `_Tables`";
5517     r = MsiDatabaseOpenView(hdb, query, &hview);
5518     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5519     r = MsiViewExecute(hview, 0);
5520     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5521
5522     r = MsiViewFetch(hview, &hrec);
5523     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5524
5525     size = MAX_PATH;
5526     r = MsiRecordGetStringA(hrec, 1, buf, &size);
5527     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5528     todo_wine
5529     {
5530         ok(!lstrcmpA(buf, "\rOne"), "Expected \"\\rOne\", got \"%s\"\n", buf);
5531     }
5532
5533     MsiCloseHandle(hrec);
5534
5535     r = MsiViewFetch(hview, &hrec);
5536     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5537
5538     size = MAX_PATH;
5539     r = MsiRecordGetStringA(hrec, 1, buf, &size);
5540     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5541     todo_wine
5542     {
5543         ok(!lstrcmpA(buf, "Tw\ro"), "Expected \"Tw\\ro\", got \"%s\"\n", buf);
5544     }
5545
5546     MsiCloseHandle(hrec);
5547
5548     r = MsiViewFetch(hview, &hrec);
5549     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5550
5551     size = MAX_PATH;
5552     r = MsiRecordGetStringA(hrec, 1, buf, &size);
5553     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5554     todo_wine
5555     {
5556         ok(!lstrcmpA(buf, "Three\r"),
5557            "Expected \"Three\r\", got \"%s\"\n", buf);
5558     }
5559
5560     MsiCloseHandle(hrec);
5561
5562     r = MsiViewFetch(hview, &hrec);
5563     todo_wine
5564     {
5565         ok(r == ERROR_NO_MORE_ITEMS,
5566            "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5567     }
5568
5569     MsiViewClose(hview);
5570     MsiCloseHandle(hview);
5571
5572     MsiCloseHandle(hdb);
5573     DeleteFileA(msifile);
5574 }
5575
5576 static void test_noquotes(void)
5577 {
5578     MSIHANDLE hdb, hview, hrec;
5579     const char *query;
5580     char buf[MAX_PATH];
5581     UINT r;
5582     DWORD size;
5583
5584     DeleteFile(msifile);
5585
5586     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
5587     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5588
5589     query = "CREATE TABLE Table ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
5590     r = run_query(hdb, 0, query);
5591     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5592
5593     query = "CREATE TABLE `Table` ( A CHAR(72) NOT NULL PRIMARY KEY `A` )";
5594     r = run_query(hdb, 0, query);
5595     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5596
5597     query = "CREATE TABLE `Table2` ( `A` CHAR(72) NOT NULL PRIMARY KEY A )";
5598     r = run_query(hdb, 0, query);
5599     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5600
5601     query = "CREATE TABLE `Table3` ( A CHAR(72) NOT NULL PRIMARY KEY A )";
5602     r = run_query(hdb, 0, query);
5603     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5604
5605     query = "SELECT * FROM `_Tables`";
5606     r = MsiDatabaseOpenView(hdb, query, &hview);
5607     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5608     r = MsiViewExecute(hview, 0);
5609     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5610
5611     r = MsiViewFetch(hview, &hrec);
5612     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5613
5614     size = MAX_PATH;
5615     r = MsiRecordGetStringA(hrec, 1, buf, &size);
5616     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5617     ok(!lstrcmpA(buf, "Table"), "Expected \"Table\", got \"%s\"\n", buf);
5618
5619     MsiCloseHandle(hrec);
5620
5621     r = MsiViewFetch(hview, &hrec);
5622     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5623
5624     size = MAX_PATH;
5625     r = MsiRecordGetStringA(hrec, 1, buf, &size);
5626     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5627     ok(!lstrcmpA(buf, "Table2"), "Expected \"Table2\", got \"%s\"\n", buf);
5628
5629     MsiCloseHandle(hrec);
5630
5631     r = MsiViewFetch(hview, &hrec);
5632     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5633
5634     size = MAX_PATH;
5635     r = MsiRecordGetStringA(hrec, 1, buf, &size);
5636     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5637     ok(!lstrcmpA(buf, "Table3"), "Expected \"Table3\", got \"%s\"\n", buf);
5638
5639     MsiCloseHandle(hrec);
5640
5641     r = MsiViewFetch(hview, &hrec);
5642     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5643
5644     MsiViewClose(hview);
5645     MsiCloseHandle(hview);
5646
5647     query = "SELECT * FROM `_Columns`";
5648     r = MsiDatabaseOpenView(hdb, query, &hview);
5649     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5650     r = MsiViewExecute(hview, 0);
5651     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5652
5653     r = MsiViewFetch(hview, &hrec);
5654     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5655
5656     size = MAX_PATH;
5657     r = MsiRecordGetStringA(hrec, 1, buf, &size);
5658     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5659     ok(!lstrcmpA(buf, "Table"), "Expected \"Table\", got \"%s\"\n", buf);
5660
5661     r = MsiRecordGetInteger(hrec, 2);
5662     ok(r == 1, "Expected 1, got %d\n", r);
5663
5664     size = MAX_PATH;
5665     r = MsiRecordGetStringA(hrec, 3, buf, &size);
5666     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5667     ok(!lstrcmpA(buf, "A"), "Expected \"A\", got \"%s\"\n", buf);
5668
5669     MsiCloseHandle(hrec);
5670
5671     r = MsiViewFetch(hview, &hrec);
5672     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5673
5674     size = MAX_PATH;
5675     r = MsiRecordGetStringA(hrec, 1, buf, &size);
5676     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5677     ok(!lstrcmpA(buf, "Table2"), "Expected \"Table2\", got \"%s\"\n", buf);
5678
5679     r = MsiRecordGetInteger(hrec, 2);
5680     ok(r == 1, "Expected 1, got %d\n", r);
5681
5682     size = MAX_PATH;
5683     r = MsiRecordGetStringA(hrec, 3, buf, &size);
5684     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5685     ok(!lstrcmpA(buf, "A"), "Expected \"A\", got \"%s\"\n", buf);
5686
5687     MsiCloseHandle(hrec);
5688
5689     r = MsiViewFetch(hview, &hrec);
5690     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5691
5692     size = MAX_PATH;
5693     r = MsiRecordGetStringA(hrec, 1, buf, &size);
5694     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5695     ok(!lstrcmpA(buf, "Table3"), "Expected \"Table3\", got \"%s\"\n", buf);
5696
5697     r = MsiRecordGetInteger(hrec, 2);
5698     ok(r == 1, "Expected 1, got %d\n", r);
5699
5700     size = MAX_PATH;
5701     r = MsiRecordGetStringA(hrec, 3, buf, &size);
5702     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5703     ok(!lstrcmpA(buf, "A"), "Expected \"A\", got \"%s\"\n", buf);
5704
5705     MsiCloseHandle(hrec);
5706
5707     r = MsiViewFetch(hview, &hrec);
5708     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5709
5710     MsiViewClose(hview);
5711     MsiCloseHandle(hview);
5712
5713     query = "INSERT INTO Table ( `A` ) VALUES ( 'hi' )";
5714     r = run_query(hdb, 0, query);
5715     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5716
5717     query = "INSERT INTO `Table` ( A ) VALUES ( 'hi' )";
5718     r = run_query(hdb, 0, query);
5719     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5720
5721     query = "INSERT INTO `Table` ( `A` ) VALUES ( hi )";
5722     r = run_query(hdb, 0, query);
5723     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5724
5725     query = "SELECT * FROM Table WHERE `A` = 'hi'";
5726     r = run_query(hdb, 0, query);
5727     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5728
5729     query = "SELECT * FROM `Table` WHERE `A` = hi";
5730     r = run_query(hdb, 0, query);
5731     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5732
5733     query = "SELECT * FROM Table";
5734     r = run_query(hdb, 0, query);
5735     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5736
5737     query = "SELECT * FROM Table2";
5738     r = MsiDatabaseOpenView(hdb, query, &hview);
5739     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5740     r = MsiViewExecute(hview, 0);
5741     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5742
5743     r = MsiViewFetch(hview, &hrec);
5744     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5745
5746     MsiViewClose(hview);
5747     MsiCloseHandle(hview);
5748
5749     query = "SELECT * FROM `Table` WHERE A = 'hi'";
5750     r = MsiDatabaseOpenView(hdb, query, &hview);
5751     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5752     r = MsiViewExecute(hview, 0);
5753     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5754
5755     r = MsiViewFetch(hview, &hrec);
5756     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5757
5758     size = MAX_PATH;
5759     r = MsiRecordGetStringA(hrec, 1, buf, &size);
5760     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5761     ok(!lstrcmpA(buf, "hi"), "Expected \"hi\", got \"%s\"\n", buf);
5762
5763     MsiCloseHandle(hrec);
5764
5765     r = MsiViewFetch(hview, &hrec);
5766     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
5767
5768     MsiViewClose(hview);
5769     MsiCloseHandle(hview);
5770
5771
5772     MsiCloseHandle(hdb);
5773     DeleteFileA(msifile);
5774 }
5775
5776 static void read_file_data(LPCSTR filename, LPSTR buffer)
5777 {
5778     OFSTRUCT ofs;
5779     HFILE file;
5780     DWORD read;
5781
5782     file = OpenFile(filename, &ofs, OF_READ);
5783     ZeroMemory(buffer, MAX_PATH);
5784     ReadFile((HANDLE)file, buffer, MAX_PATH, &read, NULL);
5785     CloseHandle((HANDLE)file);
5786 }
5787
5788 static void test_forcecodepage(void)
5789 {
5790     MSIHANDLE hdb;
5791     const char *query;
5792     char buffer[MAX_PATH];
5793     UINT r;
5794
5795     DeleteFile(msifile);
5796
5797     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
5798     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5799
5800     query = "SELECT * FROM `_ForceCodepage`";
5801     r = run_query(hdb, 0, query);
5802     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5803
5804     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )";
5805     r = run_query(hdb, 0, query);
5806     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5807
5808     query = "SELECT * FROM `_ForceCodepage`";
5809     r = run_query(hdb, 0, query);
5810     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5811
5812     r = MsiDatabaseCommit(hdb);
5813     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5814
5815     query = "SELECT * FROM `_ForceCodepage`";
5816     r = run_query(hdb, 0, query);
5817     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5818
5819     MsiCloseHandle(hdb);
5820
5821     r = MsiOpenDatabase(msifile, MSIDBOPEN_DIRECT, &hdb);
5822     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5823
5824     query = "SELECT * FROM `_ForceCodepage`";
5825     r = run_query(hdb, 0, query);
5826     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
5827
5828     r = MsiDatabaseExport(hdb, "_ForceCodepage", CURR_DIR, "forcecodepage.idt");
5829     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5830
5831     read_file_data("forcecodepage.idt", buffer);
5832     ok(!lstrcmpA(buffer, "\r\n\r\n0\t_ForceCodepage\r\n"),
5833        "Expected \"\r\n\r\n0\t_ForceCodepage\r\n\", got \"%s\"", buffer);
5834
5835     MsiCloseHandle(hdb);
5836     DeleteFileA(msifile);
5837     DeleteFileA("forcecodepage.idt");
5838 }
5839
5840 static void test_viewmodify_refresh(void)
5841 {
5842     MSIHANDLE hdb, hview, hrec;
5843     const char *query;
5844     char buffer[MAX_PATH];
5845     UINT r;
5846     DWORD size;
5847
5848     DeleteFile(msifile);
5849
5850     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
5851     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5852
5853     query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL, `B` INT PRIMARY KEY `A` )";
5854     r = run_query(hdb, 0, query);
5855     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5856
5857     query = "INSERT INTO `Table` ( `A`, `B` ) VALUES ( 'hi', 1 )";
5858     r = run_query(hdb, 0, query);
5859     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5860
5861     query = "SELECT * FROM `Table`";
5862     r = MsiDatabaseOpenView(hdb, query, &hview);
5863     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5864     r = MsiViewExecute(hview, 0);
5865     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5866
5867     r = MsiViewFetch(hview, &hrec);
5868     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5869
5870     query = "UPDATE `Table` SET `B` = 2 WHERE `A` = 'hi'";
5871     r = run_query(hdb, 0, query);
5872     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5873
5874     r = MsiViewModify(hview, MSIMODIFY_REFRESH, hrec);
5875     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5876
5877     size = MAX_PATH;
5878     r = MsiRecordGetStringA(hrec, 1, buffer, &size);
5879     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5880     ok(!lstrcmpA(buffer, "hi"), "Expected \"hi\", got \"%s\"\n", buffer);
5881     ok(size == 2, "Expected 2, got %d\n", size);
5882
5883     r = MsiRecordGetInteger(hrec, 2);
5884     ok(r == 2, "Expected 2, got %d\n", r);
5885
5886     MsiCloseHandle(hrec);
5887     MsiViewClose(hview);
5888     MsiCloseHandle(hview);
5889
5890     query = "INSERT INTO `Table` ( `A`, `B` ) VALUES ( 'hello', 3 )";
5891     r = run_query(hdb, 0, query);
5892     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5893
5894     query = "SELECT * FROM `Table` WHERE `B` = 3";
5895     r = MsiDatabaseOpenView(hdb, query, &hview);
5896     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5897     r = MsiViewExecute(hview, 0);
5898     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5899
5900     r = MsiViewFetch(hview, &hrec);
5901     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5902
5903     query = "UPDATE `Table` SET `B` = 2 WHERE `A` = 'hello'";
5904     r = run_query(hdb, 0, query);
5905     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5906
5907     query = "INSERT INTO `Table` ( `A`, `B` ) VALUES ( 'hithere', 3 )";
5908     r = run_query(hdb, 0, query);
5909     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5910
5911     r = MsiViewModify(hview, MSIMODIFY_REFRESH, hrec);
5912     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5913
5914     size = MAX_PATH;
5915     r = MsiRecordGetStringA(hrec, 1, buffer, &size);
5916     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5917     ok(!lstrcmpA(buffer, "hello"), "Expected \"hello\", got \"%s\"\n", buffer);
5918     ok(size == 5, "Expected 5, got %d\n", size);
5919
5920     r = MsiRecordGetInteger(hrec, 2);
5921     ok(r == 2, "Expected 2, got %d\n", r);
5922
5923     MsiCloseHandle(hrec);
5924     MsiViewClose(hview);
5925     MsiCloseHandle(hview);
5926     MsiCloseHandle(hdb);
5927     DeleteFileA(msifile);
5928 }
5929
5930 static void test_where_viewmodify(void)
5931 {
5932     MSIHANDLE hdb, hview, hrec;
5933     const char *query;
5934     UINT r;
5935
5936     DeleteFile(msifile);
5937
5938     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
5939     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5940
5941     query = "CREATE TABLE `Table` ( `A` INT, `B` INT PRIMARY KEY `A` )";
5942     r = run_query(hdb, 0, query);
5943     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5944
5945     query = "INSERT INTO `Table` ( `A`, `B` ) VALUES ( 1, 2 )";
5946     r = run_query(hdb, 0, query);
5947     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5948
5949     query = "INSERT INTO `Table` ( `A`, `B` ) VALUES ( 3, 4 )";
5950     r = run_query(hdb, 0, query);
5951     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5952
5953     query = "INSERT INTO `Table` ( `A`, `B` ) VALUES ( 5, 6 )";
5954     r = run_query(hdb, 0, query);
5955     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5956
5957     /* `B` = 3 doesn't match, but the view shouldn't be executed */
5958     query = "SELECT * FROM `Table` WHERE `B` = 3";
5959     r = MsiDatabaseOpenView(hdb, query, &hview);
5960     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5961
5962     hrec = MsiCreateRecord(2);
5963     MsiRecordSetInteger(hrec, 1, 7);
5964     MsiRecordSetInteger(hrec, 2, 8);
5965
5966     r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec);
5967     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5968
5969     MsiCloseHandle(hrec);
5970     MsiViewClose(hview);
5971     MsiCloseHandle(hview);
5972
5973     query = "SELECT * FROM `Table` WHERE `A` = 7";
5974     r = MsiDatabaseOpenView(hdb, query, &hview);
5975     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5976     r = MsiViewExecute(hview, 0);
5977     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5978
5979     r = MsiViewFetch(hview, &hrec);
5980     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5981
5982     r = MsiRecordGetInteger(hrec, 1);
5983     ok(r == 7, "Expected 7, got %d\n", r);
5984
5985     r = MsiRecordGetInteger(hrec, 2);
5986     ok(r == 8, "Expected 8, got %d\n", r);
5987
5988     MsiRecordSetInteger(hrec, 2, 9);
5989
5990     r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
5991     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
5992
5993     MsiCloseHandle(hrec);
5994     MsiViewClose(hview);
5995     MsiCloseHandle(hview);
5996
5997     query = "SELECT * FROM `Table` WHERE `A` = 7";
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     r = MsiRecordGetInteger(hrec, 1);
6007     ok(r == 7, "Expected 7, got %d\n", r);
6008
6009     r = MsiRecordGetInteger(hrec, 2);
6010     ok(r == 9, "Expected 9, got %d\n", r);
6011
6012     query = "UPDATE `Table` SET `B` = 10 WHERE `A` = 7";
6013     r = run_query(hdb, 0, query);
6014     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6015
6016     r = MsiViewModify(hview, MSIMODIFY_REFRESH, hrec);
6017     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6018
6019     r = MsiRecordGetInteger(hrec, 1);
6020     ok(r == 7, "Expected 7, got %d\n", r);
6021
6022     r = MsiRecordGetInteger(hrec, 2);
6023     ok(r == 10, "Expected 10, got %d\n", r);
6024
6025     MsiCloseHandle(hrec);
6026     MsiViewClose(hview);
6027     MsiCloseHandle(hview);
6028     MsiCloseHandle(hdb);
6029 }
6030
6031 static BOOL create_storage(LPCSTR name)
6032 {
6033     WCHAR nameW[MAX_PATH];
6034     IStorage *stg;
6035     IStream *stm;
6036     HRESULT hr;
6037     DWORD count;
6038     BOOL res = FALSE;
6039
6040     MultiByteToWideChar(CP_ACP, 0, name, -1, nameW, MAX_PATH);
6041     hr = StgCreateDocfile(nameW, STGM_CREATE | STGM_READWRITE |
6042                           STGM_DIRECT | STGM_SHARE_EXCLUSIVE, 0, &stg);
6043     if (FAILED(hr))
6044         return FALSE;
6045
6046     hr = IStorage_CreateStream(stg, nameW, STGM_WRITE | STGM_SHARE_EXCLUSIVE,
6047                                0, 0, &stm);
6048     if (FAILED(hr))
6049         goto done;
6050
6051     hr = IStream_Write(stm, "stgdata", 8, &count);
6052     if (SUCCEEDED(hr))
6053         res = TRUE;
6054
6055 done:
6056     IStream_Release(stm);
6057     IStorage_Release(stg);
6058
6059     return res;
6060 }
6061
6062 static void test_storages_table(void)
6063 {
6064     MSIHANDLE hdb, hview, hrec;
6065     IStorage *stg, *inner;
6066     IStream *stm;
6067     char file[MAX_PATH];
6068     char buf[MAX_PATH];
6069     WCHAR name[MAX_PATH];
6070     LPCSTR query;
6071     HRESULT hr;
6072     DWORD size;
6073     UINT r;
6074
6075     hdb = create_db();
6076     ok(hdb, "failed to create db\n");
6077
6078     r = MsiDatabaseCommit(hdb);
6079     ok(r == ERROR_SUCCESS , "Failed to commit database\n");
6080
6081     MsiCloseHandle(hdb);
6082
6083     r = MsiOpenDatabase(msifile, MSIDBOPEN_TRANSACT, &hdb);
6084     ok(r == ERROR_SUCCESS , "Failed to open database\n");
6085
6086     /* check the column types */
6087     hrec = get_column_info(hdb, "SELECT * FROM `_Storages`", MSICOLINFO_TYPES);
6088     ok(hrec, "failed to get column info hrecord\n");
6089     ok(check_record(hrec, 1, "s62"), "wrong hrecord type\n");
6090     ok(check_record(hrec, 2, "V0"), "wrong hrecord type\n");
6091
6092     MsiCloseHandle(hrec);
6093
6094     /* now try the names */
6095     hrec = get_column_info(hdb, "SELECT * FROM `_Storages`", MSICOLINFO_NAMES);
6096     ok(hrec, "failed to get column info hrecord\n");
6097     ok(check_record(hrec, 1, "Name"), "wrong hrecord type\n");
6098     ok(check_record(hrec, 2, "Data"), "wrong hrecord type\n");
6099
6100     MsiCloseHandle(hrec);
6101
6102     create_storage("storage.bin");
6103
6104     hrec = MsiCreateRecord(2);
6105     MsiRecordSetString(hrec, 1, "stgname");
6106
6107     r = MsiRecordSetStream(hrec, 2, "storage.bin");
6108     ok(r == ERROR_SUCCESS, "Failed to add stream data to the hrecord: %d\n", r);
6109
6110     DeleteFileA("storage.bin");
6111
6112     query = "INSERT INTO `_Storages` (`Name`, `Data`) VALUES (?, ?)";
6113     r = MsiDatabaseOpenView(hdb, query, &hview);
6114     ok(r == ERROR_SUCCESS, "Failed to open database hview: %d\n", r);
6115
6116     r = MsiViewExecute(hview, hrec);
6117     ok(r == ERROR_SUCCESS, "Failed to execute hview: %d\n", r);
6118
6119     MsiCloseHandle(hrec);
6120     MsiViewClose(hview);
6121     MsiCloseHandle(hview);
6122
6123     query = "SELECT `Name`, `Data` FROM `_Storages`";
6124     r = MsiDatabaseOpenView(hdb, query, &hview);
6125     ok(r == ERROR_SUCCESS, "Failed to open database hview: %d\n", r);
6126
6127     r = MsiViewExecute(hview, 0);
6128     ok(r == ERROR_SUCCESS, "Failed to execute hview: %d\n", r);
6129
6130     r = MsiViewFetch(hview, &hrec);
6131     ok(r == ERROR_SUCCESS, "Failed to fetch hrecord: %d\n", r);
6132
6133     size = MAX_PATH;
6134     r = MsiRecordGetString(hrec, 1, file, &size);
6135     ok(r == ERROR_SUCCESS, "Failed to get string: %d\n", r);
6136     ok(!lstrcmp(file, "stgname"), "Expected \"stgname\", got \"%s\"\n", file);
6137
6138     size = MAX_PATH;
6139     lstrcpyA(buf, "apple");
6140     r = MsiRecordReadStream(hrec, 2, buf, &size);
6141     ok(!lstrcmp(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf);
6142     todo_wine
6143     {
6144         ok(r == ERROR_INVALID_DATA, "Expected ERROR_INVALID_DATA, got %d\n", r);
6145         ok(size == 0, "Expected 0, got %d\n", size);
6146     }
6147
6148     MsiCloseHandle(hrec);
6149
6150     r = MsiViewFetch(hview, &hrec);
6151     ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
6152
6153     MsiViewClose(hview);
6154     MsiCloseHandle(hview);
6155
6156     MsiDatabaseCommit(hdb);
6157     MsiCloseHandle(hdb);
6158
6159     MultiByteToWideChar(CP_ACP, 0, msifile, -1, name, MAX_PATH);
6160     hr = StgOpenStorage(name, NULL, STGM_DIRECT | STGM_READ |
6161                         STGM_SHARE_DENY_WRITE, NULL, 0, &stg);
6162     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
6163     ok(stg != NULL, "Expected non-NULL storage\n");
6164
6165     MultiByteToWideChar(CP_ACP, 0, "stgname", -1, name, MAX_PATH);
6166     hr = IStorage_OpenStorage(stg, name, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE,
6167                               NULL, 0, &inner);
6168     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
6169     ok(inner != NULL, "Expected non-NULL storage\n");
6170
6171     MultiByteToWideChar(CP_ACP, 0, "storage.bin", -1, name, MAX_PATH);
6172     hr = IStorage_OpenStream(inner, name, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm);
6173     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
6174     ok(stm != NULL, "Expected non-NULL stream\n");
6175
6176     hr = IStream_Read(stm, buf, MAX_PATH, &size);
6177     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
6178     ok(size == 8, "Expected 8, got %d\n", size);
6179     ok(!lstrcmpA(buf, "stgdata"), "Expected \"stgdata\", got \"%s\"\n", buf);
6180
6181     IStream_Release(stm);
6182     IStorage_Release(inner);
6183
6184     IStorage_Release(stg);
6185     DeleteFileA(msifile);
6186 }
6187
6188 static void test_dbtopackage(void)
6189 {
6190     MSIHANDLE hdb, hpkg;
6191     CHAR package[10];
6192     CHAR buf[MAX_PATH];
6193     DWORD size;
6194     UINT r;
6195
6196     /* create an empty database, transact mode */
6197     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
6198     ok(r == ERROR_SUCCESS, "Failed to create database\n");
6199
6200     set_summary_info(hdb);
6201
6202     r = create_directory_table(hdb);
6203     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6204
6205     r = create_custom_action_table(hdb);
6206     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6207
6208     r = add_custom_action_entry(hdb, "'SetProp', 51, 'MYPROP', 'grape'");
6209     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6210
6211     sprintf(package, "#%li", hdb);
6212     r = MsiOpenPackage(package, &hpkg);
6213     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6214
6215     /* property is not set yet */
6216     size = MAX_PATH;
6217     lstrcpyA(buf, "kiwi");
6218     r = MsiGetProperty(hpkg, "MYPROP", buf, &size);
6219     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6220     ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf);
6221     ok(size == 0, "Expected 0, got %d\n", size);
6222
6223     /* run the custom action to set the property */
6224     r = MsiDoAction(hpkg, "SetProp");
6225     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6226
6227     /* property is now set */
6228     size = MAX_PATH;
6229     lstrcpyA(buf, "kiwi");
6230     r = MsiGetProperty(hpkg, "MYPROP", buf, &size);
6231     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6232     ok(!lstrcmpA(buf, "grape"), "Expected \"grape\", got \"%s\"\n", buf);
6233     ok(size == 5, "Expected 5, got %d\n", size);
6234
6235     MsiCloseHandle(hpkg);
6236
6237     /* reset the package */
6238     r = MsiOpenPackage(package, &hpkg);
6239     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6240
6241     /* property is not set anymore */
6242     size = MAX_PATH;
6243     lstrcpyA(buf, "kiwi");
6244     r = MsiGetProperty(hpkg, "MYPROP", buf, &size);
6245     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6246     todo_wine
6247     {
6248         ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf);
6249         ok(size == 0, "Expected 0, got %d\n", size);
6250     }
6251
6252     MsiCloseHandle(hdb);
6253     MsiCloseHandle(hpkg);
6254
6255     /* create an empty database, direct mode */
6256     r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATEDIRECT, &hdb);
6257     ok(r == ERROR_SUCCESS, "Failed to create database\n");
6258
6259     set_summary_info(hdb);
6260
6261     r = create_directory_table(hdb);
6262     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6263
6264     r = create_custom_action_table(hdb);
6265     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6266
6267     r = add_custom_action_entry(hdb, "'SetProp', 51, 'MYPROP', 'grape'");
6268     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6269
6270     sprintf(package, "#%li", hdb);
6271     r = MsiOpenPackage(package, &hpkg);
6272     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6273
6274     /* property is not set yet */
6275     size = MAX_PATH;
6276     lstrcpyA(buf, "kiwi");
6277     r = MsiGetProperty(hpkg, "MYPROP", buf, &size);
6278     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6279     ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf);
6280     ok(size == 0, "Expected 0, got %d\n", size);
6281
6282     /* run the custom action to set the property */
6283     r = MsiDoAction(hpkg, "SetProp");
6284     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6285
6286     /* property is now set */
6287     size = MAX_PATH;
6288     lstrcpyA(buf, "kiwi");
6289     r = MsiGetProperty(hpkg, "MYPROP", buf, &size);
6290     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6291     ok(!lstrcmpA(buf, "grape"), "Expected \"grape\", got \"%s\"\n", buf);
6292     ok(size == 5, "Expected 5, got %d\n", size);
6293
6294     MsiCloseHandle(hpkg);
6295
6296     /* reset the package */
6297     r = MsiOpenPackage(package, &hpkg);
6298     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6299
6300     /* property is not set anymore */
6301     size = MAX_PATH;
6302     lstrcpyA(buf, "kiwi");
6303     r = MsiGetProperty(hpkg, "MYPROP", buf, &size);
6304     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
6305     todo_wine
6306     {
6307         ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf);
6308         ok(size == 0, "Expected 0, got %d\n", size);
6309     }
6310
6311     MsiCloseHandle(hdb);
6312     MsiCloseHandle(hpkg);
6313     DeleteFileA(msifile);
6314 }
6315
6316 START_TEST(db)
6317 {
6318     test_msidatabase();
6319     test_msiinsert();
6320     test_msidecomposedesc();
6321     test_msibadqueries();
6322     test_viewmodify();
6323     test_viewgetcolumninfo();
6324     test_getcolinfo();
6325     test_msiexport();
6326     test_longstrings();
6327     test_streamtable();
6328     test_where();
6329     test_msiimport();
6330     test_markers();
6331     test_handle_limit();
6332     test_try_transform();
6333     test_join();
6334     test_temporary_table();
6335     test_alter();
6336     test_integers();
6337     test_update();
6338     test_special_tables();
6339     test_select_markers();
6340     test_viewmodify_update();
6341     test_stringtable();
6342     test_viewmodify_delete();
6343     test_defaultdatabase();
6344     test_order();
6345     test_viewmodify_delete_temporary();
6346     test_deleterow();
6347     test_quotes();
6348     test_carriagereturn();
6349     test_noquotes();
6350     test_forcecodepage();
6351     test_viewmodify_refresh();
6352     test_where_viewmodify();
6353     test_storages_table();
6354     test_dbtopackage();
6355 }