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
26 #include "wine/test.h"
28 static const char *msifile
= "winetest.msi";
30 static void test_msidatabase(void)
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
)
56 /* open a select query */
57 r
= MsiDatabaseOpenView(hdb
, query
, &hview
);
58 if (r
!= ERROR_SUCCESS
)
60 r
= MsiViewExecute(hview
, 0);
61 if (r
!= ERROR_SUCCESS
)
63 ret
= MsiViewFetch(hview
, phrec
);
64 r
= MsiViewClose(hview
);
65 if (r
!= ERROR_SUCCESS
)
67 r
= MsiCloseHandle(hview
);
68 if (r
!= ERROR_SUCCESS
)
73 static void test_msiinsert(void)
75 MSIHANDLE hdb
= 0, hview
= 0, hrec
= 0;
83 /* just MsiOpenDatabase should not create a file */
84 r
= MsiOpenDatabase(msifile
, MSIDBOPEN_CREATE
, &hdb
);
85 ok(r
== ERROR_SUCCESS
, "MsiOpenDatabase failed\n");
88 query
= "CREATE TABLE `phone` ( "
89 "`id` INT, `name` CHAR(32), `number` CHAR(32) "
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");
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");
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");
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 */
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");
166 /* now try a few bad INSERT xqueries */
167 query
= "INSERT INTO `phone` ( `id`, `name`, `number` )"
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` )"
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];
227 hmod
= GetModuleHandle("msi.dll");
230 pMsiDecomposeDescriptorA
= (fnMsiDecomposeDescriptorA
)
231 GetProcAddress(hmod
, "MsiDecomposeDescriptorA");
232 if (!pMsiDecomposeDescriptorA
)
235 /* test a valid feature descriptor */
236 desc
= "']gAVn-}f(ZXfeAR6.jiFollowTheWhiteRabbit>3w2x^IGfe?CxI5heAvk.";
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.";
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."
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");
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");
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");
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");
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
)
292 res
= MsiDatabaseOpenView( hdb
, szQuery
, &htab
);
293 if(res
== ERROR_SUCCESS
)
297 r
= MsiViewExecute( htab
, hrec
);
298 if(r
!= ERROR_SUCCESS
)
301 r
= MsiViewClose( htab
);
302 if(r
!= ERROR_SUCCESS
)
305 r
= MsiCloseHandle( htab
);
306 if(r
!= ERROR_SUCCESS
)
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
)
322 hrec
= MsiCreateRecord( 1 );
323 MsiRecordSetString( hrec
, 1, "Hello");
325 r
= try_query_param( hdb
, szQuery
, hrec
);
327 MsiCloseHandle( hrec
);
331 static void test_msibadqueries(void)
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 "
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
)
465 r
= MsiDatabaseOpenView(hdb
, query
, &hview
);
466 if( r
!= ERROR_SUCCESS
)
469 r
= MsiViewExecute(hview
, hrec
);
470 if( r
== ERROR_SUCCESS
)
471 r
= MsiViewClose(hview
);
472 MsiCloseHandle(hview
);
476 static void test_viewmodify(void)
478 MSIHANDLE hdb
= 0, hview
= 0, hrec
= 0;
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) "
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 */
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");
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 */
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 */
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 */
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 ... */
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)
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
)
603 res
= MsiDatabaseCommit( hdb
);
604 ok( res
== ERROR_SUCCESS
, "Failed to commit database\n" );
609 static void test_getcolinfo(void)
611 MSIHANDLE hdb
, hview
= 0, rec
= 0;
616 /* create an empty 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 */
629 r
= MsiViewGetColumnInfo( hview
, MSICOLINFO_NAMES
, &rec
);
630 ok( r
== ERROR_SUCCESS
, "failed to get names\n");
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 */
640 r
= MsiViewGetColumnInfo( hview
, MSICOLINFO_TYPES
, &rec
);
641 ok( r
== ERROR_SUCCESS
, "failed to get names\n");
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 */
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;
674 r
= MsiDatabaseOpenView(hdb
, query
, &hview
);
675 if( r
!= ERROR_SUCCESS
)
678 r
= MsiViewExecute(hview
, 0);
679 if( r
== ERROR_SUCCESS
)
681 MsiViewGetColumnInfo( hview
, type
, &rec
);
684 MsiCloseHandle(hview
);
688 static UINT
get_columns_table_type(MSIHANDLE hdb
, const char *table
, UINT field
)
690 MSIHANDLE hview
= 0, rec
= 0;
694 sprintf(query
, "select * from `_Columns` where `Table` = '%s'", table
);
696 r
= MsiDatabaseOpenView(hdb
, query
, &hview
);
697 if( r
!= ERROR_SUCCESS
)
700 r
= MsiViewExecute(hview
, 0);
701 if( r
== ERROR_SUCCESS
)
705 r
= MsiViewFetch( hview
, &rec
);
706 if( r
!= ERROR_SUCCESS
)
708 r
= MsiRecordGetInteger( rec
, 2 );
710 type
= MsiRecordGetInteger( rec
, 4 );
711 MsiCloseHandle( rec
);
716 MsiCloseHandle(hview
);
720 static BOOL
check_record( MSIHANDLE rec
, UINT field
, LPCSTR val
)
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
;
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;
821 const char file
[] = "phone.txt";
825 const char expected
[] =
826 "id\tname\tnumber\r\n"
829 "1\tAbe\t8675309\r\n";
833 /* just MsiOpenDatabase should not create a file */
834 r
= MsiOpenDatabase(msifile
, MSIDBOPEN_CREATE
, &hdb
);
835 ok(r
== ERROR_SUCCESS
, "MsiOpenDatabase failed\n");
838 query
= "CREATE TABLE `phone` ( "
839 "`id` INT, `name` CHAR(32), `number` CHAR(32) "
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
);
865 r
= MsiDatabaseExport(hdb
, "phone", path
, file
);
866 ok(r
== ERROR_SUCCESS
, "MsiDatabaseExport failed\n");
873 /* check the data that was written */
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
);
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");
892 static void test_longstrings(void)
894 const char insert_query
[] =
895 "INSERT INTO `strings` ( `id`, `val` ) VALUES('1', 'Z')";
897 MSIHANDLE hdb
= 0, hview
= 0, hrec
= 0;
900 const DWORD STRING_LENGTH
= 0x10005;
903 /* just MsiOpenDatabase should not create a file */
904 r
= MsiOpenDatabase(msifile
, MSIDBOPEN_CREATE
, &hdb
);
905 ok(r
== ERROR_SUCCESS
, "MsiOpenDatabase failed\n");
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");
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
);
950 static void test_streamtable(void)
952 MSIHANDLE hdb
= 0, rec
;
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" );
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" );
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
);
988 static void test_where(void)
990 MSIHANDLE hdb
= 0, rec
;
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
)
1056 HANDLE hf
= CreateFile(filename
, GENERIC_WRITE
, 0, NULL
,
1057 CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
1059 WriteFile(hf
, data
, data_size
, &size
, NULL
);
1063 static UINT
add_table_to_db(MSIHANDLE hdb
, LPCSTR table_data
)
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");
1074 static void test_msiimport(void)
1076 MSIHANDLE hdb
, view
, rec
;
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
);
1089 ok(r
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", r
);
1092 query
= "SELECT * FROM `TestTable`";
1093 r
= MsiDatabaseOpenView(hdb
, query
, &view
);
1096 ok(r
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", r
);
1099 r
= MsiViewGetColumnInfo(view
, MSICOLINFO_NAMES
, &rec
);
1100 count
= MsiRecordGetFieldCount(rec
);
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
);
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
);
1135 ok(r
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", r
);
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);
1149 ok(i
== 5, "Expected 5, got %d\n", i
);
1152 i
= MsiRecordGetInteger(rec
, 3);
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);
1164 ok(i
== 2147483640, "Expected 2147483640, got %d\n", i
);
1167 i
= MsiRecordGetInteger(rec
, 6);
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)
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
);
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
);
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)
1364 MSIHANDLE hviews
[MY_NVIEWS
];
1367 /* create an empty 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");
1380 ok( hviews
[i
] != 0, "%d'th handle is NULL\n", i
);
1383 ok( hviews
[i
] != 0, "%d'th handle is NULL\n", i
);
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");
1406 test_msidecomposedesc();
1407 test_msibadqueries();
1409 test_viewgetcolumninfo();
1417 test_handle_limit();