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");
944 ok(len
== STRING_LENGTH
, "string length wrong\n");
947 MsiCloseHandle(hrec
);
952 static void test_streamtable(void)
954 MSIHANDLE hdb
= 0, rec
;
958 ok( hdb
, "failed to create db\n");
960 r
= run_query( hdb
, 0,
961 "CREATE TABLE `Properties` "
962 "( `Property` CHAR(255), `Value` CHAR(1) PRIMARY KEY `Property`)" );
963 ok( r
== ERROR_SUCCESS
, "Failed to create table\n" );
965 /* check the column types */
966 rec
= get_column_info( hdb
, "select * from `_Streams`", MSICOLINFO_TYPES
);
967 ok( rec
, "failed to get column info record\n" );
970 ok( check_record( rec
, 1, "s62"), "wrong record type\n");
971 ok( check_record( rec
, 2, "V0"), "wrong record type\n");
974 MsiCloseHandle( rec
);
976 /* now try the names */
977 rec
= get_column_info( hdb
, "select * from `_Streams`", MSICOLINFO_NAMES
);
978 ok( rec
, "failed to get column info record\n" );
981 ok( check_record( rec
, 1, "Name"), "wrong record type\n");
982 ok( check_record( rec
, 2, "Data"), "wrong record type\n");
985 MsiCloseHandle( rec
);
986 MsiCloseHandle( hdb
);
990 static void test_where(void)
992 MSIHANDLE hdb
= 0, rec
;
997 ok( hdb
, "failed to create db\n");
999 r
= run_query( hdb
, 0,
1000 "CREATE TABLE `Media` ("
1001 "`DiskId` SHORT NOT NULL, "
1002 "`LastSequence` LONG, "
1003 "`DiskPrompt` CHAR(64) LOCALIZABLE, "
1004 "`Cabinet` CHAR(255), "
1005 "`VolumeLabel` CHAR(32), "
1006 "`Source` CHAR(72) "
1007 "PRIMARY KEY `DiskId`)" );
1008 ok( r
== S_OK
, "cannot create Media table: %d\n", r
);
1010 r
= run_query( hdb
, 0, "INSERT INTO `Media` "
1011 "( `DiskId`, `LastSequence`, `DiskPrompt`, `Cabinet`, `VolumeLabel`, `Source` ) "
1012 "VALUES ( 1, 0, '', 'zero.cab', '', '' )" );
1013 ok( r
== S_OK
, "cannot add file to the Media table: %d\n", r
);
1015 r
= run_query( hdb
, 0, "INSERT INTO `Media` "
1016 "( `DiskId`, `LastSequence`, `DiskPrompt`, `Cabinet`, `VolumeLabel`, `Source` ) "
1017 "VALUES ( 2, 1, '', 'one.cab', '', '' )" );
1018 ok( r
== S_OK
, "cannot add file to the Media table: %d\n", r
);
1020 r
= run_query( hdb
, 0, "INSERT INTO `Media` "
1021 "( `DiskId`, `LastSequence`, `DiskPrompt`, `Cabinet`, `VolumeLabel`, `Source` ) "
1022 "VALUES ( 3, 2, '', 'two.cab', '', '' )" );
1023 ok( r
== S_OK
, "cannot add file to the Media table: %d\n", r
);
1025 query
= "SELECT * FROM `Media`";
1026 r
= do_query(hdb
, query
, &rec
);
1027 ok(r
== ERROR_SUCCESS
, "MsiViewFetch failed: %d\n", r
);
1028 ok( check_record( rec
, 4, "zero.cab"), "wrong cabinet\n");
1029 MsiCloseHandle( rec
);
1031 query
= "SELECT * FROM `Media` WHERE `LastSequence` >= 1";
1032 r
= do_query(hdb
, query
, &rec
);
1033 ok(r
== ERROR_SUCCESS
, "MsiViewFetch failed: %d\n", r
);
1034 ok( check_record( rec
, 4, "one.cab"), "wrong cabinet\n");
1036 r
= MsiRecordGetInteger(rec
, 1);
1037 ok( 2 == r
, "field wrong\n");
1038 r
= MsiRecordGetInteger(rec
, 2);
1039 ok( 1 == r
, "field wrong\n");
1041 MsiCloseHandle( rec
);
1043 MsiCloseHandle( hdb
);
1044 DeleteFile(msifile
);
1047 static CHAR CURR_DIR
[MAX_PATH
];
1049 static const CHAR test_data
[] = "FirstPrimaryColumn\tSecondPrimaryColumn\tShortInt\tShortIntNullable\tLongInt\tLongIntNullable\tString\tLocalizableString\tLocalizableStringNullable\n"
1050 "s255\ti2\ti2\tI2\ti4\tI4\tS255\tS0\ts0\n"
1051 "TestTable\tFirstPrimaryColumn\n"
1052 "stringage\t5\t2\t\t2147483640\t-2147483640\tanother string\tlocalizable\tduh\n";
1054 static void write_file(const CHAR
*filename
, const char *data
, int data_size
)
1058 HANDLE hf
= CreateFile(filename
, GENERIC_WRITE
, 0, NULL
,
1059 CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
1061 WriteFile(hf
, data
, data_size
, &size
, NULL
);
1065 static UINT
add_table_to_db(MSIHANDLE hdb
, LPCSTR table_data
)
1069 write_file("temp_file", table_data
, (lstrlen(table_data
) - 1) * sizeof(char));
1070 r
= MsiDatabaseImportA(hdb
, CURR_DIR
, "temp_file");
1071 DeleteFileA("temp_file");
1076 static void test_msiimport(void)
1078 MSIHANDLE hdb
, view
, rec
;
1083 GetCurrentDirectoryA(MAX_PATH
, CURR_DIR
);
1085 r
= MsiOpenDatabaseA(msifile
, MSIDBOPEN_CREATE
, &hdb
);
1086 ok(r
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", r
);
1088 r
= add_table_to_db(hdb
, test_data
);
1091 ok(r
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", r
);
1094 query
= "SELECT * FROM `TestTable`";
1095 r
= MsiDatabaseOpenView(hdb
, query
, &view
);
1098 ok(r
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", r
);
1101 r
= MsiViewGetColumnInfo(view
, MSICOLINFO_NAMES
, &rec
);
1102 count
= MsiRecordGetFieldCount(rec
);
1105 ok(count
== 9, "Expected 9, got %d\n", count
);
1106 ok(check_record(rec
, 1, "FirstPrimaryColumn"), "Expected FirstPrimaryColumn\n");
1107 ok(check_record(rec
, 2, "SecondPrimaryColumn"), "Expected SecondPrimaryColumn\n");
1108 ok(check_record(rec
, 3, "ShortInt"), "Expected ShortInt\n");
1109 ok(check_record(rec
, 4, "ShortIntNullable"), "Expected ShortIntNullalble\n");
1110 ok(check_record(rec
, 5, "LongInt"), "Expected LongInt\n");
1111 ok(check_record(rec
, 6, "LongIntNullable"), "Expected LongIntNullalble\n");
1112 ok(check_record(rec
, 7, "String"), "Expected String\n");
1113 ok(check_record(rec
, 8, "LocalizableString"), "Expected LocalizableString\n");
1114 ok(check_record(rec
, 9, "LocalizableStringNullable"), "Expected LocalizableStringNullable\n");
1117 r
= MsiViewGetColumnInfo(view
, MSICOLINFO_TYPES
, &rec
);
1118 count
= MsiRecordGetFieldCount(rec
);
1121 ok(count
== 9, "Expected 9, got %d\n", count
);
1122 ok(check_record(rec
, 1, "s255"), "Expected s255\n");
1123 ok(check_record(rec
, 2, "i2"), "Expected i2\n");
1124 ok(check_record(rec
, 3, "i2"), "Expected i2\n");
1125 ok(check_record(rec
, 4, "I2"), "Expected I2\n");
1126 ok(check_record(rec
, 5, "i4"), "Expected i4\n");
1127 ok(check_record(rec
, 6, "I4"), "Expected I4\n");
1128 ok(check_record(rec
, 7, "S255"), "Expected S255\n");
1129 ok(check_record(rec
, 8, "S0"), "Expected S0\n");
1130 ok(check_record(rec
, 9, "s0"), "Expected s0\n");
1133 query
= "SELECT * FROM `TestTable`";
1134 r
= do_query(hdb
, query
, &rec
);
1137 ok(r
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", r
);
1142 ok(check_record(rec
, 1, "stringage"), "Expected 'stringage'\n");
1143 ok(check_record(rec
, 7, "another string"), "Expected 'another string'\n");
1144 ok(check_record(rec
, 8, "localizable"), "Expected 'localizable'\n");
1145 ok(check_record(rec
, 9, "duh"), "Expected 'duh'\n");
1148 i
= MsiRecordGetInteger(rec
, 2);
1151 ok(i
== 5, "Expected 5, got %d\n", i
);
1154 i
= MsiRecordGetInteger(rec
, 3);
1157 ok(i
== 2, "Expected 2, got %d\n", i
);
1160 i
= MsiRecordGetInteger(rec
, 4);
1161 ok(i
== 0x80000000, "Expected 0x80000000, got %d\n", i
);
1163 i
= MsiRecordGetInteger(rec
, 5);
1166 ok(i
== 2147483640, "Expected 2147483640, got %d\n", i
);
1169 i
= MsiRecordGetInteger(rec
, 6);
1172 ok(i
== -2147483640, "Expected -2147483640, got %d\n", i
);
1175 MsiCloseHandle(rec
);
1176 MsiCloseHandle(view
);
1177 MsiCloseHandle(hdb
);
1178 DeleteFileA(msifile
);
1181 static void test_markers(void)
1188 ok( hdb
, "failed to create db\n");
1190 rec
= MsiCreateRecord(3);
1191 MsiRecordSetString(rec
, 1, "Table");
1192 MsiRecordSetString(rec
, 2, "Apples");
1193 MsiRecordSetString(rec
, 3, "Oranges");
1195 /* try a legit create */
1196 query
= "CREATE TABLE `Table` ( `One` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`)";
1197 r
= run_query(hdb
, 0, query
);
1198 ok(r
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", r
);
1199 MsiCloseHandle(rec
);
1201 /* try table name as marker */
1202 rec
= MsiCreateRecord(1);
1203 MsiRecordSetString(rec
, 1, "Fable");
1204 query
= "CREATE TABLE `?` ( `One` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`)";
1205 r
= run_query(hdb
, rec
, query
);
1206 ok(r
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", r
);
1208 /* try table name as marker without backticks */
1209 MsiRecordSetString(rec
, 1, "Mable");
1210 query
= "CREATE TABLE ? ( `One` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`)";
1211 r
= run_query(hdb
, rec
, query
);
1212 ok(r
== ERROR_BAD_QUERY_SYNTAX
, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r
);
1214 /* try one column name as marker */
1215 MsiRecordSetString(rec
, 1, "One");
1216 query
= "CREATE TABLE `Mable` ( `?` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`)";
1217 r
= run_query(hdb
, rec
, query
);
1218 ok(r
== ERROR_BAD_QUERY_SYNTAX
, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r
);
1220 /* try column names as markers */
1221 MsiCloseHandle(rec
);
1222 rec
= MsiCreateRecord(2);
1223 MsiRecordSetString(rec
, 1, "One");
1224 MsiRecordSetString(rec
, 2, "Two");
1225 query
= "CREATE TABLE `Mable` ( `?` SHORT NOT NULL, `?` CHAR(255) PRIMARY KEY `One`)";
1226 r
= run_query(hdb
, rec
, query
);
1227 ok(r
== ERROR_BAD_QUERY_SYNTAX
, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r
);
1229 /* try names with backticks */
1230 MsiCloseHandle(rec
);
1231 rec
= MsiCreateRecord(3);
1232 MsiRecordSetString(rec
, 1, "One");
1233 MsiRecordSetString(rec
, 2, "Two");
1234 MsiRecordSetString(rec
, 3, "One");
1235 query
= "CREATE TABLE `Mable` ( `?` SHORT NOT NULL, `?` CHAR(255) PRIMARY KEY `?`)";
1236 r
= run_query(hdb
, rec
, query
);
1239 ok(r
== ERROR_BAD_QUERY_SYNTAX
, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r
);
1242 /* try names with backticks, minus definitions */
1243 query
= "CREATE TABLE `Mable` ( `?`, `?` PRIMARY KEY `?`)";
1244 r
= run_query(hdb
, rec
, query
);
1245 ok(r
== ERROR_BAD_QUERY_SYNTAX
, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r
);
1247 /* try names without backticks */
1248 query
= "CREATE TABLE `Mable` ( ? SHORT NOT NULL, ? CHAR(255) PRIMARY KEY ?)";
1249 r
= run_query(hdb
, rec
, query
);
1250 ok(r
== ERROR_BAD_QUERY_SYNTAX
, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r
);
1252 /* try one long marker */
1253 MsiCloseHandle(rec
);
1254 rec
= MsiCreateRecord(1);
1255 MsiRecordSetString(rec
, 1, "`One` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`");
1256 query
= "CREATE TABLE `Mable` ( ? )";
1257 r
= run_query(hdb
, rec
, query
);
1258 ok(r
== ERROR_BAD_QUERY_SYNTAX
, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r
);
1260 /* try all names as markers */
1261 MsiCloseHandle(rec
);
1262 rec
= MsiCreateRecord(4);
1263 MsiRecordSetString(rec
, 1, "Mable");
1264 MsiRecordSetString(rec
, 2, "One");
1265 MsiRecordSetString(rec
, 3, "Two");
1266 MsiRecordSetString(rec
, 4, "One");
1267 query
= "CREATE TABLE `?` ( `?` SHORT NOT NULL, `?` CHAR(255) PRIMARY KEY `?`)";
1268 r
= run_query(hdb
, rec
, query
);
1269 ok(r
== ERROR_BAD_QUERY_SYNTAX
, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r
);
1271 /* try a legit insert */
1272 query
= "INSERT INTO `Table` ( `One`, `Two` ) VALUES ( 5, 'hello' )";
1273 r
= run_query(hdb
, 0, query
);
1274 ok(r
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", r
);
1276 /* try values as markers */
1277 MsiCloseHandle(rec
);
1278 rec
= MsiCreateRecord(2);
1279 MsiRecordSetInteger(rec
, 1, 4);
1280 MsiRecordSetString(rec
, 2, "hi");
1281 query
= "INSERT INTO `Table` ( `One`, `Two` ) VALUES ( ?, '?' )";
1282 r
= run_query(hdb
, rec
, query
);
1283 ok(r
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", r
);
1285 /* try column names and values as markers */
1286 MsiCloseHandle(rec
);
1287 rec
= MsiCreateRecord(4);
1288 MsiRecordSetString(rec
, 1, "One");
1289 MsiRecordSetString(rec
, 2, "Two");
1290 MsiRecordSetInteger(rec
, 3, 5);
1291 MsiRecordSetString(rec
, 4, "hi");
1292 query
= "INSERT INTO `Table` ( `?`, `?` ) VALUES ( ?, '?' )";
1293 r
= run_query(hdb
, rec
, query
);
1294 ok(r
== ERROR_BAD_QUERY_SYNTAX
, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r
);
1296 /* try column names as markers */
1297 MsiCloseHandle(rec
);
1298 rec
= MsiCreateRecord(2);
1299 MsiRecordSetString(rec
, 1, "One");
1300 MsiRecordSetString(rec
, 2, "Two");
1301 query
= "INSERT INTO `Table` ( `?`, `?` ) VALUES ( 3, 'yellow' )";
1302 r
= run_query(hdb
, rec
, query
);
1303 ok(r
== ERROR_BAD_QUERY_SYNTAX
, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r
);
1305 /* try table name as a marker */
1306 MsiCloseHandle(rec
);
1307 rec
= MsiCreateRecord(1);
1308 MsiRecordSetString(rec
, 1, "Table");
1309 query
= "INSERT INTO `?` ( `One`, `Two` ) VALUES ( 2, 'green' )";
1310 r
= run_query(hdb
, rec
, query
);
1311 ok(r
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", r
);
1313 /* try table name and values as markers */
1314 MsiCloseHandle(rec
);
1315 rec
= MsiCreateRecord(3);
1316 MsiRecordSetString(rec
, 1, "Table");
1317 MsiRecordSetInteger(rec
, 2, 10);
1318 MsiRecordSetString(rec
, 3, "haha");
1319 query
= "INSERT INTO `?` ( `One`, `Two` ) VALUES ( ?, '?' )";
1320 r
= run_query(hdb
, rec
, query
);
1323 ok(r
== ERROR_FUNCTION_FAILED
, "Expected ERROR_FUNCTION_FAILED, got %d\n", r
);
1326 /* try all markers */
1327 MsiCloseHandle(rec
);
1328 rec
= MsiCreateRecord(5);
1329 MsiRecordSetString(rec
, 1, "Table");
1330 MsiRecordSetString(rec
, 1, "One");
1331 MsiRecordSetString(rec
, 1, "Two");
1332 MsiRecordSetInteger(rec
, 2, 10);
1333 MsiRecordSetString(rec
, 3, "haha");
1334 query
= "INSERT INTO `?` ( `?`, `?` ) VALUES ( ?, '?' )";
1335 r
= run_query(hdb
, rec
, query
);
1336 ok(r
== ERROR_BAD_QUERY_SYNTAX
, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r
);
1338 /* insert an integer as a string */
1339 MsiCloseHandle(rec
);
1340 rec
= MsiCreateRecord(2);
1341 MsiRecordSetString(rec
, 1, "11");
1342 MsiRecordSetString(rec
, 2, "hi");
1343 query
= "INSERT INTO `Table` ( `One`, `Two` ) VALUES ( ?, '?' )";
1344 r
= run_query(hdb
, rec
, query
);
1345 ok(r
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", r
);
1347 /* leave off the '' for the string */
1348 MsiCloseHandle(rec
);
1349 rec
= MsiCreateRecord(2);
1350 MsiRecordSetInteger(rec
, 1, 12);
1351 MsiRecordSetString(rec
, 2, "hi");
1352 query
= "INSERT INTO `Table` ( `One`, `Two` ) VALUES ( ?, ? )";
1353 r
= run_query(hdb
, rec
, query
);
1354 ok(r
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %d\n", r
);
1355 MsiCloseHandle(rec
);
1357 MsiCloseHandle(hdb
);
1358 DeleteFileA(msifile
);
1365 test_msidecomposedesc();
1366 test_msibadqueries();
1368 test_viewgetcolumninfo();