Delete all Trailing spaces in code.
[reactos.git] / rostests / winetests / msi / db.c
1 /*
2 * Copyright (C) 2005 Mike McCormack for CodeWeavers
3 *
4 * A test program for MSI database files.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20 #include <stdio.h>
21
22 #include <windows.h>
23 #include <msi.h>
24 #include <msiquery.h>
25
26 #include "wine/test.h"
27
28 static const char *msifile = "winetest.msi";
29
30 static void test_msidatabase(void)
31 {
32 MSIHANDLE hdb = 0;
33 UINT res;
34
35 DeleteFile(msifile);
36
37 /* create an empty database */
38 res = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb );
39 ok( res == ERROR_SUCCESS , "Failed to create database\n" );
40
41 res = MsiDatabaseCommit( hdb );
42 ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
43
44 res = MsiCloseHandle( hdb );
45 ok( res == ERROR_SUCCESS , "Failed to close database\n" );
46
47 res = DeleteFile( msifile );
48 ok( res == TRUE, "Failed to delete database\n" );
49 }
50
51 static UINT do_query(MSIHANDLE hdb, const char *query, MSIHANDLE *phrec)
52 {
53 MSIHANDLE hview = 0;
54 UINT r, ret;
55
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;
71 }
72
73 static void test_msiinsert(void)
74 {
75 MSIHANDLE hdb = 0, hview = 0, hrec = 0;
76 UINT r;
77 const char *query;
78 char buf[80];
79 DWORD sz;
80
81 DeleteFile(msifile);
82
83 /* just MsiOpenDatabase should not create a file */
84 r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
85 ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
86
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");
99
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");
111
112 query = "SELECT * FROM `phone` WHERE `id` = 1";
113 r = do_query(hdb, query, &hrec);
114 ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
115
116 /* check the record contains what we put in it */
117 r = MsiRecordGetFieldCount(hrec);
118 ok(r == 3, "record count wrong\n");
119
120 todo_wine {
121 r = MsiRecordIsNull(hrec, 0);
122 ok(r == FALSE, "field 0 not null\n");
123 }
124
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");
135
136 r = MsiCloseHandle(hrec);
137 ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
138
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");
145
146 r = MsiCloseHandle(hrec);
147 ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
148
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");
152
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");
156
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");
160
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");
164
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");
171
172 if (r == ERROR_SUCCESS)
173 r = MsiCloseHandle(hview);
174 }
175
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");
184
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");
190
191 if (r == ERROR_SUCCESS)
192 {
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");
199 }
200 r = MsiCloseHandle(hrec);
201 ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
202
203 r = MsiViewFetch(0, NULL);
204 ok(r == ERROR_INVALID_PARAMETER, "MsiViewFetch failed\n");
205
206 r = MsiDatabaseCommit(hdb);
207 ok(r == ERROR_SUCCESS, "MsiDatabaseCommit failed\n");
208
209 r = MsiCloseHandle(hdb);
210 ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
211
212 r = DeleteFile(msifile);
213 ok(r == TRUE, "file didn't exist after commit\n");
214 }
215
216 typedef UINT (WINAPI *fnMsiDecomposeDescriptorA)(LPCSTR, LPCSTR, LPSTR, LPSTR, DWORD *);
217 static fnMsiDecomposeDescriptorA pMsiDecomposeDescriptorA;
218
219 static void test_msidecomposedesc(void)
220 {
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;
226
227 hmod = GetModuleHandle("msi.dll");
228 if (!hmod)
229 return;
230 pMsiDecomposeDescriptorA = (fnMsiDecomposeDescriptorA)
231 GetProcAddress(hmod, "MsiDecomposeDescriptorA");
232 if (!pMsiDecomposeDescriptorA)
233 return;
234
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");
244
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");
252
253 /*
254 * Test a valid feature descriptor with the
255 * maximum number of characters and some trailing characters.
256 */
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");
265
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");
270
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");
275
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");
280
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");
285 }
286
287 static UINT try_query_param( MSIHANDLE hdb, LPCSTR szQuery, MSIHANDLE hrec )
288 {
289 MSIHANDLE htab = 0;
290 UINT res;
291
292 res = MsiDatabaseOpenView( hdb, szQuery, &htab );
293 if(res == ERROR_SUCCESS )
294 {
295 UINT r;
296
297 r = MsiViewExecute( htab, hrec );
298 if(r != ERROR_SUCCESS )
299 res = r;
300
301 r = MsiViewClose( htab );
302 if(r != ERROR_SUCCESS )
303 res = r;
304
305 r = MsiCloseHandle( htab );
306 if(r != ERROR_SUCCESS )
307 res = r;
308 }
309 return res;
310 }
311
312 static UINT try_query( MSIHANDLE hdb, LPCSTR szQuery )
313 {
314 return try_query_param( hdb, szQuery, 0 );
315 }
316
317 static UINT try_insert_query( MSIHANDLE hdb, LPCSTR szQuery )
318 {
319 MSIHANDLE hrec = 0;
320 UINT r;
321
322 hrec = MsiCreateRecord( 1 );
323 MsiRecordSetString( hrec, 1, "Hello");
324
325 r = try_query_param( hdb, szQuery, hrec );
326
327 MsiCloseHandle( hrec );
328 return r;
329 }
330
331 static void test_msibadqueries(void)
332 {
333 MSIHANDLE hdb = 0;
334 UINT r;
335
336 DeleteFile(msifile);
337
338 /* just MsiOpenDatabase should not create a file */
339 r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
340 ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
341
342 r = MsiDatabaseCommit( hdb );
343 ok(r == ERROR_SUCCESS , "Failed to commit database\n");
344
345 r = MsiCloseHandle( hdb );
346 ok(r == ERROR_SUCCESS , "Failed to close database\n");
347
348 /* open it readonly */
349 r = MsiOpenDatabase(msifile, MSIDBOPEN_READONLY, &hdb );
350 ok(r == ERROR_SUCCESS , "Failed to open database r/o\n");
351
352 /* add a table to it */
353 r = try_query( hdb, "select * from _Tables");
354 ok(r == ERROR_SUCCESS , "query 1 failed\n");
355
356 r = MsiCloseHandle( hdb );
357 ok(r == ERROR_SUCCESS , "Failed to close database r/o\n");
358
359 /* open it read/write */
360 r = MsiOpenDatabase(msifile, MSIDBOPEN_TRANSACT, &hdb );
361 ok(r == ERROR_SUCCESS , "Failed to open database r/w\n");
362
363 /* a bunch of test queries that fail with the native MSI */
364
365 r = try_query( hdb, "CREATE TABLE");
366 ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2a return code\n");
367
368 r = try_query( hdb, "CREATE TABLE `a`");
369 ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2b return code\n");
370
371 r = try_query( hdb, "CREATE TABLE `a` ()");
372 ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2c return code\n");
373
374 r = try_query( hdb, "CREATE TABLE `a` (`b`)");
375 ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2d return code\n");
376
377 r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) )");
378 ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2e return code\n");
379
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");
382
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");
385
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");
388
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");
391
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");
394
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");
397
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");
400
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");
403
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");
406
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");
409
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");
412
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");
415
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");
418
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");
421
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");
425
426 r = MsiDatabaseCommit( hdb );
427 ok(r == ERROR_SUCCESS , "Failed to commit database after write\n");
428
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");
432
433 r = try_insert_query( hdb, "insert into a ( `b` ) VALUES ( ? )");
434 ok(r == ERROR_SUCCESS , "failed to insert record in db\n");
435
436 r = MsiDatabaseCommit( hdb );
437 ok(r == ERROR_SUCCESS , "Failed to commit database after write\n");
438
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");
442
443 r = try_query( hdb,"CREATE TABLE `bee` (`foo` CHAR(72) NOT NULL )");
444 ok(r != ERROR_SUCCESS , "query 6 succeeded\n");
445
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");
449
450 r = try_query( hdb, "CREATE TABLE `c` (`b` CHAR NOT NULL PRIMARY KEY `b`)");
451 ok(r == ERROR_SUCCESS , "query 8 failed\n");
452
453 r = MsiCloseHandle( hdb );
454 ok(r == ERROR_SUCCESS , "Failed to close database transact\n");
455
456 r = DeleteFile( msifile );
457 ok(r == TRUE, "file didn't exist after commit\n");
458 }
459
460 static UINT run_query( MSIHANDLE hdb, MSIHANDLE hrec, const char *query )
461 {
462 MSIHANDLE hview = 0;
463 UINT r;
464
465 r = MsiDatabaseOpenView(hdb, query, &hview);
466 if( r != ERROR_SUCCESS )
467 return r;
468
469 r = MsiViewExecute(hview, hrec);
470 if( r == ERROR_SUCCESS )
471 r = MsiViewClose(hview);
472 MsiCloseHandle(hview);
473 return r;
474 }
475
476 static void test_viewmodify(void)
477 {
478 MSIHANDLE hdb = 0, hview = 0, hrec = 0;
479 UINT r;
480 const char *query;
481 char buffer[0x100];
482 DWORD sz;
483
484 DeleteFile(msifile);
485
486 /* just MsiOpenDatabase should not create a file */
487 r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
488 ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
489
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");
495
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");
501
502 /* open a view */
503 query = "SELECT * FROM `phone`";
504 r = MsiDatabaseOpenView(hdb, query, &hview);
505 ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
506
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");
513
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");
521
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");
527
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");
535
536 r = MsiViewExecute(hview, 0);
537 ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
538
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");
544
545 /* try an small record */
546 hrec = MsiCreateRecord(1);
547 r = MsiViewModify(hview, -1, hrec );
548 ok(r == ERROR_INVALID_DATA, "MsiViewModify failed\n");
549
550 r = MsiCloseHandle(hrec);
551 ok(r == ERROR_SUCCESS, "failed to close record\n");
552
553 /* insert a valid record */
554 hrec = MsiCreateRecord(3);
555
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");
562
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");
567
568 /* insert the same thing again */
569 r = MsiViewExecute(hview, 0);
570 ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
571
572 /* should fail ... */
573 todo_wine {
574 r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec );
575 ok(r == ERROR_FUNCTION_FAILED, "MsiViewModify failed\n");
576 }
577
578 r = MsiCloseHandle(hrec);
579 ok(r == ERROR_SUCCESS, "failed to close record\n");
580
581 r = MsiViewClose(hview);
582 ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
583 r = MsiCloseHandle(hview);
584 ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
585
586 r = MsiCloseHandle( hdb );
587 ok(r == ERROR_SUCCESS, "MsiOpenDatabase close failed\n");
588 }
589
590 static MSIHANDLE create_db(void)
591 {
592 MSIHANDLE hdb = 0;
593 UINT res;
594
595 DeleteFile(msifile);
596
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;
602
603 res = MsiDatabaseCommit( hdb );
604 ok( res == ERROR_SUCCESS , "Failed to commit database\n" );
605
606 return hdb;
607 }
608
609 static void test_getcolinfo(void)
610 {
611 MSIHANDLE hdb, hview = 0, rec = 0;
612 UINT r;
613 DWORD sz;
614 char buffer[0x20];
615
616 /* create an empty db */
617 hdb = create_db();
618 ok( hdb, "failed to create db\n");
619
620 /* tables should be present */
621 r = MsiDatabaseOpenView(hdb, "select * from _Tables", &hview);
622 ok( r == ERROR_SUCCESS, "failed to open query\n");
623
624 r = MsiViewExecute(hview, 0);
625 ok( r == ERROR_SUCCESS, "failed to execute query\n");
626
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");
637
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");
648
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");
654
655 r = MsiViewGetColumnInfo( hview, MSICOLINFO_TYPES, NULL );
656 ok( r == ERROR_INVALID_PARAMETER, "wrong error code\n");
657
658 r = MsiViewGetColumnInfo( 0, MSICOLINFO_TYPES, &rec );
659 ok( r == ERROR_INVALID_HANDLE, "wrong error code\n");
660
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");
667 }
668
669 static MSIHANDLE get_column_info(MSIHANDLE hdb, const char *query, MSICOLINFO type)
670 {
671 MSIHANDLE hview = 0, rec = 0;
672 UINT r;
673
674 r = MsiDatabaseOpenView(hdb, query, &hview);
675 if( r != ERROR_SUCCESS )
676 return r;
677
678 r = MsiViewExecute(hview, 0);
679 if( r == ERROR_SUCCESS )
680 {
681 MsiViewGetColumnInfo( hview, type, &rec );
682 MsiViewClose(hview);
683 }
684 MsiCloseHandle(hview);
685 return rec;
686 }
687
688 static UINT get_columns_table_type(MSIHANDLE hdb, const char *table, UINT field)
689 {
690 MSIHANDLE hview = 0, rec = 0;
691 UINT r, type = 0;
692 char query[0x100];
693
694 sprintf(query, "select * from `_Columns` where `Table` = '%s'", table );
695
696 r = MsiDatabaseOpenView(hdb, query, &hview);
697 if( r != ERROR_SUCCESS )
698 return r;
699
700 r = MsiViewExecute(hview, 0);
701 if( r == ERROR_SUCCESS )
702 {
703 while (1)
704 {
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 );
712 }
713
714 MsiViewClose(hview);
715 }
716 MsiCloseHandle(hview);
717 return type;
718 }
719
720 static BOOL check_record( MSIHANDLE rec, UINT field, LPCSTR val )
721 {
722 CHAR buffer[0x20];
723 UINT r;
724 DWORD sz;
725
726 sz = sizeof buffer;
727 r = MsiRecordGetString( rec, field, buffer, &sz );
728 return (r == ERROR_SUCCESS ) && !strcmp(val, buffer);
729 }
730
731 static void test_viewgetcolumninfo(void)
732 {
733 MSIHANDLE hdb = 0, rec;
734 UINT r;
735
736 hdb = create_db();
737 ok( hdb, "failed to create db\n");
738
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" );
743
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" );
747
748 ok( check_record( rec, 1, "S255"), "wrong record type\n");
749 ok( check_record( rec, 2, "S1"), "wrong record type\n");
750
751 MsiCloseHandle( rec );
752
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");
756
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" );
760
761 ok( check_record( rec, 1, "Property"), "wrong record type\n");
762 ok( check_record( rec, 2, "Value"), "wrong record type\n");
763
764 MsiCloseHandle( rec );
765
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" );
770
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" );
774
775 ok( check_record( rec, 1, "S255"), "wrong record type\n");
776 ok( check_record( rec, 2, "V0"), "wrong record type\n");
777
778 MsiCloseHandle( rec );
779
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");
783
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" );
787
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 );
791
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" );
796
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");
799
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 );
805
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 );
811
812 MsiCloseHandle( hdb );
813 }
814
815 static void test_msiexport(void)
816 {
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";
830
831 DeleteFile(msifile);
832
833 /* just MsiOpenDatabase should not create a file */
834 r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
835 ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
836
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");
849
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");
861
862 GetCurrentDirectory(MAX_PATH, path);
863
864 todo_wine {
865 r = MsiDatabaseExport(hdb, "phone", path, file);
866 ok(r == ERROR_SUCCESS, "MsiDatabaseExport failed\n");
867
868 MsiCloseHandle(hdb);
869
870 lstrcat(path, "\\");
871 lstrcat(path, file);
872
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)
878 {
879 ReadFile(handle, buffer, sizeof buffer, &length, NULL);
880 CloseHandle(handle);
881 DeleteFile(path);
882 }
883 else
884 ok(0, "failed to open file %s\n", path);
885
886 ok( length == strlen(expected), "length of data wrong\n");
887 ok( !lstrcmp(buffer, expected), "data doesn't match\n");
888 }
889 DeleteFile(msifile);
890 }
891
892 static void test_longstrings(void)
893 {
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;
901
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");
906
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");
911
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");
920
921 HeapFree(GetProcessHeap(), 0, str);
922
923 MsiDatabaseCommit(hdb);
924 ok(r == ERROR_SUCCESS, "MsiDatabaseCommit failed\n");
925 MsiCloseHandle(hdb);
926
927 r = MsiOpenDatabase(msifile, MSIDBOPEN_READONLY, &hdb);
928 ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
929
930 r = MsiDatabaseOpenView(hdb, "select * from `strings` where `id` = 1", &hview);
931 ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
932
933 r = MsiViewExecute(hview, 0);
934 ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
935
936 r = MsiViewFetch(hview, &hrec);
937 ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
938
939 MsiCloseHandle(hview);
940
941 r = MsiRecordGetString(hrec, 2, NULL, &len);
942 ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
943 todo_wine {
944 ok(len == STRING_LENGTH, "string length wrong\n");
945 }
946
947 MsiCloseHandle(hrec);
948 MsiCloseHandle(hdb);
949 DeleteFile(msifile);
950 }
951
952 static void test_streamtable(void)
953 {
954 MSIHANDLE hdb = 0, rec;
955 UINT r;
956
957 hdb = create_db();
958 ok( hdb, "failed to create db\n");
959
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" );
964
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" );
968
969 todo_wine {
970 ok( check_record( rec, 1, "s62"), "wrong record type\n");
971 ok( check_record( rec, 2, "V0"), "wrong record type\n");
972 }
973
974 MsiCloseHandle( rec );
975
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" );
979
980 todo_wine {
981 ok( check_record( rec, 1, "Name"), "wrong record type\n");
982 ok( check_record( rec, 2, "Data"), "wrong record type\n");
983 }
984
985 MsiCloseHandle( rec );
986 MsiCloseHandle( hdb );
987 DeleteFile(msifile);
988 }
989
990 static void test_where(void)
991 {
992 MSIHANDLE hdb = 0, rec;
993 LPCSTR query;
994 UINT r;
995
996 hdb = create_db();
997 ok( hdb, "failed to create db\n");
998
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 );
1009
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 );
1014
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 );
1019
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 );
1024
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 );
1030
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");
1035
1036 r = MsiRecordGetInteger(rec, 1);
1037 ok( 2 == r, "field wrong\n");
1038 r = MsiRecordGetInteger(rec, 2);
1039 ok( 1 == r, "field wrong\n");
1040
1041 MsiCloseHandle( rec );
1042
1043 MsiCloseHandle( hdb );
1044 DeleteFile(msifile);
1045 }
1046
1047 static CHAR CURR_DIR[MAX_PATH];
1048
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";
1053
1054 static void write_file(const CHAR *filename, const char *data, int data_size)
1055 {
1056 DWORD size;
1057
1058 HANDLE hf = CreateFile(filename, GENERIC_WRITE, 0, NULL,
1059 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1060
1061 WriteFile(hf, data, data_size, &size, NULL);
1062 CloseHandle(hf);
1063 }
1064
1065 static UINT add_table_to_db(MSIHANDLE hdb, LPCSTR table_data)
1066 {
1067 UINT r;
1068
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");
1072
1073 return r;
1074 }
1075
1076 static void test_msiimport(void)
1077 {
1078 MSIHANDLE hdb, view, rec;
1079 LPCSTR query;
1080 UINT r, count;
1081 signed int i;
1082
1083 GetCurrentDirectoryA(MAX_PATH, CURR_DIR);
1084
1085 r = MsiOpenDatabaseA(msifile, MSIDBOPEN_CREATE, &hdb);
1086 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1087
1088 r = add_table_to_db(hdb, test_data);
1089 todo_wine
1090 {
1091 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1092 }
1093
1094 query = "SELECT * FROM `TestTable`";
1095 r = MsiDatabaseOpenView(hdb, query, &view);
1096 todo_wine
1097 {
1098 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1099 }
1100
1101 r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec);
1102 count = MsiRecordGetFieldCount(rec);
1103 todo_wine
1104 {
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");
1115 }
1116
1117 r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
1118 count = MsiRecordGetFieldCount(rec);
1119 todo_wine
1120 {
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");
1131 }
1132
1133 query = "SELECT * FROM `TestTable`";
1134 r = do_query(hdb, query, &rec);
1135 todo_wine
1136 {
1137 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
1138 }
1139
1140 todo_wine
1141 {
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");
1146 }
1147
1148 i = MsiRecordGetInteger(rec, 2);
1149 todo_wine
1150 {
1151 ok(i == 5, "Expected 5, got %d\n", i);
1152 }
1153
1154 i = MsiRecordGetInteger(rec, 3);
1155 todo_wine
1156 {
1157 ok(i == 2, "Expected 2, got %d\n", i);
1158 }
1159
1160 i = MsiRecordGetInteger(rec, 4);
1161 ok(i == 0x80000000, "Expected 0x80000000, got %d\n", i);
1162
1163 i = MsiRecordGetInteger(rec, 5);
1164 todo_wine
1165 {
1166 ok(i == 2147483640, "Expected 2147483640, got %d\n", i);
1167 }
1168
1169 i = MsiRecordGetInteger(rec, 6);
1170 todo_wine
1171 {
1172 ok(i == -2147483640, "Expected -2147483640, got %d\n", i);
1173 }
1174
1175 MsiCloseHandle(rec);
1176 MsiCloseHandle(view);
1177 MsiCloseHandle(hdb);
1178 DeleteFileA(msifile);
1179 }
1180
1181 static void test_markers(void)
1182 {
1183 MSIHANDLE hdb, rec;
1184 LPCSTR query;
1185 UINT r;
1186
1187 hdb = create_db();
1188 ok( hdb, "failed to create db\n");
1189
1190 rec = MsiCreateRecord(3);
1191 MsiRecordSetString(rec, 1, "Table");
1192 MsiRecordSetString(rec, 2, "Apples");
1193 MsiRecordSetString(rec, 3, "Oranges");
1194
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);
1200
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);
1207
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);
1213
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);
1219
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);
1228
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);
1237 todo_wine
1238 {
1239 ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
1240 }
1241
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);
1246
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);
1251
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);
1259
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);
1270
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);
1275
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);
1284
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);
1295
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);
1304
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);
1312
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);
1321 todo_wine
1322 {
1323 ok(r == ERROR_FUNCTION_FAILED, "Expected ERROR_FUNCTION_FAILED, got %d\n", r);
1324 }
1325
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);
1337
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);
1346
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);
1356
1357 MsiCloseHandle(hdb);
1358 DeleteFileA(msifile);
1359 }
1360
1361 START_TEST(db)
1362 {
1363 test_msidatabase();
1364 test_msiinsert();
1365 test_msidecomposedesc();
1366 test_msibadqueries();
1367 test_viewmodify();
1368 test_viewgetcolumninfo();
1369 test_getcolinfo();
1370 test_msiexport();
1371 test_longstrings();
1372 test_streamtable();
1373 test_where();
1374 test_msiimport();
1375 test_markers();
1376 }