msi/tests: Add test to verify we can create 4000 msi handles.
[wine/wine64.git] / dlls / msi / tests / db.c
blob0a5b230052d98112cb80abb0364fcee457ecafd9
1 /*
2 * Copyright (C) 2005 Mike McCormack for CodeWeavers
4 * A test program for MSI database files.
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.
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.
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
20 #include <stdio.h>
22 #include <windows.h>
23 #include <msi.h>
24 #include <msiquery.h>
26 #include "wine/test.h"
28 static const char *msifile = "winetest.msi";
30 static void test_msidatabase(void)
32 MSIHANDLE hdb = 0;
33 UINT res;
35 DeleteFile(msifile);
37 /* create an empty database */
38 res = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb );
39 ok( res == ERROR_SUCCESS , "Failed to create database\n" );
41 res = MsiDatabaseCommit( hdb );
42 ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
44 res = MsiCloseHandle( hdb );
45 ok( res == ERROR_SUCCESS , "Failed to close database\n" );
47 res = DeleteFile( msifile );
48 ok( res == TRUE, "Failed to delete database\n" );
51 static UINT do_query(MSIHANDLE hdb, const char *query, MSIHANDLE *phrec)
53 MSIHANDLE hview = 0;
54 UINT r, ret;
56 /* open a select query */
57 r = MsiDatabaseOpenView(hdb, query, &hview);
58 if (r != ERROR_SUCCESS)
59 return r;
60 r = MsiViewExecute(hview, 0);
61 if (r != ERROR_SUCCESS)
62 return r;
63 ret = MsiViewFetch(hview, phrec);
64 r = MsiViewClose(hview);
65 if (r != ERROR_SUCCESS)
66 return r;
67 r = MsiCloseHandle(hview);
68 if (r != ERROR_SUCCESS)
69 return r;
70 return ret;
73 static void test_msiinsert(void)
75 MSIHANDLE hdb = 0, hview = 0, hrec = 0;
76 UINT r;
77 const char *query;
78 char buf[80];
79 DWORD sz;
81 DeleteFile(msifile);
83 /* just MsiOpenDatabase should not create a file */
84 r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
85 ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
87 /* create a table */
88 query = "CREATE TABLE `phone` ( "
89 "`id` INT, `name` CHAR(32), `number` CHAR(32) "
90 "PRIMARY KEY `id`)";
91 r = MsiDatabaseOpenView(hdb, query, &hview);
92 ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
93 r = MsiViewExecute(hview, 0);
94 ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
95 r = MsiViewClose(hview);
96 ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
97 r = MsiCloseHandle(hview);
98 ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
100 /* insert a value into it */
101 query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
102 "VALUES('1', 'Abe', '8675309')";
103 r = MsiDatabaseOpenView(hdb, query, &hview);
104 ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
105 r = MsiViewExecute(hview, 0);
106 ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
107 r = MsiViewClose(hview);
108 ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
109 r = MsiCloseHandle(hview);
110 ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
112 query = "SELECT * FROM `phone` WHERE `id` = 1";
113 r = do_query(hdb, query, &hrec);
114 ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
116 /* check the record contains what we put in it */
117 r = MsiRecordGetFieldCount(hrec);
118 ok(r == 3, "record count wrong\n");
120 todo_wine {
121 r = MsiRecordIsNull(hrec, 0);
122 ok(r == FALSE, "field 0 not null\n");
125 r = MsiRecordGetInteger(hrec, 1);
126 ok(r == 1, "field 1 contents wrong\n");
127 sz = sizeof buf;
128 r = MsiRecordGetString(hrec, 2, buf, &sz);
129 ok(r == ERROR_SUCCESS, "field 2 content fetch failed\n");
130 ok(!strcmp(buf,"Abe"), "field 2 content incorrect\n");
131 sz = sizeof buf;
132 r = MsiRecordGetString(hrec, 3, buf, &sz);
133 ok(r == ERROR_SUCCESS, "field 3 content fetch failed\n");
134 ok(!strcmp(buf,"8675309"), "field 3 content incorrect\n");
136 r = MsiCloseHandle(hrec);
137 ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
139 /* open a select query */
140 hrec = 100;
141 query = "SELECT * FROM `phone` WHERE `id` >= 10";
142 r = do_query(hdb, query, &hrec);
143 ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch failed\n");
144 ok(hrec == 0, "hrec should be null\n");
146 r = MsiCloseHandle(hrec);
147 ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
149 query = "SELECT * FROM `phone` WHERE `id` < 0";
150 r = do_query(hdb, query, &hrec);
151 ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch failed\n");
153 query = "SELECT * FROM `phone` WHERE `id` <= 0";
154 r = do_query(hdb, query, &hrec);
155 ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch failed\n");
157 query = "SELECT * FROM `phone` WHERE `id` <> 1";
158 r = do_query(hdb, query, &hrec);
159 ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch failed\n");
161 query = "SELECT * FROM `phone` WHERE `id` > 10";
162 r = do_query(hdb, query, &hrec);
163 ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch failed\n");
165 todo_wine {
166 /* now try a few bad INSERT xqueries */
167 query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
168 "VALUES(?, ?)";
169 r = MsiDatabaseOpenView(hdb, query, &hview);
170 ok(r == ERROR_BAD_QUERY_SYNTAX, "MsiDatabaseOpenView failed\n");
172 if (r == ERROR_SUCCESS)
173 r = MsiCloseHandle(hview);
176 /* construct a record to insert */
177 hrec = MsiCreateRecord(4);
178 r = MsiRecordSetInteger(hrec, 1, 2);
179 ok(r == ERROR_SUCCESS, "MsiRecordSetInteger failed\n");
180 r = MsiRecordSetString(hrec, 2, "Adam");
181 ok(r == ERROR_SUCCESS, "MsiRecordSetString failed\n");
182 r = MsiRecordSetString(hrec, 3, "96905305");
183 ok(r == ERROR_SUCCESS, "MsiRecordSetString failed\n");
185 /* insert another value, using a record and wildcards */
186 query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
187 "VALUES(?, ?, ?)";
188 r = MsiDatabaseOpenView(hdb, query, &hview);
189 ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
191 if (r == ERROR_SUCCESS)
193 r = MsiViewExecute(hview, hrec);
194 ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
195 r = MsiViewClose(hview);
196 ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
197 r = MsiCloseHandle(hview);
198 ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
200 r = MsiCloseHandle(hrec);
201 ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
203 r = MsiViewFetch(0, NULL);
204 ok(r == ERROR_INVALID_PARAMETER, "MsiViewFetch failed\n");
206 r = MsiDatabaseCommit(hdb);
207 ok(r == ERROR_SUCCESS, "MsiDatabaseCommit failed\n");
209 r = MsiCloseHandle(hdb);
210 ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
212 r = DeleteFile(msifile);
213 ok(r == TRUE, "file didn't exist after commit\n");
216 typedef UINT (WINAPI *fnMsiDecomposeDescriptorA)(LPCSTR, LPCSTR, LPSTR, LPSTR, DWORD *);
217 static fnMsiDecomposeDescriptorA pMsiDecomposeDescriptorA;
219 static void test_msidecomposedesc(void)
221 char prod[MAX_FEATURE_CHARS+1], comp[MAX_FEATURE_CHARS+1], feature[MAX_FEATURE_CHARS+1];
222 const char *desc;
223 UINT r;
224 DWORD len;
225 HMODULE hmod;
227 hmod = GetModuleHandle("msi.dll");
228 if (!hmod)
229 return;
230 pMsiDecomposeDescriptorA = (fnMsiDecomposeDescriptorA)
231 GetProcAddress(hmod, "MsiDecomposeDescriptorA");
232 if (!pMsiDecomposeDescriptorA)
233 return;
235 /* test a valid feature descriptor */
236 desc = "']gAVn-}f(ZXfeAR6.jiFollowTheWhiteRabbit>3w2x^IGfe?CxI5heAvk.";
237 len = 0;
238 r = pMsiDecomposeDescriptorA(desc, prod, feature, comp, &len);
239 ok(r == ERROR_SUCCESS, "returned an error\n");
240 ok(len == strlen(desc), "length was wrong\n");
241 ok(strcmp(prod,"{90110409-6000-11D3-8CFE-0150048383C9}")==0, "product wrong\n");
242 ok(strcmp(feature,"FollowTheWhiteRabbit")==0, "feature wrong\n");
243 ok(strcmp(comp,"{A7CD68DB-EF74-49C8-FBB2-A7C463B2AC24}")==0,"component wrong\n");
245 /* test an invalid feature descriptor with too many characters */
246 desc = "']gAVn-}f(ZXfeAR6.ji"
247 "ThisWillFailIfTheresMoreThanAGuidsChars>"
248 "3w2x^IGfe?CxI5heAvk.";
249 len = 0;
250 r = pMsiDecomposeDescriptorA(desc, prod, feature, comp, &len);
251 ok(r == ERROR_INVALID_PARAMETER, "returned wrong error\n");
254 * Test a valid feature descriptor with the
255 * maximum number of characters and some trailing characters.
257 desc = "']gAVn-}f(ZXfeAR6.ji"
258 "ThisWillWorkIfTheresLTEThanAGuidsChars>"
259 "3w2x^IGfe?CxI5heAvk."
260 "extra";
261 len = 0;
262 r = pMsiDecomposeDescriptorA(desc, prod, feature, comp, &len);
263 ok(r == ERROR_SUCCESS, "returned wrong error\n");
264 ok(len == (strlen(desc) - strlen("extra")), "length wrong\n");
266 len = 0;
267 r = pMsiDecomposeDescriptorA(desc, prod, feature, NULL, &len);
268 ok(r == ERROR_SUCCESS, "returned wrong error\n");
269 ok(len == (strlen(desc) - strlen("extra")), "length wrong\n");
271 len = 0;
272 r = pMsiDecomposeDescriptorA(desc, prod, NULL, NULL, &len);
273 ok(r == ERROR_SUCCESS, "returned wrong error\n");
274 ok(len == (strlen(desc) - strlen("extra")), "length wrong\n");
276 len = 0;
277 r = pMsiDecomposeDescriptorA(desc, NULL, NULL, NULL, &len);
278 ok(r == ERROR_SUCCESS, "returned wrong error\n");
279 ok(len == (strlen(desc) - strlen("extra")), "length wrong\n");
281 len = 0;
282 r = pMsiDecomposeDescriptorA(NULL, NULL, NULL, NULL, &len);
283 ok(r == ERROR_INVALID_PARAMETER, "returned wrong error\n");
284 ok(len == 0, "length wrong\n");
287 static UINT try_query_param( MSIHANDLE hdb, LPCSTR szQuery, MSIHANDLE hrec )
289 MSIHANDLE htab = 0;
290 UINT res;
292 res = MsiDatabaseOpenView( hdb, szQuery, &htab );
293 if(res == ERROR_SUCCESS )
295 UINT r;
297 r = MsiViewExecute( htab, hrec );
298 if(r != ERROR_SUCCESS )
299 res = r;
301 r = MsiViewClose( htab );
302 if(r != ERROR_SUCCESS )
303 res = r;
305 r = MsiCloseHandle( htab );
306 if(r != ERROR_SUCCESS )
307 res = r;
309 return res;
312 static UINT try_query( MSIHANDLE hdb, LPCSTR szQuery )
314 return try_query_param( hdb, szQuery, 0 );
317 static UINT try_insert_query( MSIHANDLE hdb, LPCSTR szQuery )
319 MSIHANDLE hrec = 0;
320 UINT r;
322 hrec = MsiCreateRecord( 1 );
323 MsiRecordSetString( hrec, 1, "Hello");
325 r = try_query_param( hdb, szQuery, hrec );
327 MsiCloseHandle( hrec );
328 return r;
331 static void test_msibadqueries(void)
333 MSIHANDLE hdb = 0;
334 UINT r;
336 DeleteFile(msifile);
338 /* just MsiOpenDatabase should not create a file */
339 r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
340 ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
342 r = MsiDatabaseCommit( hdb );
343 ok(r == ERROR_SUCCESS , "Failed to commit database\n");
345 r = MsiCloseHandle( hdb );
346 ok(r == ERROR_SUCCESS , "Failed to close database\n");
348 /* open it readonly */
349 r = MsiOpenDatabase(msifile, MSIDBOPEN_READONLY, &hdb );
350 ok(r == ERROR_SUCCESS , "Failed to open database r/o\n");
352 /* add a table to it */
353 r = try_query( hdb, "select * from _Tables");
354 ok(r == ERROR_SUCCESS , "query 1 failed\n");
356 r = MsiCloseHandle( hdb );
357 ok(r == ERROR_SUCCESS , "Failed to close database r/o\n");
359 /* open it read/write */
360 r = MsiOpenDatabase(msifile, MSIDBOPEN_TRANSACT, &hdb );
361 ok(r == ERROR_SUCCESS , "Failed to open database r/w\n");
363 /* a bunch of test queries that fail with the native MSI */
365 r = try_query( hdb, "CREATE TABLE");
366 ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2a return code\n");
368 r = try_query( hdb, "CREATE TABLE `a`");
369 ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2b return code\n");
371 r = try_query( hdb, "CREATE TABLE `a` ()");
372 ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2c return code\n");
374 r = try_query( hdb, "CREATE TABLE `a` (`b`)");
375 ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2d return code\n");
377 r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) )");
378 ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2e return code\n");
380 r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL)");
381 ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2f return code\n");
383 r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY)");
384 ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2g return code\n");
386 r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY)");
387 ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2h return code\n");
389 r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY)");
390 ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2i return code\n");
392 r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY 'b')");
393 ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2j return code\n");
395 r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY `b')");
396 ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2k return code\n");
398 r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY `b')");
399 ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2l return code\n");
401 r = try_query( hdb, "CREATE TABLE `a` (`b` CHA(72) NOT NULL PRIMARY KEY `b`)");
402 ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2m return code\n");
404 r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(-1) NOT NULL PRIMARY KEY `b`)");
405 ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2n return code\n");
407 r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(720) NOT NULL PRIMARY KEY `b`)");
408 ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2o return code\n");
410 r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL KEY `b`)");
411 ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2p return code\n");
413 r = try_query( hdb, "CREATE TABLE `a` (`` CHAR(72) NOT NULL PRIMARY KEY `b`)");
414 ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2p return code\n");
416 r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY `b`)");
417 ok(r == ERROR_SUCCESS , "valid query 2z failed\n");
419 r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY `b`)");
420 ok(r == ERROR_BAD_QUERY_SYNTAX , "created same table again\n");
422 r = try_query( hdb, "CREATE TABLE `aa` (`b` CHAR(72) NOT NULL, `c` "
423 "CHAR(72), `d` CHAR(255) NOT NULL LOCALIZABLE PRIMARY KEY `b`)");
424 ok(r == ERROR_SUCCESS , "query 4 failed\n");
426 r = MsiDatabaseCommit( hdb );
427 ok(r == ERROR_SUCCESS , "Failed to commit database after write\n");
429 r = try_query( hdb, "CREATE TABLE `blah` (`foo` CHAR(72) NOT NULL "
430 "PRIMARY KEY `foo`)");
431 ok(r == ERROR_SUCCESS , "query 4 failed\n");
433 r = try_insert_query( hdb, "insert into a ( `b` ) VALUES ( ? )");
434 ok(r == ERROR_SUCCESS , "failed to insert record in db\n");
436 r = MsiDatabaseCommit( hdb );
437 ok(r == ERROR_SUCCESS , "Failed to commit database after write\n");
439 r = try_query( hdb, "CREATE TABLE `boo` (`foo` CHAR(72) NOT NULL "
440 "PRIMARY KEY `ba`)");
441 ok(r != ERROR_SUCCESS , "query 5 succeeded\n");
443 r = try_query( hdb,"CREATE TABLE `bee` (`foo` CHAR(72) NOT NULL )");
444 ok(r != ERROR_SUCCESS , "query 6 succeeded\n");
446 r = try_query( hdb, "CREATE TABLE `temp` (`t` CHAR(72) NOT NULL "
447 "PRIMARY KEY `t`)");
448 ok(r == ERROR_SUCCESS , "query 7 failed\n");
450 r = try_query( hdb, "CREATE TABLE `c` (`b` CHAR NOT NULL PRIMARY KEY `b`)");
451 ok(r == ERROR_SUCCESS , "query 8 failed\n");
453 r = MsiCloseHandle( hdb );
454 ok(r == ERROR_SUCCESS , "Failed to close database transact\n");
456 r = DeleteFile( msifile );
457 ok(r == TRUE, "file didn't exist after commit\n");
460 static UINT run_query( MSIHANDLE hdb, MSIHANDLE hrec, const char *query )
462 MSIHANDLE hview = 0;
463 UINT r;
465 r = MsiDatabaseOpenView(hdb, query, &hview);
466 if( r != ERROR_SUCCESS )
467 return r;
469 r = MsiViewExecute(hview, hrec);
470 if( r == ERROR_SUCCESS )
471 r = MsiViewClose(hview);
472 MsiCloseHandle(hview);
473 return r;
476 static void test_viewmodify(void)
478 MSIHANDLE hdb = 0, hview = 0, hrec = 0;
479 UINT r;
480 const char *query;
481 char buffer[0x100];
482 DWORD sz;
484 DeleteFile(msifile);
486 /* just MsiOpenDatabase should not create a file */
487 r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
488 ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
490 query = "CREATE TABLE `phone` ( "
491 "`id` INT, `name` CHAR(32), `number` CHAR(32) "
492 "PRIMARY KEY `id`)";
493 r = run_query( hdb, 0, query );
494 ok(r == ERROR_SUCCESS, "query failed\n");
496 /* check what the error function reports without doing anything */
497 sz = 0;
498 /* passing NULL as the 3rd param make function to crash on older platforms */
499 r = MsiViewGetError( 0, NULL, &sz );
500 ok(r == MSIDBERROR_INVALIDARG, "MsiViewGetError return\n");
502 /* open a view */
503 query = "SELECT * FROM `phone`";
504 r = MsiDatabaseOpenView(hdb, query, &hview);
505 ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
507 /* see what happens with a good hview and bad args */
508 r = MsiViewGetError( hview, NULL, NULL );
509 ok(r == MSIDBERROR_INVALIDARG || r == MSIDBERROR_NOERROR,
510 "MsiViewGetError returns %u (expected -3)\n", r);
511 r = MsiViewGetError( hview, buffer, NULL );
512 ok(r == MSIDBERROR_INVALIDARG, "MsiViewGetError return\n");
514 /* see what happens with a zero length buffer */
515 sz = 0;
516 buffer[0] = 'x';
517 r = MsiViewGetError( hview, buffer, &sz );
518 ok(r == MSIDBERROR_MOREDATA, "MsiViewGetError return\n");
519 ok(buffer[0] == 'x', "buffer cleared\n");
520 ok(sz == 0, "size not zero\n");
522 /* ok this one is strange */
523 sz = 0;
524 r = MsiViewGetError( hview, NULL, &sz );
525 ok(r == MSIDBERROR_NOERROR, "MsiViewGetError return\n");
526 ok(sz == 0, "size not zero\n");
528 /* see if it really has an error */
529 sz = sizeof buffer;
530 buffer[0] = 'x';
531 r = MsiViewGetError( hview, buffer, &sz );
532 ok(r == MSIDBERROR_NOERROR, "MsiViewGetError return\n");
533 ok(buffer[0] == 0, "buffer not cleared\n");
534 ok(sz == 0, "size not zero\n");
536 r = MsiViewExecute(hview, 0);
537 ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
539 /* try some invalid records */
540 r = MsiViewModify(hview, MSIMODIFY_INSERT, 0 );
541 ok(r == ERROR_INVALID_HANDLE, "MsiViewModify failed\n");
542 r = MsiViewModify(hview, -1, 0 );
543 ok(r == ERROR_INVALID_HANDLE, "MsiViewModify failed\n");
545 /* try an small record */
546 hrec = MsiCreateRecord(1);
547 r = MsiViewModify(hview, -1, hrec );
548 ok(r == ERROR_INVALID_DATA, "MsiViewModify failed\n");
550 r = MsiCloseHandle(hrec);
551 ok(r == ERROR_SUCCESS, "failed to close record\n");
553 /* insert a valid record */
554 hrec = MsiCreateRecord(3);
556 r = MsiRecordSetInteger(hrec, 2, 1);
557 ok(r == ERROR_SUCCESS, "failed to set integer\n");
558 r = MsiRecordSetString(hrec, 2, "bob");
559 ok(r == ERROR_SUCCESS, "failed to set integer\n");
560 r = MsiRecordSetString(hrec, 3, "7654321");
561 ok(r == ERROR_SUCCESS, "failed to set integer\n");
563 r = MsiViewExecute(hview, 0);
564 ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
565 r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec );
566 ok(r == ERROR_SUCCESS, "MsiViewModify failed\n");
568 /* insert the same thing again */
569 r = MsiViewExecute(hview, 0);
570 ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
572 /* should fail ... */
573 todo_wine {
574 r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec );
575 ok(r == ERROR_FUNCTION_FAILED, "MsiViewModify failed\n");
578 r = MsiCloseHandle(hrec);
579 ok(r == ERROR_SUCCESS, "failed to close record\n");
581 r = MsiViewClose(hview);
582 ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
583 r = MsiCloseHandle(hview);
584 ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
586 r = MsiCloseHandle( hdb );
587 ok(r == ERROR_SUCCESS, "MsiOpenDatabase close failed\n");
590 static MSIHANDLE create_db(void)
592 MSIHANDLE hdb = 0;
593 UINT res;
595 DeleteFile(msifile);
597 /* create an empty database */
598 res = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb );
599 ok( res == ERROR_SUCCESS , "Failed to create database\n" );
600 if( res != ERROR_SUCCESS )
601 return hdb;
603 res = MsiDatabaseCommit( hdb );
604 ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
606 return hdb;
609 static void test_getcolinfo(void)
611 MSIHANDLE hdb, hview = 0, rec = 0;
612 UINT r;
613 DWORD sz;
614 char buffer[0x20];
616 /* create an empty db */
617 hdb = create_db();
618 ok( hdb, "failed to create db\n");
620 /* tables should be present */
621 r = MsiDatabaseOpenView(hdb, "select * from _Tables", &hview);
622 ok( r == ERROR_SUCCESS, "failed to open query\n");
624 r = MsiViewExecute(hview, 0);
625 ok( r == ERROR_SUCCESS, "failed to execute query\n");
627 /* check that NAMES works */
628 rec = 0;
629 r = MsiViewGetColumnInfo( hview, MSICOLINFO_NAMES, &rec );
630 ok( r == ERROR_SUCCESS, "failed to get names\n");
631 sz = sizeof buffer;
632 r = MsiRecordGetString(rec, 1, buffer, &sz );
633 ok( r == ERROR_SUCCESS, "failed to get string\n");
634 ok( !strcmp(buffer,"Name"), "_Tables has wrong column name\n");
635 r = MsiCloseHandle( rec );
636 ok( r == ERROR_SUCCESS, "failed to close record handle\n");
638 /* check that TYPES works */
639 rec = 0;
640 r = MsiViewGetColumnInfo( hview, MSICOLINFO_TYPES, &rec );
641 ok( r == ERROR_SUCCESS, "failed to get names\n");
642 sz = sizeof buffer;
643 r = MsiRecordGetString(rec, 1, buffer, &sz );
644 ok( r == ERROR_SUCCESS, "failed to get string\n");
645 ok( !strcmp(buffer,"s64"), "_Tables has wrong column type\n");
646 r = MsiCloseHandle( rec );
647 ok( r == ERROR_SUCCESS, "failed to close record handle\n");
649 /* check that invalid values fail */
650 rec = 0;
651 r = MsiViewGetColumnInfo( hview, 100, &rec );
652 ok( r == ERROR_INVALID_PARAMETER, "wrong error code\n");
653 ok( rec == 0, "returned a record\n");
655 r = MsiViewGetColumnInfo( hview, MSICOLINFO_TYPES, NULL );
656 ok( r == ERROR_INVALID_PARAMETER, "wrong error code\n");
658 r = MsiViewGetColumnInfo( 0, MSICOLINFO_TYPES, &rec );
659 ok( r == ERROR_INVALID_HANDLE, "wrong error code\n");
661 r = MsiViewClose(hview);
662 ok( r == ERROR_SUCCESS, "failed to close view\n");
663 r = MsiCloseHandle(hview);
664 ok( r == ERROR_SUCCESS, "failed to close view handle\n");
665 r = MsiCloseHandle(hdb);
666 ok( r == ERROR_SUCCESS, "failed to close database\n");
669 static MSIHANDLE get_column_info(MSIHANDLE hdb, const char *query, MSICOLINFO type)
671 MSIHANDLE hview = 0, rec = 0;
672 UINT r;
674 r = MsiDatabaseOpenView(hdb, query, &hview);
675 if( r != ERROR_SUCCESS )
676 return r;
678 r = MsiViewExecute(hview, 0);
679 if( r == ERROR_SUCCESS )
681 MsiViewGetColumnInfo( hview, type, &rec );
682 MsiViewClose(hview);
684 MsiCloseHandle(hview);
685 return rec;
688 static UINT get_columns_table_type(MSIHANDLE hdb, const char *table, UINT field)
690 MSIHANDLE hview = 0, rec = 0;
691 UINT r, type = 0;
692 char query[0x100];
694 sprintf(query, "select * from `_Columns` where `Table` = '%s'", table );
696 r = MsiDatabaseOpenView(hdb, query, &hview);
697 if( r != ERROR_SUCCESS )
698 return r;
700 r = MsiViewExecute(hview, 0);
701 if( r == ERROR_SUCCESS )
703 while (1)
705 r = MsiViewFetch( hview, &rec );
706 if( r != ERROR_SUCCESS)
707 break;
708 r = MsiRecordGetInteger( rec, 2 );
709 if (r == field)
710 type = MsiRecordGetInteger( rec, 4 );
711 MsiCloseHandle( rec );
714 MsiViewClose(hview);
716 MsiCloseHandle(hview);
717 return type;
720 static BOOL check_record( MSIHANDLE rec, UINT field, LPCSTR val )
722 CHAR buffer[0x20];
723 UINT r;
724 DWORD sz;
726 sz = sizeof buffer;
727 r = MsiRecordGetString( rec, field, buffer, &sz );
728 return (r == ERROR_SUCCESS ) && !strcmp(val, buffer);
731 static void test_viewgetcolumninfo(void)
733 MSIHANDLE hdb = 0, rec;
734 UINT r;
736 hdb = create_db();
737 ok( hdb, "failed to create db\n");
739 r = run_query( hdb, 0,
740 "CREATE TABLE `Properties` "
741 "( `Property` CHAR(255), `Value` CHAR(1) PRIMARY KEY `Property`)" );
742 ok( r == ERROR_SUCCESS , "Failed to create table\n" );
744 /* check the column types */
745 rec = get_column_info( hdb, "select * from `Properties`", MSICOLINFO_TYPES );
746 ok( rec, "failed to get column info record\n" );
748 ok( check_record( rec, 1, "S255"), "wrong record type\n");
749 ok( check_record( rec, 2, "S1"), "wrong record type\n");
751 MsiCloseHandle( rec );
753 /* check the type in _Columns */
754 ok( 0x3dff == get_columns_table_type(hdb, "Properties", 1 ), "_columns table wrong\n");
755 ok( 0x1d01 == get_columns_table_type(hdb, "Properties", 2 ), "_columns table wrong\n");
757 /* now try the names */
758 rec = get_column_info( hdb, "select * from `Properties`", MSICOLINFO_NAMES );
759 ok( rec, "failed to get column info record\n" );
761 ok( check_record( rec, 1, "Property"), "wrong record type\n");
762 ok( check_record( rec, 2, "Value"), "wrong record type\n");
764 MsiCloseHandle( rec );
766 r = run_query( hdb, 0,
767 "CREATE TABLE `Binary` "
768 "( `Name` CHAR(255), `Data` OBJECT PRIMARY KEY `Name`)" );
769 ok( r == ERROR_SUCCESS , "Failed to create table\n" );
771 /* check the column types */
772 rec = get_column_info( hdb, "select * from `Binary`", MSICOLINFO_TYPES );
773 ok( rec, "failed to get column info record\n" );
775 ok( check_record( rec, 1, "S255"), "wrong record type\n");
776 ok( check_record( rec, 2, "V0"), "wrong record type\n");
778 MsiCloseHandle( rec );
780 /* check the type in _Columns */
781 ok( 0x3dff == get_columns_table_type(hdb, "Binary", 1 ), "_columns table wrong\n");
782 ok( 0x1900 == get_columns_table_type(hdb, "Binary", 2 ), "_columns table wrong\n");
784 /* now try the names */
785 rec = get_column_info( hdb, "select * from `Binary`", MSICOLINFO_NAMES );
786 ok( rec, "failed to get column info record\n" );
788 ok( check_record( rec, 1, "Name"), "wrong record type\n");
789 ok( check_record( rec, 2, "Data"), "wrong record type\n");
790 MsiCloseHandle( rec );
792 r = run_query( hdb, 0,
793 "CREATE TABLE `UIText` "
794 "( `Key` CHAR(72) NOT NULL, `Text` CHAR(255) LOCALIZABLE PRIMARY KEY `Key`)" );
795 ok( r == ERROR_SUCCESS , "Failed to create table\n" );
797 ok( 0x2d48 == get_columns_table_type(hdb, "UIText", 1 ), "_columns table wrong\n");
798 ok( 0x1fff == get_columns_table_type(hdb, "UIText", 2 ), "_columns table wrong\n");
800 rec = get_column_info( hdb, "select * from `UIText`", MSICOLINFO_NAMES );
801 ok( rec, "failed to get column info record\n" );
802 ok( check_record( rec, 1, "Key"), "wrong record type\n");
803 ok( check_record( rec, 2, "Text"), "wrong record type\n");
804 MsiCloseHandle( rec );
806 rec = get_column_info( hdb, "select * from `UIText`", MSICOLINFO_TYPES );
807 ok( rec, "failed to get column info record\n" );
808 ok( check_record( rec, 1, "s72"), "wrong record type\n");
809 ok( check_record( rec, 2, "L255"), "wrong record type\n");
810 MsiCloseHandle( rec );
812 MsiCloseHandle( hdb );
815 static void test_msiexport(void)
817 MSIHANDLE hdb = 0, hview = 0;
818 UINT r;
819 const char *query;
820 char path[MAX_PATH];
821 const char file[] = "phone.txt";
822 HANDLE handle;
823 char buffer[0x100];
824 DWORD length;
825 const char expected[] =
826 "id\tname\tnumber\r\n"
827 "I2\tS32\tS32\r\n"
828 "phone\tid\r\n"
829 "1\tAbe\t8675309\r\n";
831 DeleteFile(msifile);
833 /* just MsiOpenDatabase should not create a file */
834 r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
835 ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
837 /* create a table */
838 query = "CREATE TABLE `phone` ( "
839 "`id` INT, `name` CHAR(32), `number` CHAR(32) "
840 "PRIMARY KEY `id`)";
841 r = MsiDatabaseOpenView(hdb, query, &hview);
842 ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
843 r = MsiViewExecute(hview, 0);
844 ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
845 r = MsiViewClose(hview);
846 ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
847 r = MsiCloseHandle(hview);
848 ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
850 /* insert a value into it */
851 query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
852 "VALUES('1', 'Abe', '8675309')";
853 r = MsiDatabaseOpenView(hdb, query, &hview);
854 ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
855 r = MsiViewExecute(hview, 0);
856 ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
857 r = MsiViewClose(hview);
858 ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
859 r = MsiCloseHandle(hview);
860 ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
862 GetCurrentDirectory(MAX_PATH, path);
864 todo_wine {
865 r = MsiDatabaseExport(hdb, "phone", path, file);
866 ok(r == ERROR_SUCCESS, "MsiDatabaseExport failed\n");
868 MsiCloseHandle(hdb);
870 lstrcat(path, "\\");
871 lstrcat(path, file);
873 /* check the data that was written */
874 length = 0;
875 memset(buffer, 0, sizeof buffer);
876 handle = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
877 if (handle != INVALID_HANDLE_VALUE)
879 ReadFile(handle, buffer, sizeof buffer, &length, NULL);
880 CloseHandle(handle);
881 DeleteFile(path);
883 else
884 ok(0, "failed to open file %s\n", path);
886 ok( length == strlen(expected), "length of data wrong\n");
887 ok( !lstrcmp(buffer, expected), "data doesn't match\n");
889 DeleteFile(msifile);
892 static void test_longstrings(void)
894 const char insert_query[] =
895 "INSERT INTO `strings` ( `id`, `val` ) VALUES('1', 'Z')";
896 char *str;
897 MSIHANDLE hdb = 0, hview = 0, hrec = 0;
898 DWORD len;
899 UINT r;
900 const DWORD STRING_LENGTH = 0x10005;
902 DeleteFile(msifile);
903 /* just MsiOpenDatabase should not create a file */
904 r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
905 ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
907 /* create a table */
908 r = try_query( hdb,
909 "CREATE TABLE `strings` ( `id` INT, `val` CHAR(0) PRIMARY KEY `id`)");
910 ok(r == ERROR_SUCCESS, "query failed\n");
912 /* try a insert a very long string */
913 str = HeapAlloc(GetProcessHeap(), 0, STRING_LENGTH+sizeof insert_query);
914 len = strchr(insert_query, 'Z') - insert_query;
915 strcpy(str, insert_query);
916 memset(str+len, 'Z', STRING_LENGTH);
917 strcpy(str+len+STRING_LENGTH, insert_query+len+1);
918 r = try_query( hdb, str );
919 ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
921 HeapFree(GetProcessHeap(), 0, str);
923 MsiDatabaseCommit(hdb);
924 ok(r == ERROR_SUCCESS, "MsiDatabaseCommit failed\n");
925 MsiCloseHandle(hdb);
927 r = MsiOpenDatabase(msifile, MSIDBOPEN_READONLY, &hdb);
928 ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
930 r = MsiDatabaseOpenView(hdb, "select * from `strings` where `id` = 1", &hview);
931 ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
933 r = MsiViewExecute(hview, 0);
934 ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
936 r = MsiViewFetch(hview, &hrec);
937 ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
939 MsiCloseHandle(hview);
941 r = MsiRecordGetString(hrec, 2, NULL, &len);
942 ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
943 ok(len == STRING_LENGTH, "string length wrong\n");
945 MsiCloseHandle(hrec);
946 MsiCloseHandle(hdb);
947 DeleteFile(msifile);
950 static void test_streamtable(void)
952 MSIHANDLE hdb = 0, rec;
953 UINT r;
955 hdb = create_db();
956 ok( hdb, "failed to create db\n");
958 r = run_query( hdb, 0,
959 "CREATE TABLE `Properties` "
960 "( `Property` CHAR(255), `Value` CHAR(1) PRIMARY KEY `Property`)" );
961 ok( r == ERROR_SUCCESS , "Failed to create table\n" );
963 /* check the column types */
964 rec = get_column_info( hdb, "select * from `_Streams`", MSICOLINFO_TYPES );
965 ok( rec, "failed to get column info record\n" );
967 todo_wine {
968 ok( check_record( rec, 1, "s62"), "wrong record type\n");
969 ok( check_record( rec, 2, "V0"), "wrong record type\n");
972 MsiCloseHandle( rec );
974 /* now try the names */
975 rec = get_column_info( hdb, "select * from `_Streams`", MSICOLINFO_NAMES );
976 ok( rec, "failed to get column info record\n" );
978 todo_wine {
979 ok( check_record( rec, 1, "Name"), "wrong record type\n");
980 ok( check_record( rec, 2, "Data"), "wrong record type\n");
983 MsiCloseHandle( rec );
984 MsiCloseHandle( hdb );
985 DeleteFile(msifile);
988 static void test_where(void)
990 MSIHANDLE hdb = 0, rec;
991 LPCSTR query;
992 UINT r;
994 hdb = create_db();
995 ok( hdb, "failed to create db\n");
997 r = run_query( hdb, 0,
998 "CREATE TABLE `Media` ("
999 "`DiskId` SHORT NOT NULL, "
1000 "`LastSequence` LONG, "
1001 "`DiskPrompt` CHAR(64) LOCALIZABLE, "
1002 "`Cabinet` CHAR(255), "
1003 "`VolumeLabel` CHAR(32), "
1004 "`Source` CHAR(72) "
1005 "PRIMARY KEY `DiskId`)" );
1006 ok( r == S_OK, "cannot create Media table: %d\n", r );
1008 r = run_query( hdb, 0, "INSERT INTO `Media` "
1009 "( `DiskId`, `LastSequence`, `DiskPrompt`, `Cabinet`, `VolumeLabel`, `Source` ) "
1010 "VALUES ( 1, 0, '', 'zero.cab', '', '' )" );
1011 ok( r == S_OK, "cannot add file to the Media table: %d\n", r );
1013 r = run_query( hdb, 0, "INSERT INTO `Media` "
1014 "( `DiskId`, `LastSequence`, `DiskPrompt`, `Cabinet`, `VolumeLabel`, `Source` ) "
1015 "VALUES ( 2, 1, '', 'one.cab', '', '' )" );
1016 ok( r == S_OK, "cannot add file to the Media table: %d\n", r );
1018 r = run_query( hdb, 0, "INSERT INTO `Media` "
1019 "( `DiskId`, `LastSequence`, `DiskPrompt`, `Cabinet`, `VolumeLabel`, `Source` ) "
1020 "VALUES ( 3, 2, '', 'two.cab', '', '' )" );
1021 ok( r == S_OK, "cannot add file to the Media table: %d\n", r );
1023 query = "SELECT * FROM `Media`";
1024 r = do_query(hdb, query, &rec);
1025 ok(r == ERROR_SUCCESS, "MsiViewFetch failed: %d\n", r);
1026 ok( check_record( rec, 4, "zero.cab"), "wrong cabinet\n");
1027 MsiCloseHandle( rec );
1029 query = "SELECT * FROM `Media` WHERE `LastSequence` >= 1";
1030 r = do_query(hdb, query, &rec);
1031 ok(r == ERROR_SUCCESS, "MsiViewFetch failed: %d\n", r);
1032 ok( check_record( rec, 4, "one.cab"), "wrong cabinet\n");
1034 r = MsiRecordGetInteger(rec, 1);
1035 ok( 2 == r, "field wrong\n");
1036 r = MsiRecordGetInteger(rec, 2);
1037 ok( 1 == r, "field wrong\n");
1039 MsiCloseHandle( rec );
1041 MsiCloseHandle( hdb );
1042 DeleteFile(msifile);
1045 static CHAR CURR_DIR[MAX_PATH];
1047 static const CHAR test_data[] = "FirstPrimaryColumn\tSecondPrimaryColumn\tShortInt\tShortIntNullable\tLongInt\tLongIntNullable\tString\tLocalizableString\tLocalizableStringNullable\n"
1048 "s255\ti2\ti2\tI2\ti4\tI4\tS255\tS0\ts0\n"
1049 "TestTable\tFirstPrimaryColumn\n"
1050 "stringage\t5\t2\t\t2147483640\t-2147483640\tanother string\tlocalizable\tduh\n";
1052 static void write_file(const CHAR *filename, const char *data, int data_size)
1054 DWORD size;
1056 HANDLE hf = CreateFile(filename, GENERIC_WRITE, 0, NULL,
1057 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1059 WriteFile(hf, data, data_size, &size, NULL);
1060 CloseHandle(hf);
1063 static UINT add_table_to_db(MSIHANDLE hdb, LPCSTR table_data)
1065 UINT r;
1067 write_file("temp_file", table_data, (lstrlen(table_data) - 1) * sizeof(char));
1068 r = MsiDatabaseImportA(hdb, CURR_DIR, "temp_file");
1069 DeleteFileA("temp_file");
1071 return r;
1074 static void test_msiimport(void)
1076 MSIHANDLE hdb, view, rec;
1077 LPCSTR query;
1078 UINT r, count;
1079 signed int i;
1081 GetCurrentDirectoryA(MAX_PATH, CURR_DIR);
1083 r = MsiOpenDatabaseA(msifile, MSIDBOPEN_CREATE, &hdb);
1084 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1086 r = add_table_to_db(hdb, test_data);
1087 todo_wine
1089 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1092 query = "SELECT * FROM `TestTable`";
1093 r = MsiDatabaseOpenView(hdb, query, &view);
1094 todo_wine
1096 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1099 r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec);
1100 count = MsiRecordGetFieldCount(rec);
1101 todo_wine
1103 ok(count == 9, "Expected 9, got %d\n", count);
1104 ok(check_record(rec, 1, "FirstPrimaryColumn"), "Expected FirstPrimaryColumn\n");
1105 ok(check_record(rec, 2, "SecondPrimaryColumn"), "Expected SecondPrimaryColumn\n");
1106 ok(check_record(rec, 3, "ShortInt"), "Expected ShortInt\n");
1107 ok(check_record(rec, 4, "ShortIntNullable"), "Expected ShortIntNullalble\n");
1108 ok(check_record(rec, 5, "LongInt"), "Expected LongInt\n");
1109 ok(check_record(rec, 6, "LongIntNullable"), "Expected LongIntNullalble\n");
1110 ok(check_record(rec, 7, "String"), "Expected String\n");
1111 ok(check_record(rec, 8, "LocalizableString"), "Expected LocalizableString\n");
1112 ok(check_record(rec, 9, "LocalizableStringNullable"), "Expected LocalizableStringNullable\n");
1115 r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
1116 count = MsiRecordGetFieldCount(rec);
1117 todo_wine
1119 ok(count == 9, "Expected 9, got %d\n", count);
1120 ok(check_record(rec, 1, "s255"), "Expected s255\n");
1121 ok(check_record(rec, 2, "i2"), "Expected i2\n");
1122 ok(check_record(rec, 3, "i2"), "Expected i2\n");
1123 ok(check_record(rec, 4, "I2"), "Expected I2\n");
1124 ok(check_record(rec, 5, "i4"), "Expected i4\n");
1125 ok(check_record(rec, 6, "I4"), "Expected I4\n");
1126 ok(check_record(rec, 7, "S255"), "Expected S255\n");
1127 ok(check_record(rec, 8, "S0"), "Expected S0\n");
1128 ok(check_record(rec, 9, "s0"), "Expected s0\n");
1131 query = "SELECT * FROM `TestTable`";
1132 r = do_query(hdb, query, &rec);
1133 todo_wine
1135 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1138 todo_wine
1140 ok(check_record(rec, 1, "stringage"), "Expected 'stringage'\n");
1141 ok(check_record(rec, 7, "another string"), "Expected 'another string'\n");
1142 ok(check_record(rec, 8, "localizable"), "Expected 'localizable'\n");
1143 ok(check_record(rec, 9, "duh"), "Expected 'duh'\n");
1146 i = MsiRecordGetInteger(rec, 2);
1147 todo_wine
1149 ok(i == 5, "Expected 5, got %d\n", i);
1152 i = MsiRecordGetInteger(rec, 3);
1153 todo_wine
1155 ok(i == 2, "Expected 2, got %d\n", i);
1158 i = MsiRecordGetInteger(rec, 4);
1159 ok(i == 0x80000000, "Expected 0x80000000, got %d\n", i);
1161 i = MsiRecordGetInteger(rec, 5);
1162 todo_wine
1164 ok(i == 2147483640, "Expected 2147483640, got %d\n", i);
1167 i = MsiRecordGetInteger(rec, 6);
1168 todo_wine
1170 ok(i == -2147483640, "Expected -2147483640, got %d\n", i);
1173 MsiCloseHandle(rec);
1174 MsiCloseHandle(view);
1175 MsiCloseHandle(hdb);
1176 DeleteFileA(msifile);
1179 static void test_markers(void)
1181 MSIHANDLE hdb, rec;
1182 LPCSTR query;
1183 UINT r;
1185 hdb = create_db();
1186 ok( hdb, "failed to create db\n");
1188 rec = MsiCreateRecord(3);
1189 MsiRecordSetString(rec, 1, "Table");
1190 MsiRecordSetString(rec, 2, "Apples");
1191 MsiRecordSetString(rec, 3, "Oranges");
1193 /* try a legit create */
1194 query = "CREATE TABLE `Table` ( `One` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`)";
1195 r = run_query(hdb, 0, query);
1196 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1197 MsiCloseHandle(rec);
1199 /* try table name as marker */
1200 rec = MsiCreateRecord(1);
1201 MsiRecordSetString(rec, 1, "Fable");
1202 query = "CREATE TABLE `?` ( `One` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`)";
1203 r = run_query(hdb, rec, query);
1204 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1206 /* try table name as marker without backticks */
1207 MsiRecordSetString(rec, 1, "Mable");
1208 query = "CREATE TABLE ? ( `One` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`)";
1209 r = run_query(hdb, rec, query);
1210 ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
1212 /* try one column name as marker */
1213 MsiRecordSetString(rec, 1, "One");
1214 query = "CREATE TABLE `Mable` ( `?` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`)";
1215 r = run_query(hdb, rec, query);
1216 ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
1218 /* try column names as markers */
1219 MsiCloseHandle(rec);
1220 rec = MsiCreateRecord(2);
1221 MsiRecordSetString(rec, 1, "One");
1222 MsiRecordSetString(rec, 2, "Two");
1223 query = "CREATE TABLE `Mable` ( `?` SHORT NOT NULL, `?` CHAR(255) PRIMARY KEY `One`)";
1224 r = run_query(hdb, rec, query);
1225 ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
1227 /* try names with backticks */
1228 MsiCloseHandle(rec);
1229 rec = MsiCreateRecord(3);
1230 MsiRecordSetString(rec, 1, "One");
1231 MsiRecordSetString(rec, 2, "Two");
1232 MsiRecordSetString(rec, 3, "One");
1233 query = "CREATE TABLE `Mable` ( `?` SHORT NOT NULL, `?` CHAR(255) PRIMARY KEY `?`)";
1234 r = run_query(hdb, rec, query);
1235 todo_wine
1237 ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
1240 /* try names with backticks, minus definitions */
1241 query = "CREATE TABLE `Mable` ( `?`, `?` PRIMARY KEY `?`)";
1242 r = run_query(hdb, rec, query);
1243 ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
1245 /* try names without backticks */
1246 query = "CREATE TABLE `Mable` ( ? SHORT NOT NULL, ? CHAR(255) PRIMARY KEY ?)";
1247 r = run_query(hdb, rec, query);
1248 ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
1250 /* try one long marker */
1251 MsiCloseHandle(rec);
1252 rec = MsiCreateRecord(1);
1253 MsiRecordSetString(rec, 1, "`One` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`");
1254 query = "CREATE TABLE `Mable` ( ? )";
1255 r = run_query(hdb, rec, query);
1256 ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
1258 /* try all names as markers */
1259 MsiCloseHandle(rec);
1260 rec = MsiCreateRecord(4);
1261 MsiRecordSetString(rec, 1, "Mable");
1262 MsiRecordSetString(rec, 2, "One");
1263 MsiRecordSetString(rec, 3, "Two");
1264 MsiRecordSetString(rec, 4, "One");
1265 query = "CREATE TABLE `?` ( `?` SHORT NOT NULL, `?` CHAR(255) PRIMARY KEY `?`)";
1266 r = run_query(hdb, rec, query);
1267 ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
1269 /* try a legit insert */
1270 query = "INSERT INTO `Table` ( `One`, `Two` ) VALUES ( 5, 'hello' )";
1271 r = run_query(hdb, 0, query);
1272 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1274 /* try values as markers */
1275 MsiCloseHandle(rec);
1276 rec = MsiCreateRecord(2);
1277 MsiRecordSetInteger(rec, 1, 4);
1278 MsiRecordSetString(rec, 2, "hi");
1279 query = "INSERT INTO `Table` ( `One`, `Two` ) VALUES ( ?, '?' )";
1280 r = run_query(hdb, rec, query);
1281 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1283 /* try column names and values as markers */
1284 MsiCloseHandle(rec);
1285 rec = MsiCreateRecord(4);
1286 MsiRecordSetString(rec, 1, "One");
1287 MsiRecordSetString(rec, 2, "Two");
1288 MsiRecordSetInteger(rec, 3, 5);
1289 MsiRecordSetString(rec, 4, "hi");
1290 query = "INSERT INTO `Table` ( `?`, `?` ) VALUES ( ?, '?' )";
1291 r = run_query(hdb, rec, query);
1292 ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
1294 /* try column names as markers */
1295 MsiCloseHandle(rec);
1296 rec = MsiCreateRecord(2);
1297 MsiRecordSetString(rec, 1, "One");
1298 MsiRecordSetString(rec, 2, "Two");
1299 query = "INSERT INTO `Table` ( `?`, `?` ) VALUES ( 3, 'yellow' )";
1300 r = run_query(hdb, rec, query);
1301 ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
1303 /* try table name as a marker */
1304 MsiCloseHandle(rec);
1305 rec = MsiCreateRecord(1);
1306 MsiRecordSetString(rec, 1, "Table");
1307 query = "INSERT INTO `?` ( `One`, `Two` ) VALUES ( 2, 'green' )";
1308 r = run_query(hdb, rec, query);
1309 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1311 /* try table name and values as markers */
1312 MsiCloseHandle(rec);
1313 rec = MsiCreateRecord(3);
1314 MsiRecordSetString(rec, 1, "Table");
1315 MsiRecordSetInteger(rec, 2, 10);
1316 MsiRecordSetString(rec, 3, "haha");
1317 query = "INSERT INTO `?` ( `One`, `Two` ) VALUES ( ?, '?' )";
1318 r = run_query(hdb, rec, query);
1319 todo_wine
1321 ok(r == ERROR_FUNCTION_FAILED, "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
1324 /* try all markers */
1325 MsiCloseHandle(rec);
1326 rec = MsiCreateRecord(5);
1327 MsiRecordSetString(rec, 1, "Table");
1328 MsiRecordSetString(rec, 1, "One");
1329 MsiRecordSetString(rec, 1, "Two");
1330 MsiRecordSetInteger(rec, 2, 10);
1331 MsiRecordSetString(rec, 3, "haha");
1332 query = "INSERT INTO `?` ( `?`, `?` ) VALUES ( ?, '?' )";
1333 r = run_query(hdb, rec, query);
1334 ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
1336 /* insert an integer as a string */
1337 MsiCloseHandle(rec);
1338 rec = MsiCreateRecord(2);
1339 MsiRecordSetString(rec, 1, "11");
1340 MsiRecordSetString(rec, 2, "hi");
1341 query = "INSERT INTO `Table` ( `One`, `Two` ) VALUES ( ?, '?' )";
1342 r = run_query(hdb, rec, query);
1343 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1345 /* leave off the '' for the string */
1346 MsiCloseHandle(rec);
1347 rec = MsiCreateRecord(2);
1348 MsiRecordSetInteger(rec, 1, 12);
1349 MsiRecordSetString(rec, 2, "hi");
1350 query = "INSERT INTO `Table` ( `One`, `Two` ) VALUES ( ?, ? )";
1351 r = run_query(hdb, rec, query);
1352 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1353 MsiCloseHandle(rec);
1355 MsiCloseHandle(hdb);
1356 DeleteFileA(msifile);
1359 #define MY_NVIEWS 4000 /* Largest installer I've seen uses < 2k */
1360 static void test_handle_limit(void)
1362 int i;
1363 MSIHANDLE hdb;
1364 MSIHANDLE hviews[MY_NVIEWS];
1365 UINT r;
1367 /* create an empty db */
1368 hdb = create_db();
1369 ok( hdb, "failed to create db\n");
1371 memset(hviews, 0, sizeof(hviews));
1373 for (i=0; i<MY_NVIEWS; i++) {
1374 static char szQueryBuf[256] = "SELECT * from `_Tables`";
1375 hviews[i] = 0xdeadbeeb;
1376 r = MsiDatabaseOpenView(hdb, szQueryBuf, &hviews[i]);
1377 ok( r == ERROR_SUCCESS, "failed to open query %d\n", i);
1378 ok( hviews[i] != 0xdeadbeeb, "no handle set\n");
1379 if (i < 0xef)
1380 ok( hviews[i] != 0, "%d'th handle is NULL\n", i);
1381 else
1382 todo_wine {
1383 ok( hviews[i] != 0, "%d'th handle is NULL\n", i);
1385 if (!hviews[i])
1386 break;
1387 ok( (i == 0 || (hviews[i] != hviews[i-1])),
1388 "got handle %p twice\n", (void *) hviews[i] );
1391 for (i=0; i<MY_NVIEWS; i++) {
1392 if (hviews[i] != 0 && hviews[i] != 0xdeadbeeb) {
1393 r = MsiCloseHandle(hviews[i]);
1394 ok( r == ERROR_SUCCESS, "failed to close view handle %d\n", i);
1398 r = MsiCloseHandle(hdb);
1399 ok( r == ERROR_SUCCESS, "failed to close database\n");
1402 START_TEST(db)
1404 test_msidatabase();
1405 test_msiinsert();
1406 test_msidecomposedesc();
1407 test_msibadqueries();
1408 test_viewmodify();
1409 test_viewgetcolumninfo();
1410 test_getcolinfo();
1411 test_msiexport();
1412 test_longstrings();
1413 test_streamtable();
1414 test_where();
1415 test_msiimport();
1416 test_markers();
1417 test_handle_limit();