ReactOS  0.4.14-dev-52-g6116262
db.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2005 Mike McCormack for CodeWeavers
3  *
4  * A test program for MSI database files.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 #define COBJMACROS
22 
23 #include <stdio.h>
24 
25 #include <windows.h>
26 #include <objidl.h>
27 #include <msi.h>
28 #include <msidefs.h>
29 #include <msiquery.h>
30 
31 #include "wine/test.h"
32 
33 static const char *msifile = "winetest-db.msi";
34 static const char *msifile2 = "winetst2-db.msi";
35 static const char *mstfile = "winetst-db.mst";
36 static const WCHAR msifileW[] = {'w','i','n','e','t','e','s','t','-','d','b','.','m','s','i',0};
37 static const WCHAR msifile2W[] = {'w','i','n','e','t','s','t','2','-','d','b','.','m','s','i',0};
38 
39 static void test_msidatabase(void)
40 {
41  MSIHANDLE hdb = 0, hdb2 = 0;
42  UINT res;
43 
45 
47  ok( res == ERROR_OPEN_FAILED, "expected failure\n");
48 
49  res = MsiOpenDatabaseW( msifileW, (LPWSTR)0xff, &hdb );
50  ok( res == ERROR_INVALID_PARAMETER, "expected failure\n");
51 
52  res = MsiCloseHandle( hdb );
53  ok( res == ERROR_SUCCESS , "Failed to close database\n" );
54 
55  /* create an empty database */
57  ok( res == ERROR_SUCCESS , "Failed to create database\n" );
58 
59  res = MsiDatabaseCommit( hdb );
60  ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
61 
62  ok( GetFileAttributesA( msifile ) != INVALID_FILE_ATTRIBUTES, "database should exist\n");
63 
64  res = MsiCloseHandle( hdb );
65  ok( res == ERROR_SUCCESS , "Failed to close database\n" );
67  ok( res == ERROR_SUCCESS , "Failed to open database\n" );
68 
69  ok( GetFileAttributesA( msifile2 ) != INVALID_FILE_ATTRIBUTES, "database should exist\n");
70 
71  res = MsiDatabaseCommit( hdb2 );
72  ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
73 
74  res = MsiCloseHandle( hdb2 );
75  ok( res == ERROR_SUCCESS , "Failed to close database\n" );
76 
78  ok( res == ERROR_SUCCESS , "Failed to open database\n" );
79 
80  res = MsiCloseHandle( hdb2 );
81  ok( res == ERROR_SUCCESS , "Failed to close database\n" );
82 
83  ok( GetFileAttributesA( msifile2 ) == INVALID_FILE_ATTRIBUTES, "uncommitted database should not exist\n");
84 
86  ok( res == ERROR_SUCCESS , "Failed to close database\n" );
87 
88  res = MsiDatabaseCommit( hdb2 );
89  ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
90 
91  res = MsiCloseHandle( hdb2 );
92  ok( res == ERROR_SUCCESS , "Failed to close database\n" );
93 
94  ok( GetFileAttributesA( msifile2 ) != INVALID_FILE_ATTRIBUTES, "committed database should exist\n");
95 
97  ok( res == ERROR_SUCCESS , "Failed to open database\n" );
98 
99  res = MsiDatabaseCommit( hdb );
100  ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
101 
102  res = MsiCloseHandle( hdb );
103  ok( res == ERROR_SUCCESS , "Failed to close database\n" );
104 
106  ok( res == ERROR_SUCCESS , "Failed to open database\n" );
107 
108  res = MsiCloseHandle( hdb );
109  ok( res == ERROR_SUCCESS , "Failed to close database\n" );
110 
112  ok( res == ERROR_SUCCESS , "Failed to open database\n" );
113 
114  res = MsiCloseHandle( hdb );
115  ok( res == ERROR_SUCCESS , "Failed to close database\n" );
116  ok( GetFileAttributesA( msifile ) != INVALID_FILE_ATTRIBUTES, "database should exist\n");
117 
118  /* MSIDBOPEN_CREATE deletes the database if MsiCommitDatabase isn't called */
120  ok( res == ERROR_SUCCESS , "Failed to open database\n" );
121 
122  ok( GetFileAttributesA( msifile ) != INVALID_FILE_ATTRIBUTES, "database should exist\n");
123 
124  res = MsiCloseHandle( hdb );
125  ok( res == ERROR_SUCCESS , "Failed to close database\n" );
126 
127  ok( GetFileAttributesA( msifile ) == INVALID_FILE_ATTRIBUTES, "database should exist\n");
128 
130  ok( res == ERROR_SUCCESS , "Failed to open database\n" );
131 
132  res = MsiDatabaseCommit( hdb );
133  ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
134 
135  ok( GetFileAttributesA( msifile ) != INVALID_FILE_ATTRIBUTES, "database should exist\n");
136 
137  res = MsiCloseHandle( hdb );
138  ok( res == ERROR_SUCCESS , "Failed to close database\n" );
139 
140  res = DeleteFileA( msifile2 );
141  ok( res == TRUE, "Failed to delete database\n" );
142 
143  res = DeleteFileA( msifile );
144  ok( res == TRUE, "Failed to delete database\n" );
145 }
146 
147 static UINT do_query(MSIHANDLE hdb, const char *query, MSIHANDLE *phrec)
148 {
149  MSIHANDLE hview = 0;
150  UINT r, ret;
151 
152  if (phrec)
153  *phrec = 0;
154 
155  /* open a select query */
156  r = MsiDatabaseOpenViewA(hdb, query, &hview);
157  if (r != ERROR_SUCCESS)
158  return r;
159  r = MsiViewExecute(hview, 0);
160  if (r != ERROR_SUCCESS)
161  return r;
162  ret = MsiViewFetch(hview, phrec);
163  r = MsiViewClose(hview);
164  if (r != ERROR_SUCCESS)
165  return r;
166  r = MsiCloseHandle(hview);
167  if (r != ERROR_SUCCESS)
168  return r;
169  return ret;
170 }
171 
172 static UINT run_query( MSIHANDLE hdb, MSIHANDLE hrec, const char *query )
173 {
174  MSIHANDLE hview = 0;
175  UINT r;
176 
177  r = MsiDatabaseOpenViewA(hdb, query, &hview);
178  if( r != ERROR_SUCCESS )
179  return r;
180 
181  r = MsiViewExecute(hview, hrec);
182  if( r == ERROR_SUCCESS )
183  r = MsiViewClose(hview);
184  MsiCloseHandle(hview);
185  return r;
186 }
187 
188 static UINT run_queryW( MSIHANDLE hdb, MSIHANDLE hrec, const WCHAR *query )
189 {
190  MSIHANDLE hview = 0;
191  UINT r;
192 
193  r = MsiDatabaseOpenViewW(hdb, query, &hview);
194  if( r != ERROR_SUCCESS )
195  return r;
196 
197  r = MsiViewExecute(hview, hrec);
198  if( r == ERROR_SUCCESS )
199  r = MsiViewClose(hview);
200  MsiCloseHandle(hview);
201  return r;
202 }
203 
205 {
206  UINT r = run_query( hdb, 0,
207  "CREATE TABLE `Component` ( "
208  "`Component` CHAR(72) NOT NULL, "
209  "`ComponentId` CHAR(38), "
210  "`Directory_` CHAR(72) NOT NULL, "
211  "`Attributes` SHORT NOT NULL, "
212  "`Condition` CHAR(255), "
213  "`KeyPath` CHAR(72) "
214  "PRIMARY KEY `Component`)" );
215  ok(r == ERROR_SUCCESS, "Failed to create Component table: %u\n", r);
216  return r;
217 }
218 
220 {
221  UINT r = run_query( hdb, 0,
222  "CREATE TABLE `CustomAction` ( "
223  "`Action` CHAR(72) NOT NULL, "
224  "`Type` SHORT NOT NULL, "
225  "`Source` CHAR(72), "
226  "`Target` CHAR(255) "
227  "PRIMARY KEY `Action`)" );
228  ok(r == ERROR_SUCCESS, "Failed to create CustomAction table: %u\n", r);
229  return r;
230 }
231 
233 {
234  UINT r = run_query( hdb, 0,
235  "CREATE TABLE `Directory` ( "
236  "`Directory` CHAR(255) NOT NULL, "
237  "`Directory_Parent` CHAR(255), "
238  "`DefaultDir` CHAR(255) NOT NULL "
239  "PRIMARY KEY `Directory`)" );
240  ok(r == ERROR_SUCCESS, "Failed to create Directory table: %u\n", r);
241  return r;
242 }
243 
245 {
246  UINT r = run_query( hdb, 0,
247  "CREATE TABLE `FeatureComponents` ( "
248  "`Feature_` CHAR(38) NOT NULL, "
249  "`Component_` CHAR(72) NOT NULL "
250  "PRIMARY KEY `Feature_`, `Component_` )" );
251  ok(r == ERROR_SUCCESS, "Failed to create FeatureComponents table: %u\n", r);
252  return r;
253 }
254 
256 {
257  UINT r = run_query( hdb, 0,
258  "CREATE TABLE `StdDlls` ( "
259  "`File` CHAR(255) NOT NULL, "
260  "`Binary_` CHAR(72) NOT NULL "
261  "PRIMARY KEY `File` )" );
262  ok(r == ERROR_SUCCESS, "Failed to create StdDlls table: %u\n", r);
263  return r;
264 }
265 
267 {
268  UINT r = run_query( hdb, 0,
269  "CREATE TABLE `Binary` ( "
270  "`Name` CHAR(72) NOT NULL, "
271  "`Data` CHAR(72) NOT NULL "
272  "PRIMARY KEY `Name` )" );
273  ok(r == ERROR_SUCCESS, "Failed to create Binary table: %u\n", r);
274  return r;
275 }
276 
277 static inline UINT add_entry(const char *file, int line, const char *type, MSIHANDLE hdb, const char *values, const char *insert)
278 {
279  char *query;
280  UINT sz, r;
281 
282  sz = strlen(values) + strlen(insert) + 1;
283  query = HeapAlloc(GetProcessHeap(), 0, sz);
285  r = run_query(hdb, 0, query);
287  ok_(file, line)(r == ERROR_SUCCESS, "failed to insert into %s table: %u\n", type, r);
288  return r;
289 }
290 
291 #define add_component_entry(hdb, values) add_entry(__FILE__, __LINE__, "Component", hdb, values, \
292  "INSERT INTO `Component` " \
293  "(`Component`, `ComponentId`, `Directory_`, " \
294  "`Attributes`, `Condition`, `KeyPath`) VALUES( %s )")
295 
296 #define add_custom_action_entry(hdb, values) add_entry(__FILE__, __LINE__, "CustomAction", hdb, values, \
297  "INSERT INTO `CustomAction` " \
298  "(`Action`, `Type`, `Source`, `Target`) VALUES( %s )")
299 
300 #define add_feature_components_entry(hdb, values) add_entry(__FILE__, __LINE__, "FeatureComponents", hdb, values, \
301  "INSERT INTO `FeatureComponents` " \
302  "(`Feature_`, `Component_`) VALUES( %s )")
303 
304 #define add_std_dlls_entry(hdb, values) add_entry(__FILE__, __LINE__, "StdDlls", hdb, values, \
305  "INSERT INTO `StdDlls` (`File`, `Binary_`) VALUES( %s )")
306 
307 #define add_binary_entry(hdb, values) add_entry(__FILE__, __LINE__, "Binary", hdb, values, \
308  "INSERT INTO `Binary` (`Name`, `Data`) VALUES( %s )")
309 
310 static void test_msiinsert(void)
311 {
312  MSIHANDLE hdb = 0, hview = 0, hview2 = 0, hrec = 0;
313  UINT r;
314  const char *query;
315  char buf[80];
316  DWORD sz;
317 
319 
320  /* just MsiOpenDatabase should not create a file */
322  ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
323 
324  /* create a table */
325  query = "CREATE TABLE `phone` ( "
326  "`id` INT, `name` CHAR(32), `number` CHAR(32) "
327  "PRIMARY KEY `id`)";
328  r = MsiDatabaseOpenViewA(hdb, query, &hview);
329  ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
330  r = MsiViewExecute(hview, 0);
331  ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
332  r = MsiViewClose(hview);
333  ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
334  r = MsiCloseHandle(hview);
335  ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
336 
337  query = "SELECT * FROM phone WHERE number = '8675309'";
338  r = MsiDatabaseOpenViewA(hdb, query, &hview2);
339  ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
340  r = MsiViewExecute(hview2, 0);
341  ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
342  r = MsiViewFetch(hview2, &hrec);
343  ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch produced items\n");
344 
345  /* insert a value into it */
346  query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
347  "VALUES('1', 'Abe', '8675309')";
348  r = MsiDatabaseOpenViewA(hdb, query, &hview);
349  ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
350  r = MsiViewExecute(hview, 0);
351  ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
352  r = MsiViewClose(hview);
353  ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
354  r = MsiCloseHandle(hview);
355  ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
356 
357  r = MsiViewFetch(hview2, &hrec);
358  ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch produced items\n");
359  r = MsiViewExecute(hview2, 0);
360  ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
361  r = MsiViewFetch(hview2, &hrec);
362  ok(r == ERROR_SUCCESS, "MsiViewFetch failed: %u\n", r);
363 
364  r = MsiCloseHandle(hrec);
365  ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
366  r = MsiViewClose(hview2);
367  ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
368  r = MsiCloseHandle(hview2);
369  ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
370 
371  query = "SELECT * FROM `phone` WHERE `id` = 1";
372  r = do_query(hdb, query, &hrec);
373  ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
374 
375  /* check the record contains what we put in it */
376  r = MsiRecordGetFieldCount(hrec);
377  ok(r == 3, "record count wrong\n");
378 
379  r = MsiRecordIsNull(hrec, 0);
380  ok(r == FALSE, "field 0 not null\n");
381 
382  r = MsiRecordGetInteger(hrec, 1);
383  ok(r == 1, "field 1 contents wrong\n");
384  sz = sizeof buf;
385  r = MsiRecordGetStringA(hrec, 2, buf, &sz);
386  ok(r == ERROR_SUCCESS, "field 2 content fetch failed\n");
387  ok(!strcmp(buf,"Abe"), "field 2 content incorrect\n");
388  sz = sizeof buf;
389  r = MsiRecordGetStringA(hrec, 3, buf, &sz);
390  ok(r == ERROR_SUCCESS, "field 3 content fetch failed\n");
391  ok(!strcmp(buf,"8675309"), "field 3 content incorrect\n");
392 
393  r = MsiCloseHandle(hrec);
394  ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
395 
396  /* open a select query */
397  hrec = 100;
398  query = "SELECT * FROM `phone` WHERE `id` >= 10";
399  r = do_query(hdb, query, &hrec);
400  ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch failed\n");
401  ok(hrec == 0, "hrec should be null\n");
402 
403  r = MsiCloseHandle(hrec);
404  ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
405 
406  query = "SELECT * FROM `phone` WHERE `id` < 0";
407  r = do_query(hdb, query, &hrec);
408  ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch failed\n");
409 
410  query = "SELECT * FROM `phone` WHERE `id` <= 0";
411  r = do_query(hdb, query, &hrec);
412  ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch failed\n");
413 
414  query = "SELECT * FROM `phone` WHERE `id` <> 1";
415  r = do_query(hdb, query, &hrec);
416  ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch failed\n");
417 
418  query = "SELECT * FROM `phone` WHERE `id` > 10";
419  r = do_query(hdb, query, &hrec);
420  ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch failed\n");
421 
422  /* now try a few bad INSERT xqueries */
423  query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
424  "VALUES(?, ?)";
425  r = MsiDatabaseOpenViewA(hdb, query, &hview);
426  ok(r == ERROR_BAD_QUERY_SYNTAX, "MsiDatabaseOpenView failed\n");
427 
428  /* construct a record to insert */
429  hrec = MsiCreateRecord(4);
430  r = MsiRecordSetInteger(hrec, 1, 2);
431  ok(r == ERROR_SUCCESS, "MsiRecordSetInteger failed\n");
432  r = MsiRecordSetStringA(hrec, 2, "Adam");
433  ok(r == ERROR_SUCCESS, "MsiRecordSetString failed\n");
434  r = MsiRecordSetStringA(hrec, 3, "96905305");
435  ok(r == ERROR_SUCCESS, "MsiRecordSetString failed\n");
436 
437  /* insert another value, using a record and wildcards */
438  query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
439  "VALUES(?, ?, ?)";
440  r = MsiDatabaseOpenViewA(hdb, query, &hview);
441  ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
442 
443  if (r == ERROR_SUCCESS)
444  {
445  r = MsiViewExecute(hview, hrec);
446  ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
447  r = MsiViewClose(hview);
448  ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
449  r = MsiCloseHandle(hview);
450  ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
451  }
452  r = MsiCloseHandle(hrec);
453  ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
454 
455  r = MsiViewFetch(0, NULL);
456  ok(r == ERROR_INVALID_PARAMETER, "MsiViewFetch failed\n");
457 
458  r = MsiDatabaseCommit(hdb);
459  ok(r == ERROR_SUCCESS, "MsiDatabaseCommit failed\n");
460 
461  r = MsiCloseHandle(hdb);
462  ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
463 
464  r = DeleteFileA(msifile);
465  ok(r == TRUE, "file didn't exist after commit\n");
466 }
467 
468 static void test_msidecomposedesc(void)
469 {
470  UINT (WINAPI *pMsiDecomposeDescriptorA)(LPCSTR, LPCSTR, LPSTR, LPSTR, DWORD *);
472  const char *desc;
473  UINT r;
474  DWORD len;
475  HMODULE hmod;
476 
477  hmod = GetModuleHandleA("msi.dll");
478  pMsiDecomposeDescriptorA = (void*)GetProcAddress(hmod, "MsiDecomposeDescriptorA");
479  if (!pMsiDecomposeDescriptorA)
480  return;
481 
482  /* test a valid feature descriptor */
483  desc = "']gAVn-}f(ZXfeAR6.jiFollowTheWhiteRabbit>3w2x^IGfe?CxI5heAvk.";
484  len = 0;
485  prod[0] = feature[0] = comp[0] = 0;
486  r = pMsiDecomposeDescriptorA(desc, prod, feature, comp, &len);
487  ok(r == ERROR_SUCCESS, "returned an error\n");
488  ok(len == strlen(desc), "length was wrong\n");
489  ok(strcmp(prod,"{90110409-6000-11D3-8CFE-0150048383C9}")==0, "product wrong\n");
490  ok(strcmp(feature,"FollowTheWhiteRabbit")==0, "feature wrong\n");
491  ok(strcmp(comp,"{A7CD68DB-EF74-49C8-FBB2-A7C463B2AC24}")==0,"component wrong\n");
492 
493  /* test an invalid feature descriptor with too many characters */
494  desc = "']gAVn-}f(ZXfeAR6.ji"
495  "ThisWillFailIfTheresMoreThanAGuidsChars>"
496  "3w2x^IGfe?CxI5heAvk.";
497  len = 0;
498  r = pMsiDecomposeDescriptorA(desc, prod, feature, comp, &len);
499  ok(r == ERROR_INVALID_PARAMETER, "returned wrong error\n");
500 
501  /* test a feature descriptor with < instead of > */
502  desc = "']gAVn-}f(ZXfeAR6.jiFollowTheWhiteRabbit<3w2x^IGfe?CxI5heAvk.";
503  len = 0;
504  prod[0] = feature[0] = 0;
505  comp[0] = 0x55;
506  r = pMsiDecomposeDescriptorA(desc, prod, feature, comp, &len);
507  ok(r == ERROR_SUCCESS, "returned an error\n");
508  ok(len == 41, "got %u\n", len);
509  ok(!strcmp(prod,"{90110409-6000-11D3-8CFE-0150048383C9}"), "got '%s'\n", prod);
510  ok(!strcmp(feature,"FollowTheWhiteRabbit"), "got '%s'\n", feature);
511  ok(!comp[0], "got '%s'\n", comp);
512 
513  len = 0;
514  prod[0] = feature[0] = 0;
515  comp[0] = 0x55;
516  r = pMsiDecomposeDescriptorA("yh1BVN)8A$!!!!!MKKSkAlwaysInstalledIntl_1033<", prod, feature, comp, &len);
517  ok(r == ERROR_SUCCESS, "got %u\n", r);
518  ok(len == 45, "got %u\n", len);
519  ok(!strcmp(prod, "{90150000-006E-0409-0000-0000000FF1CE}"), "got '%s'\n", prod);
520  ok(!strcmp(feature, "AlwaysInstalledIntl_1033"), "got '%s'\n", feature);
521  ok(!comp[0], "got '%s'\n", comp);
522 
523  /*
524  * Test a valid feature descriptor with the
525  * maximum number of characters and some trailing characters.
526  */
527  desc = "']gAVn-}f(ZXfeAR6.ji"
528  "ThisWillWorkIfTheresLTEThanAGuidsChars>"
529  "3w2x^IGfe?CxI5heAvk."
530  "extra";
531  len = 0;
532  r = pMsiDecomposeDescriptorA(desc, prod, feature, comp, &len);
533  ok(r == ERROR_SUCCESS, "returned wrong error\n");
534  ok(len == (strlen(desc) - strlen("extra")), "length wrong\n");
535 
536  len = 0;
537  r = pMsiDecomposeDescriptorA(desc, prod, feature, NULL, &len);
538  ok(r == ERROR_SUCCESS, "returned wrong error\n");
539  ok(len == (strlen(desc) - strlen("extra")), "length wrong\n");
540 
541  len = 0;
542  r = pMsiDecomposeDescriptorA(desc, prod, NULL, NULL, &len);
543  ok(r == ERROR_SUCCESS, "returned wrong error\n");
544  ok(len == (strlen(desc) - strlen("extra")), "length wrong\n");
545 
546  len = 0;
547  r = pMsiDecomposeDescriptorA(desc, NULL, NULL, NULL, &len);
548  ok(r == ERROR_SUCCESS, "returned wrong error\n");
549  ok(len == (strlen(desc) - strlen("extra")), "length wrong\n");
550 
551  len = 0;
552  r = pMsiDecomposeDescriptorA(NULL, NULL, NULL, NULL, &len);
553  ok(r == ERROR_INVALID_PARAMETER, "returned wrong error\n");
554  ok(len == 0, "length wrong\n");
555 
556  r = pMsiDecomposeDescriptorA(desc, NULL, NULL, NULL, NULL);
557  ok(r == ERROR_SUCCESS, "returned wrong error\n");
558 }
559 
560 static UINT try_query_param( MSIHANDLE hdb, LPCSTR szQuery, MSIHANDLE hrec )
561 {
562  MSIHANDLE htab = 0;
563  UINT res;
564 
565  res = MsiDatabaseOpenViewA( hdb, szQuery, &htab );
566  if(res == ERROR_SUCCESS )
567  {
568  UINT r;
569 
570  r = MsiViewExecute( htab, hrec );
571  if(r != ERROR_SUCCESS )
572  res = r;
573 
574  r = MsiViewClose( htab );
575  if(r != ERROR_SUCCESS )
576  res = r;
577 
578  r = MsiCloseHandle( htab );
579  if(r != ERROR_SUCCESS )
580  res = r;
581  }
582  return res;
583 }
584 
585 static UINT try_query( MSIHANDLE hdb, LPCSTR szQuery )
586 {
587  return try_query_param( hdb, szQuery, 0 );
588 }
589 
590 static UINT try_insert_query( MSIHANDLE hdb, LPCSTR szQuery )
591 {
592  MSIHANDLE hrec = 0;
593  UINT r;
594 
595  hrec = MsiCreateRecord( 1 );
596  MsiRecordSetStringA( hrec, 1, "Hello");
597 
598  r = try_query_param( hdb, szQuery, hrec );
599 
600  MsiCloseHandle( hrec );
601  return r;
602 }
603 
604 static void test_msibadqueries(void)
605 {
606  MSIHANDLE hdb = 0;
607  UINT r;
608 
610 
611  /* just MsiOpenDatabase should not create a file */
613  ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
614 
615  r = MsiDatabaseCommit( hdb );
616  ok(r == ERROR_SUCCESS , "Failed to commit database\n");
617 
618  r = MsiCloseHandle( hdb );
619  ok(r == ERROR_SUCCESS , "Failed to close database\n");
620 
621  /* open it readonly */
623  ok(r == ERROR_SUCCESS , "Failed to open database r/o\n");
624 
625  /* add a table to it */
626  r = try_query( hdb, "select * from _Tables");
627  ok(r == ERROR_SUCCESS , "query 1 failed\n");
628 
629  r = MsiCloseHandle( hdb );
630  ok(r == ERROR_SUCCESS , "Failed to close database r/o\n");
631 
632  /* open it read/write */
634  ok(r == ERROR_SUCCESS , "Failed to open database r/w\n");
635 
636  /* a bunch of test queries that fail with the native MSI */
637 
638  r = try_query( hdb, "CREATE TABLE");
639  ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2a return code\n");
640 
641  r = try_query( hdb, "CREATE TABLE `a`");
642  ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2b return code\n");
643 
644  r = try_query( hdb, "CREATE TABLE `a` ()");
645  ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2c return code\n");
646 
647  r = try_query( hdb, "CREATE TABLE `a` (`b`)");
648  ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2d return code\n");
649 
650  r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) )");
651  ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2e return code\n");
652 
653  r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL)");
654  ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2f return code\n");
655 
656  r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY)");
657  ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2g return code\n");
658 
659  r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY)");
660  ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2h return code\n");
661 
662  r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY)");
663  ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2i return code\n");
664 
665  r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY 'b')");
666  ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2j return code\n");
667 
668  r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY `b')");
669  ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2k return code\n");
670 
671  r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY `b')");
672  ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2l return code\n");
673 
674  r = try_query( hdb, "CREATE TABLE `a` (`b` CHA(72) NOT NULL PRIMARY KEY `b`)");
675  ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2m return code\n");
676 
677  r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(-1) NOT NULL PRIMARY KEY `b`)");
678  ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2n return code\n");
679 
680  r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(720) NOT NULL PRIMARY KEY `b`)");
681  ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2o return code\n");
682 
683  r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL KEY `b`)");
684  ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2p return code\n");
685 
686  r = try_query( hdb, "CREATE TABLE `a` (`` CHAR(72) NOT NULL PRIMARY KEY `b`)");
687  ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2p return code\n");
688 
689  r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY `b`)");
690  ok(r == ERROR_SUCCESS , "valid query 2z failed\n");
691 
692  r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY `b`)");
693  ok(r == ERROR_BAD_QUERY_SYNTAX , "created same table again\n");
694 
695  r = try_query( hdb, "CREATE TABLE `aa` (`b` CHAR(72) NOT NULL, `c` "
696  "CHAR(72), `d` CHAR(255) NOT NULL LOCALIZABLE PRIMARY KEY `b`)");
697  ok(r == ERROR_SUCCESS , "query 4 failed\n");
698 
699  r = MsiDatabaseCommit( hdb );
700  ok(r == ERROR_SUCCESS , "Failed to commit database after write\n");
701 
702  r = try_query( hdb, "CREATE TABLE `blah` (`foo` CHAR(72) NOT NULL "
703  "PRIMARY KEY `foo`)");
704  ok(r == ERROR_SUCCESS , "query 4 failed\n");
705 
706  r = try_insert_query( hdb, "insert into a ( `b` ) VALUES ( ? )");
707  ok(r == ERROR_SUCCESS , "failed to insert record in db\n");
708 
709  r = MsiDatabaseCommit( hdb );
710  ok(r == ERROR_SUCCESS , "Failed to commit database after write\n");
711 
712  r = try_query( hdb, "CREATE TABLE `boo` (`foo` CHAR(72) NOT NULL "
713  "PRIMARY KEY `ba`)");
714  ok(r != ERROR_SUCCESS , "query 5 succeeded\n");
715 
716  r = try_query( hdb,"CREATE TABLE `bee` (`foo` CHAR(72) NOT NULL )");
717  ok(r != ERROR_SUCCESS , "query 6 succeeded\n");
718 
719  r = try_query( hdb, "CREATE TABLE `temp` (`t` CHAR(72) NOT NULL "
720  "PRIMARY KEY `t`)");
721  ok(r == ERROR_SUCCESS , "query 7 failed\n");
722 
723  r = try_query( hdb, "CREATE TABLE `c` (`b` CHAR NOT NULL PRIMARY KEY `b`)");
724  ok(r == ERROR_SUCCESS , "query 8 failed\n");
725 
726  r = try_query( hdb, "select * from c");
727  ok(r == ERROR_SUCCESS , "query failed\n");
728 
729  r = try_query( hdb, "select * from c where b = 'x");
730  ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
731 
732  r = try_query( hdb, "select * from c where b = 'x'");
733  ok(r == ERROR_SUCCESS, "query failed\n");
734 
735  r = try_query( hdb, "select * from 'c'");
736  ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
737 
738  r = try_query( hdb, "select * from ''");
739  ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
740 
741  r = try_query( hdb, "select * from c where b = x");
742  ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
743 
744  r = try_query( hdb, "select * from c where b = \"x\"");
745  ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
746 
747  r = try_query( hdb, "select * from c where b = 'x'");
748  ok(r == ERROR_SUCCESS, "query failed\n");
749 
750  r = try_query( hdb, "select * from c where b = '\"x'");
751  ok(r == ERROR_SUCCESS, "query failed\n");
752 
753  if (0) /* FIXME: this query causes trouble with other tests */
754  {
755  r = try_query( hdb, "select * from c where b = '\\\'x'");
756  ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
757  }
758 
759  r = try_query( hdb, "select * from 'c'");
760  ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n");
761 
762  r = try_query( hdb, "select `c`.`b` from `c` order by `c`.`order`");
763  ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %u\n", r );
764 
765  r = try_query( hdb, "select `c`.b` from `c`");
766  ok( r == ERROR_SUCCESS, "query failed: %u\n", r );
767 
768  r = try_query( hdb, "select `c`.`b from `c`");
769  ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %u\n", r );
770 
771  r = try_query( hdb, "select `c`.b from `c`");
772  ok( r == ERROR_SUCCESS, "query failed: %u\n", r );
773 
774  r = try_query( hdb, "select `c.`b` from `c`");
775  ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %u\n", r );
776 
777  r = try_query( hdb, "select c`.`b` from `c`");
778  ok( r == ERROR_SUCCESS, "query failed: %u\n", r );
779 
780  r = try_query( hdb, "select c.`b` from `c`");
781  ok( r == ERROR_SUCCESS, "query failed: %u\n", r );
782 
783  r = try_query( hdb, "select `c`.`b` from c`");
784  ok( r == ERROR_SUCCESS, "query failed: %u\n", r );
785 
786  r = try_query( hdb, "select `c`.`b` from `c");
787  ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %u\n", r );
788 
789  r = try_query( hdb, "select `c`.`b` from c");
790  ok( r == ERROR_SUCCESS, "query failed: %u\n", r );
791 
792  r = try_query( hdb, "CREATE TABLE `\5a` (`b` CHAR NOT NULL PRIMARY KEY `b`)" );
793  ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
794 
795  r = try_query( hdb, "SELECT * FROM \5a" );
796  ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
797 
798  r = try_query( hdb, "CREATE TABLE `a\5` (`b` CHAR NOT NULL PRIMARY KEY `b`)" );
799  ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
800 
801  r = try_query( hdb, "SELECT * FROM a\5" );
802  ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
803 
804  r = try_query( hdb, "CREATE TABLE `-a` (`b` CHAR NOT NULL PRIMARY KEY `b`)" );
805  ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
806 
807  r = try_query( hdb, "SELECT * FROM -a" );
808  todo_wine ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
809 
810  r = try_query( hdb, "CREATE TABLE `a-` (`b` CHAR NOT NULL PRIMARY KEY `b`)" );
811  ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
812 
813  r = try_query( hdb, "SELECT * FROM a-" );
814  ok( r == ERROR_SUCCESS , "query failed: %u\n", r );
815 
816  r = MsiCloseHandle( hdb );
817  ok(r == ERROR_SUCCESS , "Failed to close database transact\n");
818 
819  r = DeleteFileA( msifile );
820  ok(r == TRUE, "file didn't exist after commit\n");
821 }
822 
823 static void test_viewmodify(void)
824 {
825  MSIHANDLE hdb = 0, hview = 0, hrec = 0;
826  UINT r;
827  MSIDBERROR err;
828  const char *query;
829  char buffer[0x100];
830  DWORD sz;
831 
833 
834  /* just MsiOpenDatabase should not create a file */
836  ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
837 
838  query = "CREATE TABLE `phone` ( "
839  "`id` INT, `name` CHAR(32), `number` CHAR(32) "
840  "PRIMARY KEY `id`)";
841  r = run_query( hdb, 0, query );
842  ok(r == ERROR_SUCCESS, "query failed\n");
843 
844  query = "CREATE TABLE `_Validation` ( "
845  "`Table` CHAR(32) NOT NULL, `Column` CHAR(32) NOT NULL, "
846  "`Nullable` CHAR(4) NOT NULL, `MinValue` INT, `MaxValue` INT, "
847  "`KeyTable` CHAR(255), `KeyColumn` SHORT, `Category` CHAR(32), "
848  "`Set` CHAR(255), `Description` CHAR(255) PRIMARY KEY `Table`, `Column`)";
849  r = run_query( hdb, 0, query );
850  ok(r == ERROR_SUCCESS, "query failed\n");
851 
852  query = "INSERT INTO `_Validation` ( `Table`, `Column`, `Nullable` ) "
853  "VALUES('phone', 'id', 'N')";
854  r = run_query( hdb, 0, query );
855  ok(r == ERROR_SUCCESS, "query failed\n");
856 
857  /* check what the error function reports without doing anything */
858  sz = 0;
859  /* passing NULL as the 3rd param make function to crash on older platforms */
860  err = MsiViewGetErrorA( 0, NULL, &sz );
861  ok(err == MSIDBERROR_INVALIDARG, "MsiViewGetError return\n");
862 
863  /* open a view */
864  query = "SELECT * FROM `phone`";
865  r = MsiDatabaseOpenViewA(hdb, query, &hview);
866  ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
867 
868  /* see what happens with a good hview and bad args */
869  err = MsiViewGetErrorA( hview, NULL, NULL );
871  "MsiViewGetError returns %u (expected -3)\n", err);
872  err = MsiViewGetErrorA( hview, buffer, NULL );
873  ok(err == MSIDBERROR_INVALIDARG, "MsiViewGetError return\n");
874 
875  /* see what happens with a zero length buffer */
876  sz = 0;
877  buffer[0] = 'x';
878  err = MsiViewGetErrorA( hview, buffer, &sz );
879  ok(err == MSIDBERROR_MOREDATA, "MsiViewGetError return\n");
880  ok(buffer[0] == 'x', "buffer cleared\n");
881  ok(sz == 0, "size not zero\n");
882 
883  /* ok this one is strange */
884  sz = 0;
885  err = MsiViewGetErrorA( hview, NULL, &sz );
886  ok(err == MSIDBERROR_NOERROR, "MsiViewGetError return\n");
887  ok(sz == 0, "size not zero\n");
888 
889  /* see if it really has an error */
890  sz = sizeof buffer;
891  buffer[0] = 'x';
892  err = MsiViewGetErrorA( hview, buffer, &sz );
893  ok(err == MSIDBERROR_NOERROR, "MsiViewGetError return\n");
894  ok(buffer[0] == 0, "buffer not cleared\n");
895  ok(sz == 0, "size not zero\n");
896 
897  r = MsiViewExecute(hview, 0);
898  ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
899 
900  /* try some invalid records */
901  r = MsiViewModify(hview, MSIMODIFY_INSERT, 0 );
902  ok(r == ERROR_INVALID_HANDLE, "MsiViewModify failed\n");
903  r = MsiViewModify(hview, -1, 0 );
904  ok(r == ERROR_INVALID_HANDLE, "MsiViewModify failed\n");
905 
906  /* try an small record */
907  hrec = MsiCreateRecord(1);
908  r = MsiViewModify(hview, -1, hrec );
909  ok(r == ERROR_INVALID_DATA, "MsiViewModify failed\n");
910 
911  sz = sizeof buffer;
912  buffer[0] = 'x';
913  err = MsiViewGetErrorA( hview, buffer, &sz );
914  ok(err == MSIDBERROR_NOERROR, "MsiViewGetError return\n");
915  ok(buffer[0] == 0, "buffer not cleared\n");
916  ok(sz == 0, "size not zero\n");
917 
918  r = MsiCloseHandle(hrec);
919  ok(r == ERROR_SUCCESS, "failed to close record\n");
920 
921  /* insert a valid record */
922  hrec = MsiCreateRecord(3);
923 
924  r = MsiRecordSetInteger(hrec, 1, 1);
925  ok(r == ERROR_SUCCESS, "failed to set integer\n");
926  r = MsiRecordSetStringA(hrec, 2, "bob");
927  ok(r == ERROR_SUCCESS, "failed to set string\n");
928  r = MsiRecordSetStringA(hrec, 3, "7654321");
929  ok(r == ERROR_SUCCESS, "failed to set string\n");
930 
931  r = MsiViewExecute(hview, 0);
932  ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
933  r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec );
934  ok(r == ERROR_SUCCESS, "MsiViewModify failed\n");
935 
936  /* validate it */
937  r = MsiViewExecute(hview, 0);
938  ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
939 
940  r = MsiViewModify(hview, MSIMODIFY_VALIDATE_NEW, hrec );
941  ok(r == ERROR_INVALID_DATA, "MsiViewModify failed %u\n", r);
942 
943  sz = sizeof buffer;
944  buffer[0] = 'x';
945  err = MsiViewGetErrorA( hview, buffer, &sz );
946  ok(err == MSIDBERROR_DUPLICATEKEY, "MsiViewGetError returned %u\n", err);
947  ok(!strcmp(buffer, "id"), "expected \"id\" c, got \"%s\"\n", buffer);
948  ok(sz == 2, "size not 2\n");
949 
950  /* insert the same thing again */
951  r = MsiViewExecute(hview, 0);
952  ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
953 
954  /* should fail ... */
955  r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec );
956  ok(r == ERROR_FUNCTION_FAILED, "MsiViewModify failed\n");
957 
958  /* try to merge the same record */
959  r = MsiViewExecute(hview, 0);
960  ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
961  r = MsiViewModify(hview, MSIMODIFY_MERGE, hrec );
962  ok(r == ERROR_SUCCESS, "MsiViewModify failed\n");
963 
964  r = MsiCloseHandle(hrec);
965  ok(r == ERROR_SUCCESS, "failed to close record\n");
966 
967  /* try merging a new record */
968  hrec = MsiCreateRecord(3);
969 
970  r = MsiRecordSetInteger(hrec, 1, 10);
971  ok(r == ERROR_SUCCESS, "failed to set integer\n");
972  r = MsiRecordSetStringA(hrec, 2, "pepe");
973  ok(r == ERROR_SUCCESS, "failed to set string\n");
974  r = MsiRecordSetStringA(hrec, 3, "7654321");
975  ok(r == ERROR_SUCCESS, "failed to set string\n");
976 
977  r = MsiViewModify(hview, MSIMODIFY_MERGE, hrec );
978  ok(r == ERROR_SUCCESS, "MsiViewModify failed\n");
979  r = MsiViewExecute(hview, 0);
980  ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
981 
982  r = MsiCloseHandle(hrec);
983  ok(r == ERROR_SUCCESS, "failed to close record\n");
984 
985  r = MsiViewClose(hview);
986  ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
987  r = MsiCloseHandle(hview);
988  ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
989 
990  query = "SELECT * FROM `phone`";
991  r = MsiDatabaseOpenViewA(hdb, query, &hview);
992  ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
993 
994  r = MsiViewExecute(hview, 0);
995  ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
996 
997  r = MsiViewFetch(hview, &hrec);
998  ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
999 
1000  r = MsiRecordGetInteger(hrec, 1);
1001  ok(r == 1, "Expected 1, got %d\n", r);
1002 
1003  sz = sizeof(buffer);
1004  r = MsiRecordGetStringA(hrec, 2, buffer, &sz);
1005  ok(r == ERROR_SUCCESS, "MsiRecordGetString failed\n");
1006  ok(!lstrcmpA(buffer, "bob"), "Expected bob, got %s\n", buffer);
1007 
1008  sz = sizeof(buffer);
1009  r = MsiRecordGetStringA(hrec, 3, buffer, &sz);
1010  ok(r == ERROR_SUCCESS, "MsiRecordGetString failed\n");
1011  ok(!lstrcmpA(buffer, "7654321"), "Expected 7654321, got %s\n", buffer);
1012 
1013  /* update the view, non-primary key */
1014  r = MsiRecordSetStringA(hrec, 3, "3141592");
1015  ok(r == ERROR_SUCCESS, "MsiRecordSetString failed\n");
1016 
1017  r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
1018  ok(r == ERROR_SUCCESS, "MsiViewModify failed\n");
1019 
1020  /* do it again */
1021  r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
1022  ok(r == ERROR_SUCCESS, "MsiViewModify failed: %d\n", r);
1023 
1024  /* update the view, primary key */
1025  r = MsiRecordSetInteger(hrec, 1, 5);
1026  ok(r == ERROR_SUCCESS, "MsiRecordSetInteger failed\n");
1027 
1028  r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
1029  ok(r == ERROR_FUNCTION_FAILED, "MsiViewModify failed\n");
1030 
1031  r = MsiCloseHandle(hrec);
1032  ok(r == ERROR_SUCCESS, "failed to close record\n");
1033 
1034  r = MsiViewClose(hview);
1035  ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
1036  r = MsiCloseHandle(hview);
1037  ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
1038 
1039  query = "SELECT * FROM `phone`";
1040  r = MsiDatabaseOpenViewA(hdb, query, &hview);
1041  ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
1042 
1043  r = MsiViewExecute(hview, 0);
1044  ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
1045 
1046  r = MsiViewFetch(hview, &hrec);
1047  ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
1048 
1049  r = MsiRecordGetInteger(hrec, 1);
1050  ok(r == 1, "Expected 1, got %d\n", r);
1051 
1052  sz = sizeof(buffer);
1053  r = MsiRecordGetStringA(hrec, 2, buffer, &sz);
1054  ok(r == ERROR_SUCCESS, "MsiRecordGetString failed\n");
1055  ok(!lstrcmpA(buffer, "bob"), "Expected bob, got %s\n", buffer);
1056 
1057  sz = sizeof(buffer);
1058  r = MsiRecordGetStringA(hrec, 3, buffer, &sz);
1059  ok(r == ERROR_SUCCESS, "MsiRecordGetString failed\n");
1060  ok(!lstrcmpA(buffer, "3141592"), "Expected 3141592, got %s\n", buffer);
1061 
1062  r = MsiCloseHandle(hrec);
1063  ok(r == ERROR_SUCCESS, "failed to close record\n");
1064 
1065  /* use a record that doesn't come from a view fetch */
1066  hrec = MsiCreateRecord(3);
1067  ok(hrec != 0, "MsiCreateRecord failed\n");
1068 
1069  r = MsiRecordSetInteger(hrec, 1, 3);
1070  ok(r == ERROR_SUCCESS, "failed to set integer\n");
1071  r = MsiRecordSetStringA(hrec, 2, "jane");
1072  ok(r == ERROR_SUCCESS, "failed to set string\n");
1073  r = MsiRecordSetStringA(hrec, 3, "112358");
1074  ok(r == ERROR_SUCCESS, "failed to set string\n");
1075 
1076  r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
1077  ok(r == ERROR_FUNCTION_FAILED, "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
1078 
1079  r = MsiCloseHandle(hrec);
1080  ok(r == ERROR_SUCCESS, "failed to close record\n");
1081 
1082  /* use a record that doesn't come from a view fetch, primary key matches */
1083  hrec = MsiCreateRecord(3);
1084  ok(hrec != 0, "MsiCreateRecord failed\n");
1085 
1086  r = MsiRecordSetInteger(hrec, 1, 1);
1087  ok(r == ERROR_SUCCESS, "failed to set integer\n");
1088  r = MsiRecordSetStringA(hrec, 2, "jane");
1089  ok(r == ERROR_SUCCESS, "failed to set string\n");
1090  r = MsiRecordSetStringA(hrec, 3, "112358");
1091  ok(r == ERROR_SUCCESS, "failed to set string\n");
1092 
1093  r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
1094  ok(r == ERROR_FUNCTION_FAILED, "MsiViewModify failed\n");
1095 
1096  r = MsiCloseHandle(hrec);
1097  ok(r == ERROR_SUCCESS, "failed to close record\n");
1098 
1099  hrec = MsiCreateRecord(3);
1100 
1101  r = MsiRecordSetInteger(hrec, 1, 2);
1102  ok(r == ERROR_SUCCESS, "failed to set integer\n");
1103  r = MsiRecordSetStringA(hrec, 2, "nick");
1104  ok(r == ERROR_SUCCESS, "failed to set string\n");
1105  r = MsiRecordSetStringA(hrec, 3, "141421");
1106  ok(r == ERROR_SUCCESS, "failed to set string\n");
1107 
1108  r = MsiViewExecute(hview, 0);
1109  ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
1110  r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec );
1111  ok(r == ERROR_SUCCESS, "MsiViewModify failed\n");
1112 
1113  r = MsiCloseHandle(hrec);
1114  ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
1115  r = MsiViewClose(hview);
1116  ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
1117  r = MsiCloseHandle(hview);
1118  ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
1119 
1120  query = "SELECT * FROM `phone` WHERE `id` = 1";
1121  r = MsiDatabaseOpenViewA(hdb, query, &hview);
1122  ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
1123  r = MsiViewExecute(hview, 0);
1124  ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
1125  r = MsiViewFetch(hview, &hrec);
1126  ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
1127 
1128  /* change the id to match the second row */
1129  r = MsiRecordSetInteger(hrec, 1, 2);
1130  ok(r == ERROR_SUCCESS, "failed to set integer\n");
1131  r = MsiRecordSetStringA(hrec, 2, "jerry");
1132  ok(r == ERROR_SUCCESS, "failed to set string\n");
1133 
1134  r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
1135  ok(r == ERROR_FUNCTION_FAILED, "MsiViewModify failed\n");
1136 
1137  r = MsiCloseHandle(hrec);
1138  ok(r == ERROR_SUCCESS, "failed to close record\n");
1139  r = MsiViewClose(hview);
1140  ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
1141  r = MsiCloseHandle(hview);
1142  ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
1143 
1144  /* broader search */
1145  query = "SELECT * FROM `phone` ORDER BY `id`";
1146  r = MsiDatabaseOpenViewA(hdb, query, &hview);
1147  ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
1148  r = MsiViewExecute(hview, 0);
1149  ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
1150  r = MsiViewFetch(hview, &hrec);
1151  ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
1152 
1153  /* change the id to match the second row */
1154  r = MsiRecordSetInteger(hrec, 1, 2);
1155  ok(r == ERROR_SUCCESS, "failed to set integer\n");
1156  r = MsiRecordSetStringA(hrec, 2, "jerry");
1157  ok(r == ERROR_SUCCESS, "failed to set string\n");
1158 
1159  r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec);
1160  ok(r == ERROR_FUNCTION_FAILED, "MsiViewModify failed\n");
1161 
1162  r = MsiCloseHandle(hrec);
1163  ok(r == ERROR_SUCCESS, "failed to close record\n");
1164  r = MsiViewClose(hview);
1165  ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
1166  r = MsiCloseHandle(hview);
1167  ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
1168 
1169  r = MsiCloseHandle( hdb );
1170  ok(r == ERROR_SUCCESS, "MsiOpenDatabase close failed\n");
1171 }
1172 
1173 static MSIHANDLE create_db(void)
1174 {
1175  MSIHANDLE hdb = 0;
1176  UINT res;
1177 
1179 
1180  /* create an empty database */
1182  ok( res == ERROR_SUCCESS , "Failed to create database\n" );
1183  if( res != ERROR_SUCCESS )
1184  return hdb;
1185 
1186  res = MsiDatabaseCommit( hdb );
1187  ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
1188 
1189  return hdb;
1190 }
1191 
1192 static void test_getcolinfo(void)
1193 {
1194  MSIHANDLE hdb, hview = 0, rec = 0;
1195  UINT r;
1196  DWORD sz;
1197  char buffer[0x20];
1198 
1199  /* create an empty db */
1200  hdb = create_db();
1201  ok( hdb, "failed to create db\n");
1202 
1203  /* tables should be present */
1204  r = MsiDatabaseOpenViewA(hdb, "select * from _Tables", &hview);
1205  ok( r == ERROR_SUCCESS, "failed to open query\n");
1206 
1207  r = MsiViewExecute(hview, 0);
1208  ok( r == ERROR_SUCCESS, "failed to execute query\n");
1209 
1210  /* check that NAMES works */
1211  rec = 0;
1212  r = MsiViewGetColumnInfo( hview, MSICOLINFO_NAMES, &rec );
1213  ok( r == ERROR_SUCCESS, "failed to get names\n");
1214  sz = sizeof buffer;
1215  r = MsiRecordGetStringA(rec, 1, buffer, &sz );
1216  ok( r == ERROR_SUCCESS, "failed to get string\n");
1217  ok( !strcmp(buffer,"Name"), "_Tables has wrong column name\n");
1218  r = MsiCloseHandle( rec );
1219  ok( r == ERROR_SUCCESS, "failed to close record handle\n");
1220 
1221  /* check that TYPES works */
1222  rec = 0;
1223  r = MsiViewGetColumnInfo( hview, MSICOLINFO_TYPES, &rec );
1224  ok( r == ERROR_SUCCESS, "failed to get names\n");
1225  sz = sizeof buffer;
1226  r = MsiRecordGetStringA(rec, 1, buffer, &sz );
1227  ok( r == ERROR_SUCCESS, "failed to get string\n");
1228  ok( !strcmp(buffer,"s64"), "_Tables has wrong column type\n");
1229  r = MsiCloseHandle( rec );
1230  ok( r == ERROR_SUCCESS, "failed to close record handle\n");
1231 
1232  /* check that invalid values fail */
1233  rec = 0;
1234  r = MsiViewGetColumnInfo( hview, 100, &rec );
1235  ok( r == ERROR_INVALID_PARAMETER, "wrong error code\n");
1236  ok( rec == 0, "returned a record\n");
1237 
1239  ok( r == ERROR_INVALID_PARAMETER, "wrong error code\n");
1240 
1241  r = MsiViewGetColumnInfo( 0, MSICOLINFO_TYPES, &rec );
1242  ok( r == ERROR_INVALID_HANDLE, "wrong error code\n");
1243 
1244  r = MsiViewClose(hview);
1245  ok( r == ERROR_SUCCESS, "failed to close view\n");
1246  r = MsiCloseHandle(hview);
1247  ok( r == ERROR_SUCCESS, "failed to close view handle\n");
1248  r = MsiCloseHandle(hdb);
1249  ok( r == ERROR_SUCCESS, "failed to close database\n");
1250 }
1251 
1253 {
1254  MSIHANDLE hview = 0, rec = 0;
1255  UINT r;
1256 
1257  r = MsiDatabaseOpenViewA(hdb, query, &hview);
1258  if( r != ERROR_SUCCESS )
1259  return r;
1260 
1261  r = MsiViewExecute(hview, 0);
1262  if( r == ERROR_SUCCESS )
1263  {
1264  MsiViewGetColumnInfo( hview, type, &rec );
1265  }
1266  MsiViewClose(hview);
1267  MsiCloseHandle(hview);
1268  return rec;
1269 }
1270 
1272 {
1273  MSIHANDLE hview = 0, rec = 0;
1274  UINT r, type = 0;
1275  char query[0x100];
1276 
1277  sprintf(query, "select * from `_Columns` where `Table` = '%s'", table );
1278 
1279  r = MsiDatabaseOpenViewA(hdb, query, &hview);
1280  if( r != ERROR_SUCCESS )
1281  return r;
1282 
1283  r = MsiViewExecute(hview, 0);
1284  if( r == ERROR_SUCCESS )
1285  {
1286  while (1)
1287  {
1288  r = MsiViewFetch( hview, &rec );
1289  if( r != ERROR_SUCCESS)
1290  break;
1291  r = MsiRecordGetInteger( rec, 2 );
1292  if (r == field)
1293  type = MsiRecordGetInteger( rec, 4 );
1294  MsiCloseHandle( rec );
1295  }
1296  }
1297  MsiViewClose(hview);
1298  MsiCloseHandle(hview);
1299  return type;
1300 }
1301 
1303 {
1304  CHAR buffer[0x20];
1305  UINT r;
1306  DWORD sz;
1307 
1308  sz = sizeof buffer;
1309  r = MsiRecordGetStringA( rec, field, buffer, &sz );
1310  return (r == ERROR_SUCCESS ) && !strcmp(val, buffer);
1311 }
1312 
1313 static void test_viewgetcolumninfo(void)
1314 {
1315  MSIHANDLE hdb = 0, rec;
1316  UINT r;
1317 
1318  hdb = create_db();
1319  ok( hdb, "failed to create db\n");
1320 
1321  r = run_query( hdb, 0,
1322  "CREATE TABLE `Properties` "
1323  "( `Property` CHAR(255), "
1324  " `Value` CHAR(1), "
1325  " `Intvalue` INT, "
1326  " `Integervalue` INTEGER, "
1327  " `Shortvalue` SHORT, "
1328  " `Longvalue` LONG, "
1329  " `Longcharvalue` LONGCHAR, "
1330  " `Charvalue` CHAR, "
1331  " `Localizablevalue` CHAR LOCALIZABLE "
1332  " PRIMARY KEY `Property`)" );
1333  ok( r == ERROR_SUCCESS , "Failed to create table\n" );
1334 
1335  /* check the column types */
1336  rec = get_column_info( hdb, "select * from `Properties`", MSICOLINFO_TYPES );
1337  ok( rec, "failed to get column info record\n" );
1338 
1339  ok( check_record( rec, 1, "S255"), "wrong record type\n");
1340  ok( check_record( rec, 2, "S1"), "wrong record type\n");
1341  ok( check_record( rec, 3, "I2"), "wrong record type\n");
1342  ok( check_record( rec, 4, "I2"), "wrong record type\n");
1343  ok( check_record( rec, 5, "I2"), "wrong record type\n");
1344  ok( check_record( rec, 6, "I4"), "wrong record type\n");
1345  ok( check_record( rec, 7, "S0"), "wrong record type\n");
1346  ok( check_record( rec, 8, "S0"), "wrong record type\n");
1347  ok( check_record( rec, 9, "L0"), "wrong record type\n");
1348 
1349  MsiCloseHandle( rec );
1350 
1351  /* check the type in _Columns */
1352  ok( 0x3dff == get_columns_table_type(hdb, "Properties", 1 ), "_columns table wrong\n");
1353  ok( 0x1d01 == get_columns_table_type(hdb, "Properties", 2 ), "_columns table wrong\n");
1354  ok( 0x1502 == get_columns_table_type(hdb, "Properties", 3 ), "_columns table wrong\n");
1355  ok( 0x1502 == get_columns_table_type(hdb, "Properties", 4 ), "_columns table wrong\n");
1356  ok( 0x1502 == get_columns_table_type(hdb, "Properties", 5 ), "_columns table wrong\n");
1357  ok( 0x1104 == get_columns_table_type(hdb, "Properties", 6 ), "_columns table wrong\n");
1358  ok( 0x1d00 == get_columns_table_type(hdb, "Properties", 7 ), "_columns table wrong\n");
1359  ok( 0x1d00 == get_columns_table_type(hdb, "Properties", 8 ), "_columns table wrong\n");
1360  ok( 0x1f00 == get_columns_table_type(hdb, "Properties", 9 ), "_columns table wrong\n");
1361 
1362  /* now try the names */
1363  rec = get_column_info( hdb, "select * from `Properties`", MSICOLINFO_NAMES );
1364  ok( rec, "failed to get column info record\n" );
1365 
1366  ok( check_record( rec, 1, "Property"), "wrong record type\n");
1367  ok( check_record( rec, 2, "Value"), "wrong record type\n");
1368  ok( check_record( rec, 3, "Intvalue"), "wrong record type\n");
1369  ok( check_record( rec, 4, "Integervalue"), "wrong record type\n");
1370  ok( check_record( rec, 5, "Shortvalue"), "wrong record type\n");
1371  ok( check_record( rec, 6, "Longvalue"), "wrong record type\n");
1372  ok( check_record( rec, 7, "Longcharvalue"), "wrong record type\n");
1373  ok( check_record( rec, 8, "Charvalue"), "wrong record type\n");
1374  ok( check_record( rec, 9, "Localizablevalue"), "wrong record type\n");
1375 
1376  MsiCloseHandle( rec );
1377 
1378  r = run_query( hdb, 0,
1379  "CREATE TABLE `Binary` "
1380  "( `Name` CHAR(255), `Data` OBJECT PRIMARY KEY `Name`)" );
1381  ok( r == ERROR_SUCCESS , "Failed to create table\n" );
1382 
1383  /* check the column types */
1384  rec = get_column_info( hdb, "select * from `Binary`", MSICOLINFO_TYPES );
1385  ok( rec, "failed to get column info record\n" );
1386 
1387  ok( check_record( rec, 1, "S255"), "wrong record type\n");
1388  ok( check_record( rec, 2, "V0"), "wrong record type\n");
1389 
1390  MsiCloseHandle( rec );
1391 
1392  /* check the type in _Columns */
1393  ok( 0x3dff == get_columns_table_type(hdb, "Binary", 1 ), "_columns table wrong\n");
1394  ok( 0x1900 == get_columns_table_type(hdb, "Binary", 2 ), "_columns table wrong\n");
1395 
1396  /* now try the names */
1397  rec = get_column_info( hdb, "select * from `Binary`", MSICOLINFO_NAMES );
1398  ok( rec, "failed to get column info record\n" );
1399 
1400  ok( check_record( rec, 1, "Name"), "wrong record type\n");
1401  ok( check_record( rec, 2, "Data"), "wrong record type\n");
1402  MsiCloseHandle( rec );
1403 
1404  r = run_query( hdb, 0,
1405  "CREATE TABLE `UIText` "
1406  "( `Key` CHAR(72) NOT NULL, `Text` CHAR(255) LOCALIZABLE PRIMARY KEY `Key`)" );
1407  ok( r == ERROR_SUCCESS , "Failed to create table\n" );
1408 
1409  ok( 0x2d48 == get_columns_table_type(hdb, "UIText", 1 ), "_columns table wrong\n");
1410  ok( 0x1fff == get_columns_table_type(hdb, "UIText", 2 ), "_columns table wrong\n");
1411 
1412  rec = get_column_info( hdb, "select * from `UIText`", MSICOLINFO_NAMES );
1413  ok( rec, "failed to get column info record\n" );
1414  ok( check_record( rec, 1, "Key"), "wrong record type\n");
1415  ok( check_record( rec, 2, "Text"), "wrong record type\n");
1416  MsiCloseHandle( rec );
1417 
1418  rec = get_column_info( hdb, "select * from `UIText`", MSICOLINFO_TYPES );
1419  ok( rec, "failed to get column info record\n" );
1420  ok( check_record( rec, 1, "s72"), "wrong record type\n");
1421  ok( check_record( rec, 2, "L255"), "wrong record type\n");
1422  MsiCloseHandle( rec );
1423 
1424  MsiCloseHandle( hdb );
1425 }
1426 
1427 static void test_msiexport(void)
1428 {
1429  MSIHANDLE hdb = 0, hview = 0;
1430  UINT r;
1431  const char *query;
1432  char path[MAX_PATH];
1433  const char file[] = "phone.txt";
1434  HANDLE handle;
1435  char buffer[0x100];
1436  DWORD length;
1437  const char expected[] =
1438  "id\tname\tnumber\r\n"
1439  "I2\tS32\tS32\r\n"
1440  "phone\tid\r\n"
1441  "1\tAbe\t8675309\r\n";
1442 
1444 
1445  /* just MsiOpenDatabase should not create a file */
1447  ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
1448 
1449  /* create a table */
1450  query = "CREATE TABLE `phone` ( "
1451  "`id` INT, `name` CHAR(32), `number` CHAR(32) "
1452  "PRIMARY KEY `id`)";
1453  r = MsiDatabaseOpenViewA(hdb, query, &hview);
1454  ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
1455  r = MsiViewExecute(hview, 0);
1456  ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
1457  r = MsiViewClose(hview);
1458  ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
1459  r = MsiCloseHandle(hview);
1460  ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
1461 
1462  /* insert a value into it */
1463  query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
1464  "VALUES('1', 'Abe', '8675309')";
1465  r = MsiDatabaseOpenViewA(hdb, query, &hview);
1466  ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
1467  r = MsiViewExecute(hview, 0);
1468  ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
1469  r = MsiViewClose(hview);
1470  ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
1471  r = MsiCloseHandle(hview);
1472  ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
1473 
1475 
1476  r = MsiDatabaseExportA(hdb, "phone", path, file);
1477  ok(r == ERROR_SUCCESS, "MsiDatabaseExport failed\n");
1478 
1479  MsiCloseHandle(hdb);
1480 
1481  lstrcatA(path, "\\");
1482  lstrcatA(path, file);
1483 
1484  /* check the data that was written */
1485  length = 0;
1486  memset(buffer, 0, sizeof buffer);
1489  {
1490  ReadFile(handle, buffer, sizeof buffer, &length, NULL);
1492  DeleteFileA(path);
1493  }
1494  else
1495  ok(0, "failed to open file %s\n", path);
1496 
1497  ok( length == strlen(expected), "length of data wrong\n");
1498  ok( !lstrcmpA(buffer, expected), "data doesn't match\n");
1500 }
1501 
1502 static void test_longstrings(void)
1503 {
1504  const char insert_query[] =
1505  "INSERT INTO `strings` ( `id`, `val` ) VALUES('1', 'Z')";
1506  char *str;
1507  MSIHANDLE hdb = 0, hview = 0, hrec = 0;
1508  DWORD len;
1509  UINT r;
1510  const DWORD STRING_LENGTH = 0x10005;
1511 
1513  /* just MsiOpenDatabase should not create a file */
1515  ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
1516 
1517  /* create a table */
1518  r = try_query( hdb,
1519  "CREATE TABLE `strings` ( `id` INT, `val` CHAR(0) PRIMARY KEY `id`)");
1520  ok(r == ERROR_SUCCESS, "query failed\n");
1521 
1522  /* try to insert a very long string */
1523  str = HeapAlloc(GetProcessHeap(), 0, STRING_LENGTH+sizeof insert_query);
1524  len = strchr(insert_query, 'Z') - insert_query;
1525  strcpy(str, insert_query);
1526  memset(str+len, 'Z', STRING_LENGTH);
1527  strcpy(str+len+STRING_LENGTH, insert_query+len+1);
1528  r = try_query( hdb, str );
1529  ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
1530 
1531  HeapFree(GetProcessHeap(), 0, str);
1532 
1533  r = MsiDatabaseCommit(hdb);
1534  ok(r == ERROR_SUCCESS, "MsiDatabaseCommit failed\n");
1535  MsiCloseHandle(hdb);
1536 
1538  ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
1539 
1540  r = MsiDatabaseOpenViewA(hdb, "select * from `strings` where `id` = 1", &hview);
1541  ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
1542 
1543  r = MsiViewExecute(hview, 0);
1544  ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
1545 
1546  r = MsiViewFetch(hview, &hrec);
1547  ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
1548 
1549  MsiViewClose(hview);
1550  MsiCloseHandle(hview);
1551 
1552  r = MsiRecordGetStringA(hrec, 2, NULL, &len);
1553  ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
1554  ok(len == STRING_LENGTH, "string length wrong\n");
1555 
1556  MsiCloseHandle(hrec);
1557  MsiCloseHandle(hdb);
1559 }
1560 
1562 {
1563  HANDLE file;
1564  DWORD written;
1565 
1567  if (file == INVALID_HANDLE_VALUE)
1568  return;
1569 
1570  WriteFile(file, data, strlen(data), &written, NULL);
1571  WriteFile(file, "\n", strlen("\n"), &written, NULL);
1572 
1573  if (size)
1574  {
1576  SetEndOfFile(file);
1577  }
1578 
1579  CloseHandle(file);
1580 }
1581 
1582 #define create_file(name) create_file_data(name, name, 0)
1583 
1584 static void test_streamtable(void)
1585 {
1586  MSIHANDLE hdb = 0, rec, view, hsi;
1587  char file[MAX_PATH];
1588  char buf[MAX_PATH];
1589  DWORD size;
1590  UINT r;
1591 
1592  hdb = create_db();
1593  ok( hdb, "failed to create db\n");
1594 
1595  r = run_query( hdb, 0,
1596  "CREATE TABLE `Properties` "
1597  "( `Property` CHAR(255), `Value` CHAR(1) PRIMARY KEY `Property`)" );
1598  ok( r == ERROR_SUCCESS , "Failed to create table\n" );
1599 
1600  r = run_query( hdb, 0,
1601  "INSERT INTO `Properties` "
1602  "( `Value`, `Property` ) VALUES ( 'Prop', 'value' )" );
1603  ok( r == ERROR_SUCCESS, "Failed to add to table\n" );
1604 
1605  r = MsiDatabaseCommit( hdb );
1606  ok( r == ERROR_SUCCESS , "Failed to commit database\n" );
1607 
1608  MsiCloseHandle( hdb );
1609 
1611  ok( r == ERROR_SUCCESS , "Failed to open database\n" );
1612 
1613  /* check the column types */
1614  rec = get_column_info( hdb, "select * from `_Streams`", MSICOLINFO_TYPES );
1615  ok( rec, "failed to get column info record\n" );
1616 
1617  ok( check_record( rec, 1, "s62"), "wrong record type\n");
1618  ok( check_record( rec, 2, "V0"), "wrong record type\n");
1619 
1620  MsiCloseHandle( rec );
1621 
1622  /* now try the names */
1623  rec = get_column_info( hdb, "select * from `_Streams`", MSICOLINFO_NAMES );
1624  ok( rec, "failed to get column info record\n" );
1625 
1626  ok( check_record( rec, 1, "Name"), "wrong record type\n");
1627  ok( check_record( rec, 2, "Data"), "wrong record type\n");
1628 
1629  MsiCloseHandle( rec );
1630 
1631  r = MsiDatabaseOpenViewA( hdb,
1632  "SELECT * FROM `_Streams` WHERE `Name` = '\5SummaryInformation'", &view );
1633  ok( r == ERROR_SUCCESS, "Failed to open database view: %u\n", r );
1634 
1635  r = MsiViewExecute( view, 0 );
1636  ok( r == ERROR_SUCCESS, "Failed to execute view: %u\n", r );
1637 
1638  r = MsiViewFetch( view, &rec );
1639  ok( r == ERROR_NO_MORE_ITEMS, "Unexpected result: %u\n", r );
1640 
1641  MsiCloseHandle( rec );
1642  MsiViewClose( view );
1643  MsiCloseHandle( view );
1644 
1645  /* create a summary information stream */
1646  r = MsiGetSummaryInformationA( hdb, NULL, 1, &hsi );
1647  ok( r == ERROR_SUCCESS, "Failed to get summary information handle: %u\n", r );
1648 
1650  ok( r == ERROR_SUCCESS, "Failed to set property: %u\n", r );
1651 
1652  r = MsiSummaryInfoPersist( hsi );
1653  ok( r == ERROR_SUCCESS, "Failed to save summary information: %u\n", r );
1654 
1655  MsiCloseHandle( hsi );
1656 
1657  r = MsiDatabaseOpenViewA( hdb,
1658  "SELECT * FROM `_Streams` WHERE `Name` = '\5SummaryInformation'", &view );
1659  ok( r == ERROR_SUCCESS, "Failed to open database view: %u\n", r );
1660 
1661  r = MsiViewExecute( view, 0 );
1662  ok( r == ERROR_SUCCESS, "Failed to execute view: %u\n", r );
1663 
1664  r = MsiViewFetch( view, &rec );
1665  ok( r == ERROR_SUCCESS, "Unexpected result: %u\n", r );
1666 
1667  MsiCloseHandle( rec );
1668  MsiViewClose( view );
1669  MsiCloseHandle( view );
1670 
1671  /* insert a file into the _Streams table */
1672  create_file( "test.txt" );
1673 
1674  rec = MsiCreateRecord( 2 );
1675  MsiRecordSetStringA( rec, 1, "data" );
1676 
1677  r = MsiRecordSetStreamA( rec, 2, "test.txt" );
1678  ok( r == ERROR_SUCCESS, "Failed to add stream data to the record: %d\n", r);
1679 
1680  DeleteFileA("test.txt");
1681 
1682  r = MsiDatabaseOpenViewA( hdb,
1683  "INSERT INTO `_Streams` ( `Name`, `Data` ) VALUES ( ?, ? )", &view );
1684  ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r);
1685 
1686  r = MsiViewExecute( view, rec );
1687  ok( r == ERROR_SUCCESS, "Failed to execute view: %d\n", r);
1688 
1689  MsiCloseHandle( rec );
1690  MsiViewClose( view );
1691  MsiCloseHandle( view );
1692 
1693  /* insert another one */
1694  create_file( "test1.txt" );
1695 
1696  rec = MsiCreateRecord( 2 );
1697  MsiRecordSetStringA( rec, 1, "data1" );
1698 
1699  r = MsiRecordSetStreamA( rec, 2, "test1.txt" );
1700  ok( r == ERROR_SUCCESS, "Failed to add stream data to the record: %d\n", r);
1701 
1702  DeleteFileA("test1.txt");
1703 
1704  r = MsiDatabaseOpenViewA( hdb,
1705  "INSERT INTO `_Streams` ( `Name`, `Data` ) VALUES ( ?, ? )", &view );
1706  ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r);
1707 
1708  r = MsiViewExecute( view, rec );
1709  ok( r == ERROR_SUCCESS, "Failed to execute view: %d\n", r);
1710 
1711  MsiCloseHandle( rec );
1712  MsiViewClose( view );
1713  MsiCloseHandle( view );
1714 
1715  /* try again */
1716  create_file( "test1.txt" );
1717 
1718  rec = MsiCreateRecord( 2 );
1719  MsiRecordSetStringA( rec, 1, "data1" );
1720 
1721  r = MsiRecordSetStreamA( rec, 2, "test1.txt" );
1722  ok( r == ERROR_SUCCESS, "Failed to add stream data to the record: %d\n", r );
1723 
1724  DeleteFileA( "test1.txt" );
1725 
1726  r = MsiDatabaseOpenViewA( hdb,
1727  "INSERT INTO `_Streams` ( `Name`, `Data` ) VALUES ( ?, ? )", &view );
1728  ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r );
1729 
1730  r = MsiViewExecute( view, rec );
1731  ok( r == ERROR_FUNCTION_FAILED, "got %u\n", r );
1732 
1733  MsiCloseHandle( rec );
1734  MsiViewClose( view );
1735  MsiCloseHandle( view );
1736 
1737  r = MsiDatabaseOpenViewA( hdb,
1738  "SELECT `Name`, `Data` FROM `_Streams` WHERE `Name` = 'data'", &view );
1739  ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r);
1740 
1741  r = MsiViewExecute( view, 0 );
1742  ok( r == ERROR_SUCCESS, "Failed to execute view: %d\n", r);
1743 
1744  r = MsiViewFetch( view, &rec );
1745  ok( r == ERROR_SUCCESS, "Failed to fetch record: %d\n", r);
1746 
1747  size = MAX_PATH;
1748  r = MsiRecordGetStringA( rec, 1, file, &size );
1749  ok( r == ERROR_SUCCESS, "Failed to get string: %d\n", r);
1750  ok( !lstrcmpA(file, "data"), "Expected 'data', got %s\n", file);
1751 
1752  size = MAX_PATH;
1753  memset(buf, 0, MAX_PATH);
1754  r = MsiRecordReadStream( rec, 2, buf, &size );
1755  ok( r == ERROR_SUCCESS, "Failed to get stream: %d\n", r);
1756  ok( !lstrcmpA(buf, "test.txt\n"), "Expected 'test.txt\\n', got %s\n", buf);
1757 
1758  MsiCloseHandle( rec );
1759  MsiViewClose( view );
1760  MsiCloseHandle( view );
1761 
1762  r = MsiDatabaseOpenViewA( hdb,
1763  "SELECT `Name`, `Data` FROM `_Streams` WHERE `Name` = 'data1'", &view );
1764  ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r);
1765 
1766  r = MsiViewExecute( view, 0 );
1767  ok( r == ERROR_SUCCESS, "Failed to execute view: %d\n", r);
1768 
1769  r = MsiViewFetch( view, &rec );
1770  ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1771 
1772  size = MAX_PATH;
1773  r = MsiRecordGetStringA( rec, 1, file, &size );
1774  ok( r == ERROR_SUCCESS, "Failed to get string: %d\n", r);
1775  ok( !lstrcmpA(file, "data1"), "Expected 'data1', got %s\n", file);
1776 
1777  size = MAX_PATH;
1778  memset(buf, 0, MAX_PATH);
1779  r = MsiRecordReadStream( rec, 2, buf, &size );
1780  ok( r == ERROR_SUCCESS, "Failed to get stream: %d\n", r);
1781  ok( !lstrcmpA(buf, "test1.txt\n"), "Expected 'test1.txt\\n', got %s\n", buf);
1782 
1783  MsiCloseHandle( rec );
1784  MsiViewClose( view );
1785  MsiCloseHandle( view );
1786 
1787  /* perform an update */
1788  create_file( "test2.txt" );
1789  rec = MsiCreateRecord( 1 );
1790 
1791  r = MsiRecordSetStreamA( rec, 1, "test2.txt" );
1792  ok( r == ERROR_SUCCESS, "Failed to add stream data to the record: %d\n", r);
1793 
1794  DeleteFileA("test2.txt");
1795 
1796  r = MsiDatabaseOpenViewA( hdb,
1797  "UPDATE `_Streams` SET `Data` = ? WHERE `Name` = 'data1'", &view );
1798  ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r);
1799 
1800  r = MsiViewExecute( view, rec );
1801  ok( r == ERROR_SUCCESS, "Failed to execute view: %d\n", r);
1802 
1803  MsiCloseHandle( rec );
1804  MsiViewClose( view );
1805  MsiCloseHandle( view );
1806 
1807  r = MsiDatabaseOpenViewA( hdb,
1808  "SELECT `Name`, `Data` FROM `_Streams` WHERE `Name` = 'data1'", &view );
1809  ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r);
1810 
1811  r = MsiViewExecute( view, 0 );
1812  ok( r == ERROR_SUCCESS, "Failed to execute view: %d\n", r);
1813 
1814  r = MsiViewFetch( view, &rec );
1815  ok( r == ERROR_SUCCESS, "Failed to fetch record: %d\n", r);
1816 
1817  size = MAX_PATH;
1818  r = MsiRecordGetStringA( rec, 1, file, &size );
1819  ok( r == ERROR_SUCCESS, "Failed to get string: %d\n", r);
1820  ok( !lstrcmpA(file, "data1"), "Expected 'data1', got %s\n", file);
1821 
1822  size = MAX_PATH;
1823  memset(buf, 0, MAX_PATH);
1824  r = MsiRecordReadStream( rec, 2, buf, &size );
1825  ok( r == ERROR_SUCCESS, "Failed to get stream: %d\n", r);
1826  ok( !lstrcmpA(buf, "test2.txt\n"), "Expected 'test2.txt\\n', got %s\n", buf);
1827 
1828  MsiCloseHandle( rec );
1829  MsiViewClose( view );
1830  MsiCloseHandle( view );
1831  MsiCloseHandle( hdb );
1833 }
1834 
1835 static void test_binary(void)
1836 {
1837  MSIHANDLE hdb = 0, rec;
1838  char file[MAX_PATH];
1839  char buf[MAX_PATH];
1840  DWORD size;
1841  LPCSTR query;
1842  UINT r;
1843 
1844  /* insert a file into the Binary table */
1846  ok( r == ERROR_SUCCESS , "Failed to open database\n" );
1847 
1848  query = "CREATE TABLE `Binary` ( `Name` CHAR(72) NOT NULL, `ID` INT NOT NULL, `Data` OBJECT PRIMARY KEY `Name`, `ID`)";
1849  r = run_query( hdb, 0, query );
1850  ok( r == ERROR_SUCCESS, "Cannot create Binary table: %d\n", r );
1851 
1852  create_file( "test.txt" );
1853  rec = MsiCreateRecord( 1 );
1854  r = MsiRecordSetStreamA( rec, 1, "test.txt" );
1855  ok( r == ERROR_SUCCESS, "Failed to add stream data to the record: %d\n", r);
1856  DeleteFileA( "test.txt" );
1857 
1858  /* try a name that exceeds maximum OLE stream name length */
1859  query = "INSERT INTO `Binary` ( `Name`, `ID`, `Data` ) VALUES ( 'encryption.dll.CB4E6205_F99A_4C51_ADD4_184506EFAB87', 10000, ? )";
1860  r = run_query( hdb, rec, query );
1861  ok( r == ERROR_SUCCESS, "Insert into Binary table failed: %d\n", r );
1862 
1863  r = MsiCloseHandle( rec );
1864  ok( r == ERROR_SUCCESS , "Failed to close record handle\n" );
1865 
1866  r = MsiDatabaseCommit( hdb );
1867  ok( r == ERROR_FUNCTION_FAILED , "got %u\n", r );
1868 
1869  r = MsiCloseHandle( hdb );
1870  ok( r == ERROR_SUCCESS , "Failed to close database\n" );
1871 
1873  ok( r == ERROR_SUCCESS , "Failed to open database\n" );
1874 
1875  query = "CREATE TABLE `Binary` ( `Name` CHAR(72) NOT NULL, `ID` INT NOT NULL, `Data` OBJECT PRIMARY KEY `Name`, `ID`)";
1876  r = run_query( hdb, 0, query );
1877  ok( r == ERROR_SUCCESS, "Cannot create Binary table: %d\n", r );
1878 
1879  create_file( "test.txt" );
1880  rec = MsiCreateRecord( 1 );
1881  r = MsiRecordSetStreamA( rec, 1, "test.txt" );
1882  ok( r == ERROR_SUCCESS, "Failed to add stream data to the record: %d\n", r );
1883  DeleteFileA( "test.txt" );
1884 
1885  query = "INSERT INTO `Binary` ( `Name`, `ID`, `Data` ) VALUES ( 'filename1', 1, ? )";
1886  r = run_query( hdb, rec, query );
1887  ok( r == ERROR_SUCCESS, "Insert into Binary table failed: %d\n", r );
1888 
1889  query = "INSERT INTO `Binary` ( `Name`, `ID`, `Data` ) VALUES ( 'filename1', 1, ? )";
1890  r = run_query( hdb, rec, query );
1891  ok( r == ERROR_FUNCTION_FAILED, "got %u\n", r );
1892 
1893  r = MsiCloseHandle( rec );
1894  ok( r == ERROR_SUCCESS , "Failed to close record handle\n" );
1895 
1896  r = MsiDatabaseCommit( hdb );
1897  ok( r == ERROR_SUCCESS , "Failed to commit database\n" );
1898 
1899  r = MsiCloseHandle( hdb );
1900  ok( r == ERROR_SUCCESS , "Failed to close database\n" );
1901 
1902  /* read file from the Stream table */
1904  ok( r == ERROR_SUCCESS , "Failed to open database\n" );
1905 
1906  query = "SELECT * FROM `_Streams`";
1907  r = do_query( hdb, query, &rec );
1908  ok( r == ERROR_SUCCESS, "SELECT query failed: %d\n", r );
1909 
1910  size = MAX_PATH;
1911  r = MsiRecordGetStringA( rec, 1, file, &size );
1912  ok( r == ERROR_SUCCESS, "Failed to get string: %d\n", r );
1913  ok( !lstrcmpA(file, "Binary.filename1.1"), "Expected 'Binary.filename1.1', got %s\n", file );
1914 
1915  size = MAX_PATH;
1916  memset( buf, 0, MAX_PATH );
1917  r = MsiRecordReadStream( rec, 2, buf, &size );
1918  ok( r == ERROR_SUCCESS, "Failed to get stream: %d\n", r );
1919  ok( !lstrcmpA(buf, "test.txt\n"), "Expected 'test.txt\\n', got %s\n", buf );
1920 
1921  r = MsiCloseHandle( rec );
1922  ok( r == ERROR_SUCCESS , "Failed to close record handle\n" );
1923 
1924  /* read file from the Binary table */
1925  query = "SELECT * FROM `Binary`";
1926  r = do_query( hdb, query, &rec );
1927  ok( r == ERROR_SUCCESS, "SELECT query failed: %d\n", r );
1928 
1929  size = MAX_PATH;
1930  r = MsiRecordGetStringA( rec, 1, file, &size );
1931  ok( r == ERROR_SUCCESS, "Failed to get string: %d\n", r );
1932  ok( !lstrcmpA(file, "filename1"), "Expected 'filename1', got %s\n", file );
1933 
1934  size = MAX_PATH;
1935  memset( buf, 0, MAX_PATH );
1936  r = MsiRecordReadStream( rec, 3, buf, &size );
1937  ok( r == ERROR_SUCCESS, "Failed to get stream: %d\n", r );
1938  ok( !lstrcmpA(buf, "test.txt\n"), "Expected 'test.txt\\n', got %s\n", buf );
1939 
1940  r = MsiCloseHandle( rec );
1941  ok( r == ERROR_SUCCESS , "Failed to close record handle\n" );
1942 
1943  r = MsiCloseHandle( hdb );
1944  ok( r == ERROR_SUCCESS , "Failed to close database\n" );
1945 
1946  DeleteFileA( msifile );
1947 }
1948 
1950 {
1951  MSIHANDLE hdb = 0, rec, view;
1952  LPCSTR query;
1953  UINT r;
1954 
1955  hdb = create_db();
1956  ok( hdb, "failed to create db\n");
1957 
1958  r = run_query(hdb, 0,
1959  "CREATE TABLE `IESTable` ("
1960  "`Action` CHAR(64), "
1961  "`Condition` CHAR(64), "
1962  "`Sequence` LONG PRIMARY KEY `Sequence`)");
1963  ok( r == S_OK, "Cannot create IESTable table: %d\n", r);
1964 
1965  r = run_query(hdb, 0,
1966  "CREATE TABLE `CATable` ("
1967  "`Action` CHAR(64), "
1968  "`Type` LONG PRIMARY KEY `Type`)");
1969  ok( r == S_OK, "Cannot create CATable table: %d\n", r);
1970 
1971  r = run_query(hdb, 0, "INSERT INTO `IESTable` "
1972  "( `Action`, `Condition`, `Sequence`) "
1973  "VALUES ( 'clean', 'cond4', 4)");
1974  ok( r == S_OK, "cannot add entry to IESTable table:%d\n", r );
1975 
1976  r = run_query(hdb, 0, "INSERT INTO `IESTable` "
1977  "( `Action`, `Condition`, `Sequence`) "
1978  "VALUES ( 'depends', 'cond1', 1)");
1979  ok( r == S_OK, "cannot add entry to IESTable table:%d\n", r );
1980 
1981  r = run_query(hdb, 0, "INSERT INTO `IESTable` "
1982  "( `Action`, `Condition`, `Sequence`) "
1983  "VALUES ( 'build', 'cond2', 2)");
1984  ok( r == S_OK, "cannot add entry to IESTable table:%d\n", r );
1985 
1986  r = run_query(hdb, 0, "INSERT INTO `IESTable` "
1987  "( `Action`, `Condition`, `Sequence`) "
1988  "VALUES ( 'build2', 'cond6', 6)");
1989  ok( r == S_OK, "cannot add entry to IESTable table:%d\n", r );
1990 
1991  r = run_query(hdb, 0, "INSERT INTO `IESTable` "
1992  "( `Action`, `Condition`, `Sequence`) "
1993  "VALUES ( 'build', 'cond3', 3)");
1994  ok(r == S_OK, "cannot add entry to IESTable table:%d\n", r );
1995 
1996  r = run_query(hdb, 0, "INSERT INTO `CATable` "
1997  "( `Action`, `Type` ) "
1998  "VALUES ( 'build', 32)");
1999  ok(r == S_OK, "cannot add entry to CATable table:%d\n", r );
2000 
2001  r = run_query(hdb, 0, "INSERT INTO `CATable` "
2002  "( `Action`, `Type` ) "
2003  "VALUES ( 'depends', 64)");
2004  ok(r == S_OK, "cannot add entry to CATable table:%d\n", r );
2005 
2006  r = run_query(hdb, 0, "INSERT INTO `CATable` "
2007  "( `Action`, `Type` ) "
2008  "VALUES ( 'clean', 63)");
2009  ok(r == S_OK, "cannot add entry to CATable table:%d\n", r );
2010 
2011  r = run_query(hdb, 0, "INSERT INTO `CATable` "
2012  "( `Action`, `Type` ) "
2013  "VALUES ( 'build2', 34)");
2014  ok(r == S_OK, "cannot add entry to CATable table:%d\n", r );
2015  query = "Select IESTable.Condition from CATable, IESTable where "
2016  "CATable.Action = IESTable.Action and CATable.Type = 32";
2017  r = MsiDatabaseOpenViewA(hdb, query, &view);
2018  ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
2019 
2020  r = MsiViewExecute(view, 0);
2021  ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
2022 
2023  r = MsiViewFetch(view, &rec);
2024  ok( r == ERROR_SUCCESS, "failed to fetch view: %d\n", r );
2025 
2026  ok( check_record( rec, 1, "cond2"), "wrong condition\n");
2027 
2028  MsiCloseHandle( rec );
2029  r = MsiViewFetch(view, &rec);
2030  ok( r == ERROR_SUCCESS, "failed to fetch view: %d\n", r );
2031 
2032  ok( check_record( rec, 1, "cond3"), "wrong condition\n");
2033 
2034  MsiCloseHandle( rec );
2035  MsiViewClose(view);
2037 
2038  MsiCloseHandle( hdb );
2040 }
2041 
2042 
2043 static void test_where(void)
2044 {
2045  MSIHANDLE hdb = 0, rec, view;
2046  LPCSTR query;
2047  UINT r;
2048  DWORD size;
2049  CHAR buf[MAX_PATH];
2050  UINT count;
2051 
2052  hdb = create_db();
2053  ok( hdb, "failed to create db\n");
2054 
2055  r = run_query( hdb, 0,
2056  "CREATE TABLE `Media` ("
2057  "`DiskId` SHORT NOT NULL, "
2058  "`LastSequence` LONG, "
2059  "`DiskPrompt` CHAR(64) LOCALIZABLE, "
2060  "`Cabinet` CHAR(255), "
2061  "`VolumeLabel` CHAR(32), "
2062  "`Source` CHAR(72) "
2063  "PRIMARY KEY `DiskId`)" );
2064  ok( r == S_OK, "cannot create Media table: %d\n", r );
2065 
2066  r = run_query( hdb, 0, "INSERT INTO `Media` "
2067  "( `DiskId`, `LastSequence`, `DiskPrompt`, `Cabinet`, `VolumeLabel`, `Source` ) "
2068  "VALUES ( 1, 0, '', 'zero.cab', '', '' )" );
2069  ok( r == S_OK, "cannot add file to the Media table: %d\n", r );
2070 
2071  r = run_query( hdb, 0, "INSERT INTO `Media` "
2072  "( `DiskId`, `LastSequence`, `DiskPrompt`, `Cabinet`, `VolumeLabel`, `Source` ) "
2073  "VALUES ( 2, 1, '', 'one.cab', '', '' )" );
2074  ok( r == S_OK, "cannot add file to the Media table: %d\n", r );
2075 
2076  r = run_query( hdb, 0, "INSERT INTO `Media` "
2077  "( `DiskId`, `LastSequence`, `DiskPrompt`, `Cabinet`, `VolumeLabel`, `Source` ) "
2078  "VALUES ( 3, 2, '', 'two.cab', '', '' )" );
2079  ok( r == S_OK, "cannot add file to the Media table: %d\n", r );
2080 
2081  query = "SELECT * FROM `Media`";
2082  r = do_query(hdb, query, &rec);
2083  ok(r == ERROR_SUCCESS, "MsiViewFetch failed: %d\n", r);
2084  ok( check_record( rec, 4, "zero.cab"), "wrong cabinet\n");
2085  MsiCloseHandle( rec );
2086 
2087  query = "SELECT * FROM `Media` WHERE `LastSequence` >= 1";
2088  r = do_query(hdb, query, &rec);
2089  ok(r == ERROR_SUCCESS, "MsiViewFetch failed: %d\n", r);
2090  ok( check_record( rec, 4, "one.cab"), "wrong cabinet\n");
2091 
2092  r = MsiRecordGetInteger(rec, 1);
2093  ok( 2 == r, "field wrong\n");
2094  r = MsiRecordGetInteger(rec, 2);
2095  ok( 1 == r, "field wrong\n");
2096  MsiCloseHandle( rec );
2097 
2098  query = "SELECT `DiskId` FROM `Media` WHERE `LastSequence` >= 1 AND DiskId >= 0";
2099  r = MsiDatabaseOpenViewA(hdb, query, &view);
2100  ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
2101 
2102  r = MsiViewExecute(view, 0);
2103  ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
2104 
2105  r = MsiViewFetch(view, &rec);
2106  ok( r == ERROR_SUCCESS, "failed to fetch view: %d\n", r );
2107 
2108  count = MsiRecordGetFieldCount( rec );
2109  ok( count == 1, "Expected 1 record fields, got %d\n", count );
2110 
2111  size = MAX_PATH;
2112  r = MsiRecordGetStringA( rec, 1, buf, &size );
2113  ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
2114  ok( !lstrcmpA( buf, "2" ), "For (row %d, column 1) expected '%d', got %s\n", 0, 2, buf );
2115  MsiCloseHandle( rec );
2116 
2117  r = MsiViewFetch(view, &rec);
2118  ok( r == ERROR_SUCCESS, "failed to fetch view: %d\n", r );
2119 
2120  size = MAX_PATH;
2121  r = MsiRecordGetStringA( rec, 1, buf, &size );
2122  ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
2123  ok( !lstrcmpA( buf, "3" ), "For (row %d, column 1) expected '%d', got %s\n", 1, 3, buf );
2124  MsiCloseHandle( rec );
2125 
2126  r = MsiViewFetch(view, &rec);
2127  ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
2128 
2129  MsiViewClose(view);
2131 
2132  MsiCloseHandle( rec );
2133 
2134  rec = 0;
2135  query = "SELECT * FROM `Media` WHERE `DiskPrompt` IS NULL";
2136  r = do_query(hdb, query, &rec);
2137  ok( r == ERROR_SUCCESS, "query failed: %d\n", r );
2138  MsiCloseHandle( rec );
2139 
2140  rec = 0;
2141  query = "SELECT * FROM `Media` WHERE `DiskPrompt` < 'Cabinet'";
2142  r = do_query(hdb, query, &rec);
2143  ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %d\n", r );
2144  MsiCloseHandle( rec );
2145 
2146  rec = 0;
2147  query = "SELECT * FROM `Media` WHERE `DiskPrompt` > 'Cabinet'";
2148  r = do_query(hdb, query, &rec);
2149  ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %d\n", r );
2150  MsiCloseHandle( rec );
2151 
2152  rec = 0;
2153  query = "SELECT * FROM `Media` WHERE `DiskPrompt` <> 'Cabinet'";
2154  r = do_query(hdb, query, &rec);
2155  ok( r == ERROR_SUCCESS, "query failed: %d\n", r );
2156  MsiCloseHandle( rec );
2157 
2158  rec = 0;
2159  query = "SELECT * FROM `Media` WHERE `DiskPrompt` = 'Cabinet'";
2160  r = do_query(hdb, query, &rec);
2161  ok( r == ERROR_NO_MORE_ITEMS, "query failed: %d\n", r );
2162  MsiCloseHandle( rec );
2163 
2164  rec = MsiCreateRecord(1);
2165  MsiRecordSetStringA(rec, 1, "");
2166 
2167  query = "SELECT * FROM `Media` WHERE `DiskPrompt` = ?";
2168  r = MsiDatabaseOpenViewA(hdb, query, &view);
2169  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2170  r = MsiViewExecute(view, rec);
2171  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2172 
2173  MsiCloseHandle(rec);
2174 
2175  r = MsiViewFetch(view, &rec);
2176  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2177 
2178  MsiCloseHandle(rec);
2179  MsiViewClose(view);
2181 
2182  MsiCloseHandle( hdb );
2184 }
2185 
2187 
2188 static const CHAR test_data[] = "FirstPrimaryColumn\tSecondPrimaryColumn\tShortInt\tShortIntNullable\tLongInt\tLongIntNullable\tString\tLocalizableString\tLocalizableStringNullable\n"
2189  "s255\ti2\ti2\tI2\ti4\tI4\tS255\tS0\ts0\n"
2190  "TestTable\tFirstPrimaryColumn\n"
2191  "stringage\t5\t2\t\t2147483640\t-2147483640\tanother string\tlocalizable\tduh\n";
2192 
2193 static const CHAR two_primary[] = "PrimaryOne\tPrimaryTwo\n"
2194  "s255\ts255\n"
2195  "TwoPrimary\tPrimaryOne\tPrimaryTwo\n"
2196  "papaya\tleaf\n"
2197  "papaya\tflower\n";
2198 
2199 static const CHAR endlines1[] = "A\tB\tC\tD\tE\tF\r\n"
2200  "s72\ts72\ts72\ts72\ts72\ts72\n"
2201  "Table\tA\r\n"
2202  "a\tb\tc\td\te\tf\n"
2203  "g\th\ti\t\rj\tk\tl\r\n";
2204 
2205 static const CHAR endlines2[] = "A\tB\tC\tD\tE\tF\r"
2206  "s72\ts72\ts72\ts72\ts72\ts72\n"
2207  "Table2\tA\r\n"
2208  "a\tb\tc\td\te\tf\n"
2209  "g\th\ti\tj\tk\tl\r\n";
2210 
2211 static const CHAR suminfo[] = "PropertyId\tValue\n"
2212  "i2\tl255\n"
2213  "_SummaryInformation\tPropertyId\n"
2214  "1\t1252\n"
2215  "2\tInstaller Database\n"
2216  "3\tInstaller description\n"
2217  "4\tWineHQ\n"
2218  "5\tInstaller\n"
2219  "6\tInstaller comments\n"
2220  "7\tIntel;1033,2057\n"
2221  "9\t{12345678-1234-1234-1234-123456789012}\n"
2222  "12\t2009/04/12 15:46:11\n"
2223  "13\t2009/04/12 15:46:11\n"
2224  "14\t200\n"
2225  "15\t2\n"
2226  "18\tVim\n"
2227  "19\t2\n";
2228 
2229 static void write_file(const CHAR *filename, const char *data, int data_size)
2230 {
2231  DWORD size;
2232 
2235  WriteFile(hf, data, data_size, &size, NULL);
2236  CloseHandle(hf);
2237 }
2238 
2240 {
2241  UINT r;
2242 
2243  write_file("temp_file", table_data, (lstrlenA(table_data) - 1) * sizeof(char));
2244  r = MsiDatabaseImportA(hdb, CURR_DIR, "temp_file");
2245  DeleteFileA("temp_file");
2246 
2247  return r;
2248 }
2249 
2250 static void test_suminfo_import(void)
2251 {
2252  MSIHANDLE hdb, hsi, view = 0;
2253  LPCSTR query;
2254  UINT r, count, size, type;
2255  char str_value[50];
2256  INT int_value;
2257  FILETIME ft_value;
2258 
2260 
2262  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2263 
2264  r = add_table_to_db(hdb, suminfo);
2265  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2266 
2267  /* _SummaryInformation is not imported as a regular table... */
2268 
2269  query = "SELECT * FROM `_SummaryInformation`";
2270  r = MsiDatabaseOpenViewA(hdb, query, &view);
2271  ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %u\n", r);
2273 
2274  /* ...its data is added to the special summary information stream */
2275 
2276  r = MsiGetSummaryInformationA(hdb, NULL, 0, &hsi);
2277  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2278 
2280  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2281  ok(count == 14, "Expected 14, got %u\n", count);
2282 
2283  r = MsiSummaryInfoGetPropertyA(hsi, PID_CODEPAGE, &type, &int_value, NULL, NULL, NULL);
2284  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2285  ok(type == VT_I2, "Expected VT_I2, got %u\n", type);
2286  ok(int_value == 1252, "Expected 1252, got %d\n", int_value);
2287 
2288  size = sizeof(str_value);
2289  r = MsiSummaryInfoGetPropertyA(hsi, PID_TITLE, &type, NULL, NULL, str_value, &size);
2290  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2291  ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
2292  ok(size == 18, "Expected 18, got %u\n", size);
2293  ok(!strcmp(str_value, "Installer Database"),
2294  "Expected \"Installer Database\", got %s\n", str_value);
2295 
2296  size = sizeof(str_value);
2297  r = MsiSummaryInfoGetPropertyA(hsi, PID_SUBJECT, &type, NULL, NULL, str_value, &size);
2298  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2299  ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
2300  ok(!strcmp(str_value, "Installer description"),
2301  "Expected \"Installer description\", got %s\n", str_value);
2302 
2303  size = sizeof(str_value);
2304  r = MsiSummaryInfoGetPropertyA(hsi, PID_AUTHOR, &type, NULL, NULL, str_value, &size);
2305  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2306  ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
2307  ok(!strcmp(str_value, "WineHQ"),
2308  "Expected \"WineHQ\", got %s\n", str_value);
2309 
2310  size = sizeof(str_value);
2311  r = MsiSummaryInfoGetPropertyA(hsi, PID_KEYWORDS, &type, NULL, NULL, str_value, &size);
2312  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2313  ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
2314  ok(!strcmp(str_value, "Installer"),
2315  "Expected \"Installer\", got %s\n", str_value);
2316 
2317  size = sizeof(str_value);
2318  r = MsiSummaryInfoGetPropertyA(hsi, PID_COMMENTS, &type, NULL, NULL, str_value, &size);
2319  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2320  ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
2321  ok(!strcmp(str_value, "Installer comments"),
2322  "Expected \"Installer comments\", got %s\n", str_value);
2323 
2324  size = sizeof(str_value);
2325  r = MsiSummaryInfoGetPropertyA(hsi, PID_TEMPLATE, &type, NULL, NULL, str_value, &size);
2326  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2327  ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
2328  ok(!strcmp(str_value, "Intel;1033,2057"),
2329  "Expected \"Intel;1033,2057\", got %s\n", str_value);
2330 
2331  size = sizeof(str_value);
2332  r = MsiSummaryInfoGetPropertyA(hsi, PID_REVNUMBER, &type, NULL, NULL, str_value, &size);
2333  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2334  ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
2335  ok(!strcmp(str_value, "{12345678-1234-1234-1234-123456789012}"),
2336  "Expected \"{12345678-1234-1234-1234-123456789012}\", got %s\n", str_value);
2337 
2338  r = MsiSummaryInfoGetPropertyA(hsi, PID_CREATE_DTM, &type, NULL, &ft_value, NULL, NULL);
2339  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2340  ok(type == VT_FILETIME, "Expected VT_FILETIME, got %u\n", type);
2341 
2343  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2344  ok(type == VT_FILETIME, "Expected VT_FILETIME, got %u\n", type);
2345 
2346  r = MsiSummaryInfoGetPropertyA(hsi, PID_PAGECOUNT, &type, &int_value, NULL, NULL, NULL);
2347  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2348  ok(type == VT_I4, "Expected VT_I4, got %u\n", type);
2349  ok(int_value == 200, "Expected 200, got %d\n", int_value);
2350 
2351  r = MsiSummaryInfoGetPropertyA(hsi, PID_WORDCOUNT, &type, &int_value, NULL, NULL, NULL);
2352  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2353  ok(type == VT_I4, "Expected VT_I4, got %u\n", type);
2354  ok(int_value == 2, "Expected 2, got %d\n", int_value);
2355 
2356  r = MsiSummaryInfoGetPropertyA(hsi, PID_SECURITY, &type, &int_value, NULL, NULL, NULL);
2357  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2358  ok(type == VT_I4, "Expected VT_I4, got %u\n", type);
2359  ok(int_value == 2, "Expected 2, got %d\n", int_value);
2360 
2361  size = sizeof(str_value);
2362  r = MsiSummaryInfoGetPropertyA(hsi, PID_APPNAME, &type, NULL, NULL, str_value, &size);
2363  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
2364  ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type);
2365  ok(!strcmp(str_value, "Vim"), "Expected \"Vim\", got %s\n", str_value);
2366 
2367  MsiCloseHandle(hsi);
2368  MsiCloseHandle(hdb);
2370 }
2371 
2372 static void test_msiimport(void)
2373 {
2374  MSIHANDLE hdb, view, rec;
2375  LPCSTR query;
2376  UINT r, count;
2377  signed int i;
2378 
2380 
2382  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2383 
2384  r = MsiDatabaseImportA(hdb, CURR_DIR, NULL);
2385  ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r);
2386 
2387  r = MsiDatabaseImportA(hdb, CURR_DIR, "nonexistent");
2388  ok(r == ERROR_FUNCTION_FAILED, "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
2389 
2390  r = add_table_to_db(hdb, test_data);
2391  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2392 
2393  r = add_table_to_db(hdb, two_primary);
2394  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2395 
2396  r = add_table_to_db(hdb, endlines1);
2397  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2398 
2399  r = add_table_to_db(hdb, endlines2);
2400  ok(r == ERROR_FUNCTION_FAILED, "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
2401 
2402  query = "SELECT * FROM `TestTable`";
2403  r = MsiDatabaseOpenViewA(hdb, query, &view);
2404  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2405 
2407  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2409  ok(count == 9, "Expected 9, got %d\n", count);
2410  ok(check_record(rec, 1, "FirstPrimaryColumn"), "Expected FirstPrimaryColumn\n");
2411  ok(check_record(rec, 2, "SecondPrimaryColumn"), "Expected SecondPrimaryColumn\n");
2412  ok(check_record(rec, 3, "ShortInt"), "Expected ShortInt\n");
2413  ok(check_record(rec, 4, "ShortIntNullable"), "Expected ShortIntNullalble\n");
2414  ok(check_record(rec, 5, "LongInt"), "Expected LongInt\n");
2415  ok(check_record(rec, 6, "LongIntNullable"), "Expected LongIntNullalble\n");
2416  ok(check_record(rec, 7, "String"), "Expected String\n");
2417  ok(check_record(rec, 8, "LocalizableString"), "Expected LocalizableString\n");
2418  ok(check_record(rec, 9, "LocalizableStringNullable"), "Expected LocalizableStringNullable\n");
2419  MsiCloseHandle(rec);
2420 
2422  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2424  ok(count == 9, "Expected 9, got %d\n", count);
2425  ok(check_record(rec, 1, "s255"), "Expected s255\n");
2426  ok(check_record(rec, 2, "i2"), "Expected i2\n");
2427  ok(check_record(rec, 3, "i2"), "Expected i2\n");
2428  ok(check_record(rec, 4, "I2"), "Expected I2\n");
2429  ok(check_record(rec, 5, "i4"), "Expected i4\n");
2430  ok(check_record(rec, 6, "I4"), "Expected I4\n");
2431  ok(check_record(rec, 7, "S255"), "Expected S255\n");
2432  ok(check_record(rec, 8, "S0"), "Expected S0\n");
2433  ok(check_record(rec, 9, "s0"), "Expected s0\n");
2434  MsiCloseHandle(rec);
2435 
2436  query = "SELECT * FROM `TestTable`";
2437  r = do_query(hdb, query, &rec);
2438  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2439  ok(check_record(rec, 1, "stringage"), "Expected 'stringage'\n");
2440  ok(check_record(rec, 7, "another string"), "Expected 'another string'\n");
2441  ok(check_record(rec, 8, "localizable"), "Expected 'localizable'\n");
2442  ok(check_record(rec, 9, "duh"), "Expected 'duh'\n");
2443 
2444  i = MsiRecordGetInteger(rec, 2);
2445  ok(i == 5, "Expected 5, got %d\n", i);
2446 
2447  i = MsiRecordGetInteger(rec, 3);
2448  ok(i == 2, "Expected 2, got %d\n", i);
2449 
2450  i = MsiRecordGetInteger(rec, 4);
2451  ok(i == MSI_NULL_INTEGER, "Expected MSI_NULL_INTEGER, got %d\n", i);
2452 
2453  i = MsiRecordGetInteger(rec, 5);
2454  ok(i == 2147483640, "Expected 2147483640, got %d\n", i);
2455 
2456  i = MsiRecordGetInteger(rec, 6);
2457  ok(i == -2147483640, "Expected -2147483640, got %d\n", i);
2458 
2459  MsiCloseHandle(rec);
2460  MsiViewClose(view);
2462 
2463  query = "SELECT * FROM `TwoPrimary`";
2464  r = MsiDatabaseOpenViewA(hdb, query, &view);
2465  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2466 
2468  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2470  ok(count == 2, "Expected 2, got %d\n", count);
2471  ok(check_record(rec, 1, "PrimaryOne"), "Expected PrimaryOne\n");
2472  ok(check_record(rec, 2, "PrimaryTwo"), "Expected PrimaryTwo\n");
2473 
2474  MsiCloseHandle(rec);
2475 
2477  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2479  ok(count == 2, "Expected 2, got %d\n", count);
2480  ok(check_record(rec, 1, "s255"), "Expected s255\n");
2481  ok(check_record(rec, 2, "s255"), "Expected s255\n");
2482  MsiCloseHandle(rec);
2483 
2484  r = MsiViewExecute(view, 0);
2485  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2486 
2487  r = MsiViewFetch(view, &rec);
2488  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2489 
2490  ok(check_record(rec, 1, "papaya"), "Expected 'papaya'\n");
2491  ok(check_record(rec, 2, "leaf"), "Expected 'leaf'\n");
2492 
2493  MsiCloseHandle(rec);
2494 
2495  r = MsiViewFetch(view, &rec);
2496  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2497 
2498  ok(check_record(rec, 1, "papaya"), "Expected 'papaya'\n");
2499  ok(check_record(rec, 2, "flower"), "Expected 'flower'\n");
2500 
2501  MsiCloseHandle(rec);
2502 
2503  r = MsiViewFetch(view, &rec);
2505  "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
2506 
2507  r = MsiViewClose(view);
2508  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2509 
2511 
2512  query = "SELECT * FROM `Table`";
2513  r = MsiDatabaseOpenViewA(hdb, query, &view);
2514  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2515 
2517  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2519  ok(count == 6, "Expected 6, got %d\n", count);
2520  ok(check_record(rec, 1, "A"), "Expected A\n");
2521  ok(check_record(rec, 2, "B"), "Expected B\n");
2522  ok(check_record(rec, 3, "C"), "Expected C\n");
2523  ok(check_record(rec, 4, "D"), "Expected D\n");
2524  ok(check_record(rec, 5, "E"), "Expected E\n");
2525  ok(check_record(rec, 6, "F"), "Expected F\n");
2526  MsiCloseHandle(rec);
2527 
2529  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2531  ok(count == 6, "Expected 6, got %d\n", count);
2532  ok(check_record(rec, 1, "s72"), "Expected s72\n");
2533  ok(check_record(rec, 2, "s72"), "Expected s72\n");
2534  ok(check_record(rec, 3, "s72"), "Expected s72\n");
2535  ok(check_record(rec, 4, "s72"), "Expected s72\n");
2536  ok(check_record(rec, 5, "s72"), "Expected s72\n");
2537  ok(check_record(rec, 6, "s72"), "Expected s72\n");
2538  MsiCloseHandle(rec);
2539 
2540  MsiViewClose(view);
2542 
2543  query = "SELECT * FROM `Table`";
2544  r = MsiDatabaseOpenViewA(hdb, query, &view);
2545  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2546 
2547  r = MsiViewExecute(view, 0);
2548  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2549 
2550  r = MsiViewFetch(view, &rec);
2551  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2552  ok(check_record(rec, 1, "a"), "Expected 'a'\n");
2553  ok(check_record(rec, 2, "b"), "Expected 'b'\n");
2554  ok(check_record(rec, 3, "c"), "Expected 'c'\n");
2555  ok(check_record(rec, 4, "d"), "Expected 'd'\n");
2556  ok(check_record(rec, 5, "e"), "Expected 'e'\n");
2557  ok(check_record(rec, 6, "f"), "Expected 'f'\n");
2558 
2559  MsiCloseHandle(rec);
2560 
2561  r = MsiViewFetch(view, &rec);
2562  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2563  ok(check_record(rec, 1, "g"), "Expected 'g'\n");
2564  ok(check_record(rec, 2, "h"), "Expected 'h'\n");
2565  ok(check_record(rec, 3, "i"), "Expected 'i'\n");
2566  ok(check_record(rec, 4, "j"), "Expected 'j'\n");
2567  ok(check_record(rec, 5, "k"), "Expected 'k'\n");
2568  ok(check_record(rec, 6, "l"), "Expected 'l'\n");
2569 
2570  MsiCloseHandle(rec);
2571 
2572  r = MsiViewFetch(view, &rec);
2574  "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
2575 
2576  MsiViewClose(view);
2578  MsiCloseHandle(hdb);
2580 }
2581 
2582 static const CHAR bin_import_dat[] = "Name\tData\r\n"
2583  "s72\tV0\r\n"
2584  "Binary\tName\r\n"
2585  "filename1\tfilename1.ibd\r\n";
2586 
2587 static void test_binary_import(void)
2588 {
2589  MSIHANDLE hdb = 0, rec;
2590  char file[MAX_PATH];
2591  char buf[MAX_PATH];
2592  char path[MAX_PATH];
2593  DWORD size;
2594  LPCSTR query;
2595  UINT r;
2596 
2597  /* create files to import */
2598  write_file("bin_import.idt", bin_import_dat,
2599  (sizeof(bin_import_dat) - 1) * sizeof(char));
2600  CreateDirectoryA("bin_import", NULL);
2601  create_file_data("bin_import/filename1.ibd", "just some words", 15);
2602 
2603  /* import files into database */
2605  ok( r == ERROR_SUCCESS , "Failed to open database\n");
2606 
2608  r = MsiDatabaseImportA(hdb, path, "bin_import.idt");
2609  ok(r == ERROR_SUCCESS , "Failed to import Binary table\n");
2610 
2611  /* read file from the Binary table */
2612  query = "SELECT * FROM `Binary`";
2613  r = do_query(hdb, query, &rec);
2614  ok(r == ERROR_SUCCESS, "SELECT query failed: %d\n", r);
2615 
2616  size = MAX_PATH;
2617  r = MsiRecordGetStringA(rec, 1, file, &size);
2618  ok(r == ERROR_SUCCESS, "Failed to get string: %d\n", r);
2619  ok(!lstrcmpA(file, "filename1"), "Expected 'filename1', got %s\n", file);
2620 
2621  size = MAX_PATH;
2622  memset(buf, 0, MAX_PATH);
2623  r = MsiRecordReadStream(rec, 2, buf, &size);
2624  ok(r == ERROR_SUCCESS, "Failed to get stream: %d\n", r);
2625  ok(!lstrcmpA(buf, "just some words"), "Expected 'just some words', got %s\n", buf);
2626 
2627  r = MsiCloseHandle(rec);
2628  ok(r == ERROR_SUCCESS , "Failed to close record handle\n");
2629 
2630  r = MsiCloseHandle(hdb);
2631  ok(r == ERROR_SUCCESS , "Failed to close database\n");
2632 
2633  DeleteFileA("bin_import/filename1.ibd");
2634  RemoveDirectoryA("bin_import");
2635  DeleteFileA("bin_import.idt");
2636 }
2637 
2638 static void test_markers(void)
2639 {
2640  MSIHANDLE hdb, rec;
2641  LPCSTR query;
2642  UINT r;
2643 
2644  hdb = create_db();
2645  ok( hdb, "failed to create db\n");
2646 
2647  rec = MsiCreateRecord(3);
2648  MsiRecordSetStringA(rec, 1, "Table");
2649  MsiRecordSetStringA(rec, 2, "Apples");
2650  MsiRecordSetStringA(rec, 3, "Oranges");
2651 
2652  /* try a legit create */
2653  query = "CREATE TABLE `Table` ( `One` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`)";
2654  r = run_query(hdb, 0, query);
2655  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2656  MsiCloseHandle(rec);
2657 
2658  /* try table name as marker */
2659  rec = MsiCreateRecord(1);
2660  MsiRecordSetStringA(rec, 1, "Fable");
2661  query = "CREATE TABLE `?` ( `One` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`)";
2662  r = run_query(hdb, rec, query);
2663  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2664 
2665  /* verify that we just created a table called '?', not 'Fable' */
2666  r = try_query(hdb, "SELECT * from `Fable`");
2667  ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2668 
2669  r = try_query(hdb, "SELECT * from `?`");
2670  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2671 
2672  /* try table name as marker without backticks */
2673  MsiRecordSetStringA(rec, 1, "Mable");
2674  query = "CREATE TABLE ? ( `One` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`)";
2675  r = run_query(hdb, rec, query);
2676  ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2677 
2678  /* try one column name as marker */
2679  MsiRecordSetStringA(rec, 1, "One");
2680  query = "CREATE TABLE `Mable` ( `?` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`)";
2681  r = run_query(hdb, rec, query);
2682  ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2683  MsiCloseHandle(rec);
2684 
2685  /* try column names as markers */
2686  rec = MsiCreateRecord(2);
2687  MsiRecordSetStringA(rec, 1, "One");
2688  MsiRecordSetStringA(rec, 2, "Two");
2689  query = "CREATE TABLE `Mable` ( `?` SHORT NOT NULL, `?` CHAR(255) PRIMARY KEY `One`)";
2690  r = run_query(hdb, rec, query);
2691  ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2692  MsiCloseHandle(rec);
2693 
2694  /* try names with backticks */
2695  rec = MsiCreateRecord(3);
2696  MsiRecordSetStringA(rec, 1, "One");
2697  MsiRecordSetStringA(rec, 2, "Two");
2698  MsiRecordSetStringA(rec, 3, "One");
2699  query = "CREATE TABLE `Mable` ( `?` SHORT NOT NULL, `?` CHAR(255) PRIMARY KEY `?`)";
2700  r = run_query(hdb, rec, query);
2701  ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2702 
2703  /* try names with backticks, minus definitions */
2704  query = "CREATE TABLE `Mable` ( `?`, `?` PRIMARY KEY `?`)";
2705  r = run_query(hdb, rec, query);
2706  ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2707 
2708  /* try names without backticks */
2709  query = "CREATE TABLE `Mable` ( ? SHORT NOT NULL, ? CHAR(255) PRIMARY KEY ?)";
2710  r = run_query(hdb, rec, query);
2711  ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2712  MsiCloseHandle(rec);
2713 
2714  /* try one long marker */
2715  rec = MsiCreateRecord(1);
2716  MsiRecordSetStringA(rec, 1, "`One` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`");
2717  query = "CREATE TABLE `Mable` ( ? )";
2718  r = run_query(hdb, rec, query);
2719  ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2720  MsiCloseHandle(rec);
2721 
2722  /* try all names as markers */
2723  rec = MsiCreateRecord(4);
2724  MsiRecordSetStringA(rec, 1, "Mable");
2725  MsiRecordSetStringA(rec, 2, "One");
2726  MsiRecordSetStringA(rec, 3, "Two");
2727  MsiRecordSetStringA(rec, 4, "One");
2728  query = "CREATE TABLE `?` ( `?` SHORT NOT NULL, `?` CHAR(255) PRIMARY KEY `?`)";
2729  r = run_query(hdb, rec, query);
2730  ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2731  MsiCloseHandle(rec);
2732 
2733  /* try a legit insert */
2734  query = "INSERT INTO `Table` ( `One`, `Two` ) VALUES ( 5, 'hello' )";
2735  r = run_query(hdb, 0, query);
2736  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2737 
2738  r = try_query(hdb, "SELECT * from `Table`");
2739  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2740 
2741  /* try values as markers */
2742  rec = MsiCreateRecord(2);
2743  MsiRecordSetInteger(rec, 1, 4);
2744  MsiRecordSetStringA(rec, 2, "hi");
2745  query = "INSERT INTO `Table` ( `One`, `Two` ) VALUES ( ?, '?' )";
2746  r = run_query(hdb, rec, query);
2747  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2748  MsiCloseHandle(rec);
2749 
2750  /* try column names and values as markers */
2751  rec = MsiCreateRecord(4);
2752  MsiRecordSetStringA(rec, 1, "One");
2753  MsiRecordSetStringA(rec, 2, "Two");
2754  MsiRecordSetInteger(rec, 3, 5);
2755  MsiRecordSetStringA(rec, 4, "hi");
2756  query = "INSERT INTO `Table` ( `?`, `?` ) VALUES ( ?, '?' )";
2757  r = run_query(hdb, rec, query);
2758  ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2759  MsiCloseHandle(rec);
2760 
2761  /* try column names as markers */
2762  rec = MsiCreateRecord(2);
2763  MsiRecordSetStringA(rec, 1, "One");
2764  MsiRecordSetStringA(rec, 2, "Two");
2765  query = "INSERT INTO `Table` ( `?`, `?` ) VALUES ( 3, 'yellow' )";
2766  r = run_query(hdb, rec, query);
2767  ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2768  MsiCloseHandle(rec);
2769 
2770  /* try table name as a marker */
2771  rec = MsiCreateRecord(1);
2772  MsiRecordSetStringA(rec, 1, "Table");
2773  query = "INSERT INTO `?` ( `One`, `Two` ) VALUES ( 2, 'green' )";
2774  r = run_query(hdb, rec, query);
2775  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2776  MsiCloseHandle(rec);
2777 
2778  /* try table name and values as markers */
2779  rec = MsiCreateRecord(3);
2780  MsiRecordSetStringA(rec, 1, "Table");
2781  MsiRecordSetInteger(rec, 2, 10);
2782  MsiRecordSetStringA(rec, 3, "haha");
2783  query = "INSERT INTO `?` ( `One`, `Two` ) VALUES ( ?, '?' )";
2784  r = run_query(hdb, rec, query);
2785  ok(r == ERROR_FUNCTION_FAILED, "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
2786  MsiCloseHandle(rec);
2787 
2788  /* try all markers */
2789  rec = MsiCreateRecord(5);
2790  MsiRecordSetStringA(rec, 1, "Table");
2791  MsiRecordSetStringA(rec, 1, "One");
2792  MsiRecordSetStringA(rec, 1, "Two");
2793  MsiRecordSetInteger(rec, 2, 10);
2794  MsiRecordSetStringA(rec, 3, "haha");
2795  query = "INSERT INTO `?` ( `?`, `?` ) VALUES ( ?, '?' )";
2796  r = run_query(hdb, rec, query);
2797  ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
2798  MsiCloseHandle(rec);
2799 
2800  /* insert an integer as a string */
2801  rec = MsiCreateRecord(2);
2802  MsiRecordSetStringA(rec, 1, "11");
2803  MsiRecordSetStringA(rec, 2, "hi");
2804  query = "INSERT INTO `Table` ( `One`, `Two` ) VALUES ( ?, '?' )";
2805  r = run_query(hdb, rec, query);
2806  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2807  MsiCloseHandle(rec);
2808 
2809  /* leave off the '' for the string */
2810  rec = MsiCreateRecord(2);
2811  MsiRecordSetInteger(rec, 1, 12);
2812  MsiRecordSetStringA(rec, 2, "hi");
2813  query = "INSERT INTO `Table` ( `One`, `Two` ) VALUES ( ?, ? )";
2814  r = run_query(hdb, rec, query);
2815  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
2816  MsiCloseHandle(rec);
2817 
2818  MsiCloseHandle(hdb);
2820 }
2821 
2822 #define MY_NVIEWS 4000 /* Largest installer I've seen uses < 2000 */
2823 static void test_handle_limit(void)
2824 {
2825  int i;
2826  MSIHANDLE hdb;
2827  MSIHANDLE hviews[MY_NVIEWS];
2828  UINT r;
2829 
2830  /* create an empty db */
2831  hdb = create_db();
2832  ok( hdb, "failed to create db\n");
2833 
2834  memset(hviews, 0, sizeof(hviews));
2835 
2836  for (i=0; i<MY_NVIEWS; i++) {
2837  static char szQueryBuf[256] = "SELECT * from `_Tables`";
2838  hviews[i] = 0xdeadbeeb;
2839  r = MsiDatabaseOpenViewA(hdb, szQueryBuf, &hviews[i]);
2840  if( r != ERROR_SUCCESS || hviews[i] == 0xdeadbeeb ||
2841  hviews[i] == 0 || (i && (hviews[i] == hviews[i-1])))
2842  break;
2843  }
2844 
2845  ok( i == MY_NVIEWS, "problem opening views\n");
2846 
2847  for (i=0; i<MY_NVIEWS; i++) {
2848  if (hviews[i] != 0 && hviews[i] != 0xdeadbeeb) {
2849  MsiViewClose(hviews[i]);
2850  r = MsiCloseHandle(hviews[i]);
2851  if (r != ERROR_SUCCESS)
2852  break;
2853  }
2854  }
2855 
2856  ok( i == MY_NVIEWS, "problem closing views\n");
2857 
2858  r = MsiCloseHandle(hdb);
2859  ok( r == ERROR_SUCCESS, "failed to close database\n");
2860 }
2861 
2862 static void generate_transform(void)
2863 {
2864  MSIHANDLE hdb1, hdb2, hrec;
2865  LPCSTR query;
2866  UINT r;
2867 
2868  /* start with two identical databases */
2870 
2872  ok( r == ERROR_SUCCESS , "Failed to create database\n" );
2873 
2874  r = MsiDatabaseCommit( hdb1 );
2875  ok( r == ERROR_SUCCESS , "Failed to commit database\n" );
2876 
2878  ok( r == ERROR_SUCCESS , "Failed to create database\n" );
2879 
2880  /* the transform between two identical database should be empty */
2881  r = MsiDatabaseGenerateTransformA(hdb1, hdb2, NULL, 0, 0);
2882  todo_wine {
2883  ok( r == ERROR_NO_DATA, "return code %d, should be ERROR_NO_DATA\n", r );
2884  }
2885 
2886  query = "CREATE TABLE `AAR` ( `BAR` SHORT NOT NULL, `CAR` CHAR(255) PRIMARY KEY `CAR`)";
2887  r = run_query(hdb1, 0, query);
2888  ok(r == ERROR_SUCCESS, "failed to add table\n");
2889 
2890  query = "INSERT INTO `AAR` ( `BAR`, `CAR` ) VALUES ( 1, 'vw' )";
2891  r = run_query(hdb1, 0, query);
2892  ok(r == ERROR_SUCCESS, "failed to add row 1\n");
2893 
2894  query = "INSERT INTO `AAR` ( `BAR`, `CAR` ) VALUES ( 2, 'bmw' )";
2895  r = run_query(hdb1, 0, query);
2896  ok(r == ERROR_SUCCESS, "failed to add row 2\n");
2897 
2898  query = "UPDATE `MOO` SET `OOO` = 'c' WHERE `NOO` = 1";
2899  r = run_query(hdb1, 0, query);
2900  ok(r == ERROR_SUCCESS, "failed to modify row\n");
2901 
2902  query = "DELETE FROM `MOO` WHERE `NOO` = 3";
2903  r = run_query(hdb1, 0, query);
2904  ok(r == ERROR_SUCCESS, "failed to delete row\n");
2905 
2906  hrec = MsiCreateRecord(2);
2907  r = MsiRecordSetInteger(hrec, 1, 1);
2908  ok(r == ERROR_SUCCESS, "failed to set integer\n");
2909 
2910  write_file("testdata.bin", "naengmyon", 9);
2911  r = MsiRecordSetStreamA(hrec, 2, "testdata.bin");
2912  ok(r == ERROR_SUCCESS, "failed to set stream\n");
2913 
2914  query = "INSERT INTO `BINARY` ( `ID`, `BLOB` ) VALUES ( ?, ? )";
2915  r = run_query(hdb1, hrec, query);
2916  ok(r == ERROR_SUCCESS, "failed to add row with blob\n");
2917 
2918  MsiCloseHandle(hrec);
2919 
2920  query = "ALTER TABLE `MOO` ADD `COW` INTEGER";
2921  r = run_query(hdb1, 0, query);
2922  ok(r == ERROR_SUCCESS, "failed to add column\n");
2923 
2924  query = "ALTER TABLE `MOO` ADD `PIG` INTEGER";
2925  r = run_query(hdb1, 0, query);
2926  ok(r == ERROR_SUCCESS, "failed to add column\n");
2927 
2928  query = "UPDATE `MOO` SET `PIG` = 5 WHERE `NOO` = 1";
2929  r = run_query(hdb1, 0, query);
2930  ok(r == ERROR_SUCCESS, "failed to modify row\n");
2931 
2932  query = "CREATE TABLE `Property` ( `Property` CHAR(72) NOT NULL, "
2933  "`Value` CHAR(0) PRIMARY KEY `Property`)";
2934  r = run_query(hdb1, 0, query);
2935  ok(r == ERROR_SUCCESS, "failed to add property table\n");
2936 
2937  query = "INSERT INTO `Property` ( `Property`, `Value` ) VALUES ( 'prop', 'val' )";
2938  r = run_query(hdb1, 0, query);
2939  ok(r == ERROR_SUCCESS, "failed to add property\n");
2940 
2941  /* database needs to be committed */
2942  MsiDatabaseCommit(hdb1);
2943 
2944  r = MsiDatabaseGenerateTransformA(hdb1, hdb2, mstfile, 0, 0);
2945  ok( r == ERROR_SUCCESS, "return code %d, should be ERROR_SUCCESS\n", r );
2946 
2947  MsiCloseHandle( hdb1 );
2948  MsiCloseHandle( hdb2 );
2949 
2950  DeleteFileA("testdata.bin");
2951 }
2952 
2953 /* data for generating a transform */
2954 
2955 /* tables transform names - encoded as they would be in an msi database file */
2956 static const WCHAR name1[] = { 0x4840, 0x3a8a, 0x481b, 0 }; /* AAR */
2957 static const WCHAR name2[] = { 0x4840, 0x3b3f, 0x43f2, 0x4438, 0x45b1, 0 }; /* _Columns */
2958 static const WCHAR name3[] = { 0x4840, 0x3f7f, 0x4164, 0x422f, 0x4836, 0 }; /* _Tables */
2959 static const WCHAR name4[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0 }; /* _StringData */
2960 static const WCHAR name5[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0 }; /* _StringPool */
2961 static const WCHAR name6[] = { 0x4840, 0x3e16, 0x4818, 0}; /* MOO */
2962 static const WCHAR name7[] = { 0x4840, 0x3c8b, 0x3a97, 0x409b, 0 }; /* BINARY */
2963 static const WCHAR name8[] = { 0x3c8b, 0x3a97, 0x409b, 0x387e, 0 }; /* BINARY.1 */
2964 static const WCHAR name9[] = { 0x4840, 0x4559, 0x44f2, 0x4568, 0x4737, 0 }; /* Property */
2965 
2966 /* data in each table */
2967 static const WCHAR data1[] = { /* AAR */
2968  0x0201, 0x0008, 0x8001, /* 0x0201 = add row (1), two shorts */
2969  0x0201, 0x0009, 0x8002,
2970 };
2971 static const WCHAR data2[] = { /* _Columns */
2972  0x0401, 0x0001, 0x8003, 0x0002, 0x9502,
2973  0x0401, 0x0001, 0x8004, 0x0003, 0x9502,
2974  0x0401, 0x0005, 0x0000, 0x0006, 0xbdff, /* 0x0401 = add row (1), 4 shorts */
2975  0x0401, 0x0005, 0x0000, 0x0007, 0x8502,
2976  0x0401, 0x000a, 0x0000, 0x000a, 0xad48,
2977  0x0401, 0x000a, 0x0000, 0x000b, 0x9d00,
2978 };
2979 static const WCHAR data3[] = { /* _Tables */
2980  0x0101, 0x0005, /* 0x0101 = add row (1), 1 short */
2981  0x0101, 0x000a,
2982 };
2983 static const char data4[] = /* _StringData */
2984  "MOOCOWPIGcAARCARBARvwbmwPropertyValuepropval"; /* all the strings squashed together */
2985 static const WCHAR data5[] = { /* _StringPool */
2986 /* len, refs */
2987  0, 0, /* string 0 '' */
2988  3, 2, /* string 1 'MOO' */
2989  3, 1, /* string 2 'COW' */
2990  3, 1, /* string 3 'PIG' */
2991  1, 1, /* string 4 'c' */
2992  3, 3, /* string 5 'AAR' */
2993  3, 1, /* string 6 'CAR' */
2994  3, 1, /* string 7 'BAR' */
2995  2, 1, /* string 8 'vw' */
2996  3, 1, /* string 9 'bmw' */
2997  8, 4, /* string 10 'Property' */
2998  5, 1, /* string 11 'Value' */
2999  4, 1, /* string 12 'prop' */
3000  3, 1, /* string 13 'val' */
3001 };
3002 /* update row, 0x0002 is a bitmask of present column data, keys are excluded */
3003 static const WCHAR data6[] = { /* MOO */
3004  0x000a, 0x8001, 0x0004, 0x8005, /* update row */
3005  0x0000, 0x8003, /* delete row */
3006 };
3007 
3008 static const WCHAR data7[] = { /* BINARY */
3009  0x0201, 0x8001, 0x0001,
3010 };
3011 
3012 static const char data8[] = /* stream data for the BINARY table */
3013  "naengmyon";
3014 
3015 static const WCHAR data9[] = { /* Property */
3016  0x0201, 0x000c, 0x000d,
3017 };
3018 
3019 static const struct {
3021  const void *data;
3024 {
3025  { name1, data1, sizeof data1 },
3026  { name2, data2, sizeof data2 },
3027  { name3, data3, sizeof data3 },
3028  { name4, data4, sizeof data4 - 1 },
3029  { name5, data5, sizeof data5 },
3030  { name6, data6, sizeof data6 },
3031  { name7, data7, sizeof data7 },
3032  { name8, data8, sizeof data8 - 1 },
3033  { name9, data9, sizeof data9 },
3034 };
3035 
3036 #define NUM_TRANSFORM_TABLES (sizeof table_transform_data/sizeof table_transform_data[0])
3037 
3038 static void generate_transform_manual(void)
3039 {
3040  IStorage *stg = NULL;
3041  IStream *stm;
3042  WCHAR name[0x20];
3043  HRESULT r;
3044  DWORD i, count;
3046 
3047  const CLSID CLSID_MsiTransform = { 0xc1082,0,0,{0xc0,0,0,0,0,0,0,0x46}};
3048 
3049  MultiByteToWideChar(CP_ACP, 0, mstfile, -1, name, 0x20);
3050 
3051  r = StgCreateDocfile(name, mode, 0, &stg);
3052  ok(r == S_OK, "failed to create storage\n");
3053  if (!stg)
3054  return;
3055 
3056  r = IStorage_SetClass( stg, &CLSID_MsiTransform );
3057  ok(r == S_OK, "failed to set storage type\n");
3058 
3059  for (i=0; i<NUM_TRANSFORM_TABLES; i++)
3060  {
3061  r = IStorage_CreateStream( stg, table_transform_data[i].name,
3062  STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stm );
3063  if (FAILED(r))
3064  {
3065  ok(0, "failed to create stream %08x\n", r);
3066  continue;
3067  }
3068 
3069  r = IStream_Write( stm, table_transform_data[i].data,
3071  if (FAILED(r) || count != table_transform_data[i].size)
3072  ok(0, "failed to write stream\n");
3073  IStream_Release(stm);
3074  }
3075 
3076  IStorage_Release(stg);
3077 }
3078 
3080 {
3081  UINT res;
3083 
3084  /* build summary info */
3086  ok( res == ERROR_SUCCESS , "Failed to open summaryinfo\n" );
3087 
3089  "Installation Database");
3090  ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
3091 
3093  "Installation Database");
3094  ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
3095 
3097  "Wine Hackers");
3098  ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
3099 
3101  ";1033,2057");
3102  ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
3103 
3105  "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}");
3106  ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
3107 
3109  ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
3110 
3112  ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
3113 
3115  ok( res == ERROR_SUCCESS , "Failed to make summary info persist\n" );
3116 
3118  ok( res == ERROR_SUCCESS , "Failed to close suminfo\n" );
3119 
3120  return res;
3121 }
3122 
3124 {
3125  MSIHANDLE hdb = 0;
3126  UINT res;
3127 
3129 
3130  /* create an empty database */
3132  ok( res == ERROR_SUCCESS , "Failed to create database\n" );
3133  if( res != ERROR_SUCCESS )
3134  return hdb;
3135 
3136  res = MsiDatabaseCommit( hdb );
3137  ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
3138 
3139  res = set_summary_info(hdb);
3140  ok( res == ERROR_SUCCESS , "Failed to set summary info\n" );
3141 
3143 
3144  return hdb;
3145 }
3146 
3148 {
3149  UINT res;
3150  CHAR szPackage[12];
3151  MSIHANDLE hPackage;
3152 
3153  sprintf(szPackage, "#%u", hdb);
3154  res = MsiOpenPackageA(szPackage, &hPackage);
3155  if (res != ERROR_SUCCESS)
3156  return res;
3157 
3158  res = MsiCloseHandle(hdb);
3159  if (res != ERROR_SUCCESS)
3160  {
3161  MsiCloseHandle(hPackage);
3162  return res;
3163  }
3164 
3165  *handle = hPackage;
3166  return ERROR_SUCCESS;
3167 }
3168 
3169 static void test_try_transform(void)
3170 {
3171  MSIHANDLE hdb, hview, hrec, hpkg = 0;
3172  LPCSTR query;
3173  UINT r;
3174  DWORD sz;
3175  char buffer[MAX_PATH];
3176 
3179 
3180  /* create the database */
3181  hdb = create_package_db(msifileW);
3182  ok(hdb, "Failed to create package db\n");
3183 
3184  query = "CREATE TABLE `MOO` ( `NOO` SHORT NOT NULL, `OOO` CHAR(255) PRIMARY KEY `NOO`)";
3185  r = run_query(hdb, 0, query);
3186  ok(r == ERROR_SUCCESS, "failed to add table\n");
3187 
3188  query = "INSERT INTO `MOO` ( `NOO`, `OOO` ) VALUES ( 1, 'a' )";
3189  r = run_query(hdb, 0, query);
3190  ok(r == ERROR_SUCCESS, "failed to add row\n");
3191 
3192  query = "INSERT INTO `MOO` ( `NOO`, `OOO` ) VALUES ( 2, 'b' )";
3193  r = run_query(hdb, 0, query);
3194  ok(r == ERROR_SUCCESS, "failed to add row\n");
3195 
3196  query = "INSERT INTO `MOO` ( `NOO`, `OOO` ) VALUES ( 3, 'c' )";
3197  r = run_query(hdb, 0, query);
3198  ok(r == ERROR_SUCCESS, "failed to add row\n");
3199 
3200  query = "CREATE TABLE `BINARY` ( `ID` SHORT NOT NULL, `BLOB` OBJECT PRIMARY KEY `ID`)";
3201  r = run_query(hdb, 0, query);
3202  ok(r == ERROR_SUCCESS, "failed to add table\n");
3203 
3204  hrec = MsiCreateRecord(2);
3205  r = MsiRecordSetInteger(hrec, 1, 2);
3206  ok(r == ERROR_SUCCESS, "failed to set integer\n");
3207 
3208  write_file("testdata.bin", "lamyon", 6);
3209  r = MsiRecordSetStreamA(hrec, 2, "testdata.bin");
3210  ok(r == ERROR_SUCCESS, "failed to set stream\n");
3211 
3212  query = "INSERT INTO `BINARY` ( `ID`, `BLOB` ) VALUES ( ?, ? )";
3213  r = run_query(hdb, hrec, query);
3214  ok(r == ERROR_SUCCESS, "failed to add row with blob\n");
3215 
3216  MsiCloseHandle(hrec);
3217 
3218  r = MsiDatabaseCommit( hdb );
3219  ok( r == ERROR_SUCCESS , "Failed to commit database\n" );
3220 
3221  MsiCloseHandle( hdb );
3222  DeleteFileA("testdata.bin");
3223 
3224  /*
3225  * Both these generate an equivalent transform,
3226  * but the first doesn't work in Wine yet
3227  * because MsiDatabaseGenerateTransform is unimplemented.
3228  */
3229  if (0)
3231  else
3233 
3235  ok( r == ERROR_SUCCESS , "Failed to create database\n" );
3236 
3237  r = MsiDatabaseApplyTransformA( hdb, mstfile, 0 );
3238  ok( r == ERROR_SUCCESS, "return code %d, should be ERROR_SUCCESS\n", r );
3239 
3240  r = MsiDatabaseCommit( hdb );
3241  ok( r == ERROR_SUCCESS , "Failed to commit database\n" );
3242 
3243  /* check new values */
3244  hrec = 0;
3245  query = "select `BAR`,`CAR` from `AAR` where `BAR` = 1 AND `CAR` = 'vw'";
3246  r = do_query(hdb, query, &hrec);
3247  ok(r == ERROR_SUCCESS, "select query failed\n");
3248  MsiCloseHandle(hrec);
3249 
3250  query = "select `BAR`,`CAR` from `AAR` where `BAR` = 2 AND `CAR` = 'bmw'";
3251  hrec = 0;
3252  r = do_query(hdb, query, &hrec);
3253  ok(r == ERROR_SUCCESS, "select query failed\n");
3254  MsiCloseHandle(hrec);
3255 
3256  /* check updated values */
3257  hrec = 0;
3258  query = "select `NOO`,`OOO` from `MOO` where `NOO` = 1 AND `OOO` = 'c'";
3259  r = do_query(hdb, query, &hrec);
3260  ok(r == ERROR_SUCCESS, "select query failed\n");
3261  MsiCloseHandle(hrec);
3262 
3263  /* check unchanged value */
3264  hrec = 0;
3265  query = "select `NOO`,`OOO` from `MOO` where `NOO` = 2 AND `OOO` = 'b'";
3266  r = do_query(hdb, query, &hrec);
3267  ok(r == ERROR_SUCCESS, "select query failed\n");
3268  MsiCloseHandle(hrec);
3269 
3270  /* check deleted value */
3271  hrec = 0;
3272  query = "select * from `MOO` where `NOO` = 3";
3273  r = do_query(hdb, query, &hrec);
3274  ok(r == ERROR_NO_MORE_ITEMS, "select query failed\n");
3275  if (hrec) MsiCloseHandle(hrec);
3276 
3277  /* check added stream */
3278  hrec = 0;
3279  query = "select `BLOB` from `BINARY` where `ID` = 1";
3280  r = do_query(hdb, query, &hrec);
3281  ok(r == ERROR_SUCCESS, "select query failed\n");
3282 
3283  /* check the contents of the stream */
3284  sz = sizeof buffer;
3285  r = MsiRecordReadStream( hrec, 1, buffer, &sz );
3286  ok(r == ERROR_SUCCESS, "read stream failed\n");
3287  ok(!memcmp(buffer, "naengmyon", 9), "stream data was wrong\n");
3288  ok(sz == 9, "stream data was wrong size\n");
3289  if (hrec) MsiCloseHandle(hrec);
3290 
3291  /* check the validity of the table with a deleted row */
3292  hrec = 0;
3293  query = "select * from `MOO`";
3294  r = MsiDatabaseOpenViewA(hdb, query, &hview);
3295  ok(r == ERROR_SUCCESS, "open view failed\n");
3296 
3297  r = MsiViewExecute(hview, 0);
3298  ok(r == ERROR_SUCCESS, "view execute failed\n");
3299 
3300  r = MsiViewFetch(hview, &hrec);
3301  ok(r == ERROR_SUCCESS, "view fetch failed\n");
3302 
3303  r = MsiRecordGetInteger(hrec, 1);
3304  ok(r == 1, "Expected 1, got %d\n", r);
3305 
3306  sz = sizeof buffer;
3307  r = MsiRecordGetStringA(hrec, 2, buffer, &sz);
3308  ok(r == ERROR_SUCCESS, "record get string failed\n");
3309  ok(!lstrcmpA(buffer, "c"), "Expected c, got %s\n", buffer);
3310 
3311  r = MsiRecordGetInteger(hrec, 3);
3312  ok(r == 0x80000000, "Expected 0x80000000, got %d\n", r);
3313 
3314  r = MsiRecordGetInteger(hrec, 4);
3315  ok(r == 5, "Expected 5, got %d\n", r);
3316 
3317  MsiCloseHandle(hrec);
3318 
3319  r = MsiViewFetch(hview, &hrec);
3320  ok(r == ERROR_SUCCESS, "view fetch failed\n");
3321 
3322  r = MsiRecordGetInteger(hrec, 1);
3323  ok(r == 2, "Expected 2, got %d\n", r);
3324 
3325  sz = sizeof buffer;
3326  r = MsiRecordGetStringA(hrec, 2, buffer, &sz);
3327  ok(r == ERROR_SUCCESS, "record get string failed\n");
3328  ok(!lstrcmpA(buffer, "b"), "Expected b, got %s\n", buffer);
3329 
3330  r = MsiRecordGetInteger(hrec, 3);
3331  ok(r == 0x80000000, "Expected 0x80000000, got %d\n", r);
3332 
3333  r = MsiRecordGetInteger(hrec, 4);
3334  ok(r == 0x80000000, "Expected 0x80000000, got %d\n", r);
3335 
3336  MsiCloseHandle(hrec);
3337 
3338  r = MsiViewFetch(hview, &hrec);
3339  ok(r == ERROR_NO_MORE_ITEMS, "view fetch succeeded\n");
3340 
3341  MsiCloseHandle(hrec);
3342  MsiViewClose(hview);
3343  MsiCloseHandle(hview);
3344 
3345  /* check that the property was added */
3346  r = package_from_db(hdb, &hpkg);
3348  {
3349  skip("Not enough rights to perform tests\n");
3350  goto error;
3351  }
3352  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
3353 
3354  sz = MAX_PATH;
3355  r = MsiGetPropertyA(hpkg, "prop", buffer, &sz);
3356  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
3357  ok(!lstrcmpA(buffer, "val"), "Expected val, got %s\n", buffer);
3358 
3359  MsiCloseHandle(hpkg);
3360 
3361 error:
3362  MsiCloseHandle(hdb);
3365 }
3366 
3367 struct join_res
3368 {
3371 };
3372 
3374 {
3379 };
3380 
3382 {
3389 };
3390 
3391 static const struct join_res join_res_first[] =
3392 {
3393  { "alveolar", "procerus" },
3394  { "septum", "procerus" },
3395  { "septum", "nasalis" },
3396  { "ramus", "nasalis" },
3397  { "malar", "mentalis" },
3398 };
3399 
3400 static const struct join_res join_res_second[] =
3401 {
3402  { "nasal", "septum" },
3403  { "mandible", "ramus" },
3404 };
3405 
3406 static const struct join_res join_res_third[] =
3407 {
3408  { "msvcp.dll", "abcdefgh" },
3409  { "msvcr.dll", "ijklmnop" },
3410 };
3411 
3412 static const struct join_res join_res_fourth[] =
3413 {
3414  { "msvcp.dll.01234", "single.dll.31415" },
3415 };
3416 
3417 static const struct join_res join_res_fifth[] =
3418 {
3419  { "malar", "procerus" },
3420 };
3421 
3422 static const struct join_res join_res_sixth[] =
3423 {
3424  { "malar", "procerus" },
3425  { "malar", "procerus" },
3426  { "malar", "nasalis" },
3427  { "malar", "nasalis" },
3428  { "malar", "nasalis" },
3429  { "malar", "mentalis" },
3430 };
3431 
3432 static const struct join_res join_res_seventh[] =
3433 {
3434  { "malar", "nasalis" },
3435  { "malar", "nasalis" },
3436  { "malar", "nasalis" },
3437 };
3438 
3439 static const struct join_res_4col join_res_eighth[] =
3440 {
3441  { "msvcp.dll", "msvcp.dll.01234", "msvcp.dll.01234", "abcdefgh" },
3442  { "msvcr.dll", "msvcr.dll.56789", "msvcp.dll.01234", "abcdefgh" },
3443  { "msvcp.dll", "msvcp.dll.01234", "msvcr.dll.56789", "ijklmnop" },
3444  { "msvcr.dll", "msvcr.dll.56789", "msvcr.dll.56789", "ijklmnop" },
3445  { "msvcp.dll", "msvcp.dll.01234", "single.dll.31415", "msvcp.dll" },
3446  { "msvcr.dll", "msvcr.dll.56789", "single.dll.31415", "msvcp.dll" },
3447 };
3448 
3449 static const struct join_res_uint join_res_ninth[] =
3450 {
3451  { 1, 2, 3, 4, 7, 8 },
3452  { 1, 2, 5, 6, 7, 8 },
3453  { 1, 2, 3, 4, 9, 10 },
3454  { 1, 2, 5, 6, 9, 10 },
3455  { 1, 2, 3, 4, 11, 12 },
3456  { 1, 2, 5, 6, 11, 12 },
3457 };
3458 
3459 static void test_join(void)
3460 {
3461  MSIHANDLE hdb, hview, hrec;
3462  LPCSTR query;
3463  CHAR buf[MAX_PATH];
3464  UINT r, count;
3465  DWORD size, i;
3466  BOOL data_correct;
3467 
3468  hdb = create_db();
3469  ok( hdb, "failed to create db\n");
3470 
3471  create_component_table( hdb );
3472  add_component_entry( hdb, "'zygomatic', 'malar', 'INSTALLDIR', 0, '', ''" );
3473  add_component_entry( hdb, "'maxilla', 'alveolar', 'INSTALLDIR', 0, '', ''" );
3474  add_component_entry( hdb, "'nasal', 'septum', 'INSTALLDIR', 0, '', ''" );
3475  add_component_entry( hdb, "'mandible', 'ramus', 'INSTALLDIR', 0, '', ''" );
3476 
3478  add_feature_components_entry( hdb, "'procerus', 'maxilla'" );
3479  add_feature_components_entry( hdb, "'procerus', 'nasal'" );
3480  add_feature_components_entry( hdb, "'nasalis', 'nasal'" );
3481  add_feature_components_entry( hdb, "'nasalis', 'mandible'" );
3482  add_feature_components_entry( hdb, "'nasalis', 'notacomponent'" );
3483  add_feature_components_entry( hdb, "'mentalis', 'zygomatic'" );
3484 
3485  create_std_dlls_table( hdb );
3486  add_std_dlls_entry( hdb, "'msvcp.dll', 'msvcp.dll.01234'" );
3487  add_std_dlls_entry( hdb, "'msvcr.dll', 'msvcr.dll.56789'" );
3488 
3489  create_binary_table( hdb );
3490  add_binary_entry( hdb, "'msvcp.dll.01234', 'abcdefgh'" );
3491  add_binary_entry( hdb, "'msvcr.dll.56789', 'ijklmnop'" );
3492  add_binary_entry( hdb, "'single.dll.31415', 'msvcp.dll'" );
3493 
3494  query = "CREATE TABLE `One` (`A` SHORT, `B` SHORT PRIMARY KEY `A`)";
3495  r = run_query( hdb, 0, query);
3496  ok(r == ERROR_SUCCESS, "cannot create table: %d\n", r );
3497 
3498  query = "CREATE TABLE `Two` (`C` SHORT, `D` SHORT PRIMARY KEY `C`)";
3499  r = run_query( hdb, 0, query);
3500  ok(r == ERROR_SUCCESS, "cannot create table: %d\n", r );
3501 
3502  query = "CREATE TABLE `Three` (`E` SHORT, `F` SHORT PRIMARY KEY `E`)";
3503  r = run_query( hdb, 0, query);
3504  ok(r == ERROR_SUCCESS, "cannot create table: %d\n", r );
3505 
3506  query = "INSERT INTO `One` (`A`, `B`) VALUES (1, 2)";
3507  r = run_query( hdb, 0, query);
3508  ok(r == ERROR_SUCCESS, "cannot insert into table: %d\n", r );
3509 
3510  query = "INSERT INTO `Two` (`C`, `D`) VALUES (3, 4)";
3511  r = run_query( hdb, 0, query);
3512  ok(r == ERROR_SUCCESS, "cannot insert into table: %d\n", r );
3513 
3514  query = "INSERT INTO `Two` (`C`, `D`) VALUES (5, 6)";
3515  r = run_query( hdb, 0, query);
3516  ok(r == ERROR_SUCCESS, "cannot insert into table: %d\n", r );
3517 
3518  query = "INSERT INTO `Three` (`E`, `F`) VALUES (7, 8)";
3519  r = run_query( hdb, 0, query);
3520  ok(r == ERROR_SUCCESS, "cannot insert into table: %d\n", r );
3521 
3522  query = "INSERT INTO `Three` (`E`, `F`) VALUES (9, 10)";
3523  r = run_query( hdb, 0, query);
3524  ok(r == ERROR_SUCCESS, "cannot insert into table: %d\n", r );
3525 
3526  query = "INSERT INTO `Three` (`E`, `F`) VALUES (11, 12)";
3527  r = run_query( hdb, 0, query);
3528  ok(r == ERROR_SUCCESS, "cannot insert into table: %d\n", r );
3529 
3530  query = "CREATE TABLE `Four` (`G` SHORT, `H` SHORT PRIMARY KEY `G`)";
3531  r = run_query( hdb, 0, query);
3532  ok(r == ERROR_SUCCESS, "cannot create table: %d\n", r );
3533 
3534  query = "CREATE TABLE `Five` (`I` SHORT, `J` SHORT PRIMARY KEY `I`)";
3535  r = run_query( hdb, 0, query);
3536  ok(r == ERROR_SUCCESS, "cannot create table: %d\n", r );
3537 
3538  query = "INSERT INTO `Five` (`I`, `J`) VALUES (13, 14)";
3539  r = run_query( hdb, 0, query);
3540  ok(r == ERROR_SUCCESS, "cannot insert into table: %d\n", r );
3541 
3542  query = "INSERT INTO `Five` (`I`, `J`) VALUES (15, 16)";
3543  r = run_query( hdb, 0, query);
3544  ok(r == ERROR_SUCCESS, "cannot insert into table: %d\n", r );
3545 
3546  query = "SELECT `Component`.`ComponentId`, `FeatureComponents`.`Feature_` "
3547  "FROM `Component`, `FeatureComponents` "
3548  "WHERE `Component`.`Component` = `FeatureComponents`.`Component_` "
3549  "ORDER BY `Feature_`";
3550  r = MsiDatabaseOpenViewA(hdb, query, &hview);
3551  ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3552 
3553  r = MsiViewExecute(hview, 0);
3554  ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3555 
3556  i = 0;
3557  while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3558  {
3559  count = MsiRecordGetFieldCount( hrec );
3560  ok( count == 2, "Expected 2 record fields, got %d\n", count );
3561 
3562  size = MAX_PATH;
3563  r = MsiRecordGetStringA( hrec, 1, buf, &size );
3564  ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3565  ok( !lstrcmpA( buf, join_res_first[i].one ),
3566  "For (row %d, column 1) expected '%s', got %s\n", i, join_res_first[i].one, buf );
3567 
3568  size = MAX_PATH;
3569  r = MsiRecordGetStringA( hrec, 2, buf, &size );
3570  ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3571  ok( !lstrcmpA( buf, join_res_first[i].two ),
3572  "For (row %d, column 2) expected '%s', got %s\n", i, join_res_first[i].two, buf );
3573 
3574  i++;
3575  MsiCloseHandle(hrec);
3576  }
3577 
3578  ok( i == 5, "Expected 5 rows, got %d\n", i );
3579  ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3580 
3581  MsiViewClose(hview);
3582  MsiCloseHandle(hview);
3583 
3584  /* try a join without a WHERE condition */
3585  query = "SELECT `Component`.`ComponentId`, `FeatureComponents`.`Feature_` "
3586  "FROM `Component`, `FeatureComponents` ";
3587  r = MsiDatabaseOpenViewA(hdb, query, &hview);
3588  ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3589 
3590  r = MsiViewExecute(hview, 0);
3591  ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3592 
3593  i = 0;
3594  while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3595  {
3596  i++;
3597  MsiCloseHandle(hrec);
3598  }
3599  ok( i == 24, "Expected 24 rows, got %d\n", i );
3600 
3601  MsiViewClose(hview);
3602  MsiCloseHandle(hview);
3603 
3604  query = "SELECT DISTINCT Component, ComponentId FROM FeatureComponents, Component "
3605  "WHERE FeatureComponents.Component_=Component.Component "
3606  "AND (Feature_='nasalis') ORDER BY Feature_";
3607  r = MsiDatabaseOpenViewA(hdb, query, &hview);
3608  ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3609 
3610  r = MsiViewExecute(hview, 0);
3611  ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3612 
3613  i = 0;
3614  data_correct = TRUE;
3615  while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3616  {
3617  count = MsiRecordGetFieldCount( hrec );
3618  ok( count == 2, "Expected 2 record fields, got %d\n", count );
3619 
3620  size = MAX_PATH;
3621  r = MsiRecordGetStringA( hrec, 1, buf, &size );
3622  ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3623  if( lstrcmpA( buf, join_res_second[i].one ))
3624  data_correct = FALSE;
3625 
3626  size = MAX_PATH;
3627  r = MsiRecordGetStringA( hrec, 2, buf, &size );
3628  ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3629  if( lstrcmpA( buf, join_res_second[i].two ))
3630  data_correct = FALSE;
3631 
3632  i++;
3633  MsiCloseHandle(hrec);
3634  }
3635 
3636  ok( data_correct, "data returned in the wrong order\n");
3637 
3638  ok( i == 2, "Expected 2 rows, got %d\n", i );
3639  ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3640 
3641  MsiViewClose(hview);
3642  MsiCloseHandle(hview);
3643 
3644  query = "SELECT `StdDlls`.`File`, `Binary`.`Data` "
3645  "FROM `StdDlls`, `Binary` "
3646  "WHERE `StdDlls`.`Binary_` = `Binary`.`Name` "
3647  "ORDER BY `File`";
3648  r = MsiDatabaseOpenViewA(hdb, query, &hview);
3649  ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3650 
3651  r = MsiViewExecute(hview, 0);
3652  ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3653 
3654  i = 0;
3655  data_correct = TRUE;
3656  while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3657  {
3658  count = MsiRecordGetFieldCount( hrec );
3659  ok( count == 2, "Expected 2 record fields, got %d\n", count );
3660 
3661  size = MAX_PATH;
3662  r = MsiRecordGetStringA( hrec, 1, buf, &size );
3663  ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3664  if( lstrcmpA( buf, join_res_third[i].one ) )
3665  data_correct = FALSE;
3666 
3667  size = MAX_PATH;
3668  r = MsiRecordGetStringA( hrec, 2, buf, &size );
3669  ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r );
3670  if( lstrcmpA( buf, join_res_third[i].two ) )
3671  data_correct = FALSE;
3672 
3673  i++;
3674  MsiCloseHandle(hrec);
3675  }
3676  ok( data_correct, "data returned in the wrong order\n");
3677 
3678  ok( i == 2, "Expected 2 rows, got %d\n", i );
3679 
3680  ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r );
3681 
3682  MsiViewClose(hview);
3683  MsiCloseHandle(hview);
3684 
3685  query = "SELECT `StdDlls`.`Binary_`, `Binary`.`Name` "
3686  "FROM `StdDlls`, `Binary` "
3687  "WHERE `StdDlls`.`File` = `Binary`.`Data` "
3688  "ORDER BY `Name`";
3689  r = MsiDatabaseOpenViewA(hdb, query, &hview);
3690  ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r );
3691 
3692  r = MsiViewExecute(hview, 0);
3693  ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r );
3694 
3695  i = 0;
3696  data_correct = TRUE;
3697  while ((r = MsiViewFetch(hview, &hrec)) == ERROR_SUCCESS)
3698  {
3699  count = MsiRecordGetFieldCount( hrec );
3700  ok( count == 2, "Expected 2 record fields, got %d\n", count );
3701 
3702  size = MAX_PATH;
3703  r = MsiRecordGetStringA( hrec, 1, buf, &size );
3704  ok( r == ERROR_SUCCESS, "failed to get record string: %d\n",