[MSI] Prevent uninitialized variable usage
[reactos.git] / dll / win32 / msi / msiquery.c
1 /*
2 * Implementation of the Microsoft Installer (msi.dll)
3 *
4 * Copyright 2002-2005 Mike McCormack for CodeWeavers
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 #include <stdarg.h>
22
23 #define COBJMACROS
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winerror.h"
28 #include "wine/debug.h"
29 #include "wine/unicode.h"
30 #include "msi.h"
31 #include "msiquery.h"
32 #include "objbase.h"
33 #include "objidl.h"
34 #include "msipriv.h"
35 #include "winnls.h"
36
37 #include "query.h"
38 #include "msiserver.h"
39
40 #include "initguid.h"
41
42 WINE_DEFAULT_DEBUG_CHANNEL(msi);
43
44 static void MSI_CloseView( MSIOBJECTHDR *arg )
45 {
46 MSIQUERY *query = (MSIQUERY*) arg;
47 struct list *ptr, *t;
48
49 if( query->view && query->view->ops->delete )
50 query->view->ops->delete( query->view );
51 msiobj_release( &query->db->hdr );
52
53 LIST_FOR_EACH_SAFE( ptr, t, &query->mem )
54 {
55 msi_free( ptr );
56 }
57 }
58
59 UINT VIEW_find_column( MSIVIEW *table, LPCWSTR name, LPCWSTR table_name, UINT *n )
60 {
61 LPCWSTR col_name, haystack_table_name;
62 UINT i, count, r;
63
64 r = table->ops->get_dimensions( table, NULL, &count );
65 if( r != ERROR_SUCCESS )
66 return r;
67
68 for( i=1; i<=count; i++ )
69 {
70 INT x;
71
72 r = table->ops->get_column_info( table, i, &col_name, NULL,
73 NULL, &haystack_table_name );
74 if( r != ERROR_SUCCESS )
75 return r;
76 x = strcmpW( name, col_name );
77 if( table_name )
78 x |= strcmpW( table_name, haystack_table_name );
79 if( !x )
80 {
81 *n = i;
82 return ERROR_SUCCESS;
83 }
84 }
85 return ERROR_INVALID_PARAMETER;
86 }
87
88 UINT WINAPI MsiDatabaseOpenViewA(MSIHANDLE hdb,
89 LPCSTR szQuery, MSIHANDLE *phView)
90 {
91 UINT r;
92 LPWSTR szwQuery;
93
94 TRACE("%d %s %p\n", hdb, debugstr_a(szQuery), phView);
95
96 if( szQuery )
97 {
98 szwQuery = strdupAtoW( szQuery );
99 if( !szwQuery )
100 return ERROR_FUNCTION_FAILED;
101 }
102 else
103 szwQuery = NULL;
104
105 r = MsiDatabaseOpenViewW( hdb, szwQuery, phView);
106
107 msi_free( szwQuery );
108 return r;
109 }
110
111 UINT MSI_DatabaseOpenViewW(MSIDATABASE *db,
112 LPCWSTR szQuery, MSIQUERY **pView)
113 {
114 MSIQUERY *query;
115 UINT r;
116
117 TRACE("%s %p\n", debugstr_w(szQuery), pView);
118
119 if( !szQuery)
120 return ERROR_INVALID_PARAMETER;
121
122 /* pre allocate a handle to hold a pointer to the view */
123 query = alloc_msiobject( MSIHANDLETYPE_VIEW, sizeof (MSIQUERY),
124 MSI_CloseView );
125 if( !query )
126 return ERROR_FUNCTION_FAILED;
127
128 msiobj_addref( &db->hdr );
129 query->db = db;
130 list_init( &query->mem );
131
132 r = MSI_ParseSQL( db, szQuery, &query->view, &query->mem );
133 if( r == ERROR_SUCCESS )
134 {
135 msiobj_addref( &query->hdr );
136 *pView = query;
137 }
138
139 msiobj_release( &query->hdr );
140 return r;
141 }
142
143 UINT MSI_OpenQuery( MSIDATABASE *db, MSIQUERY **view, LPCWSTR fmt, ... )
144 {
145 UINT r;
146 int size = 100, res;
147 LPWSTR query;
148
149 /* construct the string */
150 for (;;)
151 {
152 va_list va;
153 query = msi_alloc( size*sizeof(WCHAR) );
154 va_start(va, fmt);
155 res = vsnprintfW(query, size, fmt, va);
156 va_end(va);
157 if (res == -1) size *= 2;
158 else if (res >= size) size = res + 1;
159 else break;
160 msi_free( query );
161 }
162 /* perform the query */
163 r = MSI_DatabaseOpenViewW(db, query, view);
164 msi_free(query);
165 return r;
166 }
167
168 UINT MSI_IterateRecords( MSIQUERY *view, LPDWORD count,
169 record_func func, LPVOID param )
170 {
171 MSIRECORD *rec = NULL;
172 UINT r, n = 0, max = 0;
173
174 r = MSI_ViewExecute( view, NULL );
175 if( r != ERROR_SUCCESS )
176 return r;
177
178 if( count )
179 max = *count;
180
181 /* iterate a query */
182 for( n = 0; (max == 0) || (n < max); n++ )
183 {
184 r = MSI_ViewFetch( view, &rec );
185 if( r != ERROR_SUCCESS )
186 break;
187 if (func)
188 r = func( rec, param );
189 msiobj_release( &rec->hdr );
190 if( r != ERROR_SUCCESS )
191 break;
192 }
193
194 MSI_ViewClose( view );
195
196 if( count )
197 *count = n;
198
199 if( r == ERROR_NO_MORE_ITEMS )
200 r = ERROR_SUCCESS;
201
202 return r;
203 }
204
205 /* return a single record from a query */
206 MSIRECORD *MSI_QueryGetRecord( MSIDATABASE *db, LPCWSTR fmt, ... )
207 {
208 MSIRECORD *rec = NULL;
209 MSIQUERY *view = NULL;
210 UINT r;
211 int size = 100, res;
212 LPWSTR query;
213
214 /* construct the string */
215 for (;;)
216 {
217 va_list va;
218 query = msi_alloc( size*sizeof(WCHAR) );
219 va_start(va, fmt);
220 res = vsnprintfW(query, size, fmt, va);
221 va_end(va);
222 if (res == -1) size *= 2;
223 else if (res >= size) size = res + 1;
224 else break;
225 msi_free( query );
226 }
227 /* perform the query */
228 r = MSI_DatabaseOpenViewW(db, query, &view);
229 msi_free(query);
230
231 if( r == ERROR_SUCCESS )
232 {
233 MSI_ViewExecute( view, NULL );
234 MSI_ViewFetch( view, &rec );
235 MSI_ViewClose( view );
236 msiobj_release( &view->hdr );
237 }
238 return rec;
239 }
240
241 UINT WINAPI MsiDatabaseOpenViewW(MSIHANDLE hdb,
242 LPCWSTR szQuery, MSIHANDLE *phView)
243 {
244 MSIDATABASE *db;
245 MSIQUERY *query = NULL;
246 UINT ret;
247
248 TRACE("%s %p\n", debugstr_w(szQuery), phView);
249
250 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
251 if( !db )
252 {
253 HRESULT hr;
254 IWineMsiRemoteDatabase *remote_database;
255
256 remote_database = (IWineMsiRemoteDatabase *)msi_get_remote( hdb );
257 if ( !remote_database )
258 return ERROR_INVALID_HANDLE;
259
260 hr = IWineMsiRemoteDatabase_OpenView( remote_database, szQuery, phView );
261 IWineMsiRemoteDatabase_Release( remote_database );
262
263 if (FAILED(hr))
264 {
265 if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
266 return HRESULT_CODE(hr);
267
268 return ERROR_FUNCTION_FAILED;
269 }
270
271 return ERROR_SUCCESS;
272 }
273
274 ret = MSI_DatabaseOpenViewW( db, szQuery, &query );
275 if( ret == ERROR_SUCCESS )
276 {
277 *phView = alloc_msihandle( &query->hdr );
278 if (! *phView)
279 ret = ERROR_NOT_ENOUGH_MEMORY;
280 msiobj_release( &query->hdr );
281 }
282 msiobj_release( &db->hdr );
283
284 return ret;
285 }
286
287 UINT msi_view_get_row(MSIDATABASE *db, MSIVIEW *view, UINT row, MSIRECORD **rec)
288 {
289 UINT row_count = 0, col_count = 0, i, ival, ret, type;
290
291 TRACE("%p %p %d %p\n", db, view, row, rec);
292
293 ret = view->ops->get_dimensions(view, &row_count, &col_count);
294 if (ret)
295 return ret;
296
297 if (!col_count)
298 return ERROR_INVALID_PARAMETER;
299
300 if (row >= row_count)
301 return ERROR_NO_MORE_ITEMS;
302
303 *rec = MSI_CreateRecord(col_count);
304 if (!*rec)
305 return ERROR_FUNCTION_FAILED;
306
307 for (i = 1; i <= col_count; i++)
308 {
309 ret = view->ops->get_column_info(view, i, NULL, &type, NULL, NULL);
310 if (ret)
311 {
312 ERR("Error getting column type for %d\n", i);
313 continue;
314 }
315
316 if (MSITYPE_IS_BINARY(type))
317 {
318 IStream *stm = NULL;
319
320 ret = view->ops->fetch_stream(view, row, i, &stm);
321 if ((ret == ERROR_SUCCESS) && stm)
322 {
323 MSI_RecordSetIStream(*rec, i, stm);
324 IStream_Release(stm);
325 }
326 else
327 WARN("failed to get stream\n");
328
329 continue;
330 }
331
332 ret = view->ops->fetch_int(view, row, i, &ival);
333 if (ret)
334 {
335 ERR("Error fetching data for %d\n", i);
336 continue;
337 }
338
339 if (! (type & MSITYPE_VALID))
340 ERR("Invalid type!\n");
341
342 /* check if it's nul (0) - if so, don't set anything */
343 if (!ival)
344 continue;
345
346 if (type & MSITYPE_STRING)
347 {
348 int len;
349 const WCHAR *sval = msi_string_lookup( db->strings, ival, &len );
350 msi_record_set_string( *rec, i, sval, len );
351 }
352 else
353 {
354 if ((type & MSI_DATASIZEMASK) == 2)
355 MSI_RecordSetInteger(*rec, i, ival - (1<<15));
356 else
357 MSI_RecordSetInteger(*rec, i, ival - (1u<<31));
358 }
359 }
360
361 return ERROR_SUCCESS;
362 }
363
364 UINT MSI_ViewFetch(MSIQUERY *query, MSIRECORD **prec)
365 {
366 MSIVIEW *view;
367 UINT r;
368
369 TRACE("%p %p\n", query, prec );
370
371 view = query->view;
372 if( !view )
373 return ERROR_FUNCTION_FAILED;
374
375 r = msi_view_get_row(query->db, view, query->row, prec);
376 if (r == ERROR_SUCCESS)
377 {
378 query->row ++;
379 MSI_RecordSetIntPtr(*prec, 0, (INT_PTR)query);
380 }
381
382 return r;
383 }
384
385 UINT WINAPI MsiViewFetch(MSIHANDLE hView, MSIHANDLE *record)
386 {
387 MSIQUERY *query;
388 MSIRECORD *rec = NULL;
389 UINT ret;
390
391 TRACE("%d %p\n", hView, record);
392
393 if( !record )
394 return ERROR_INVALID_PARAMETER;
395 *record = 0;
396
397 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
398 if( !query )
399 return ERROR_INVALID_HANDLE;
400 ret = MSI_ViewFetch( query, &rec );
401 if( ret == ERROR_SUCCESS )
402 {
403 *record = alloc_msihandle( &rec->hdr );
404 if (! *record)
405 ret = ERROR_NOT_ENOUGH_MEMORY;
406 msiobj_release( &rec->hdr );
407 }
408 msiobj_release( &query->hdr );
409 return ret;
410 }
411
412 UINT MSI_ViewClose(MSIQUERY *query)
413 {
414 MSIVIEW *view;
415
416 TRACE("%p\n", query );
417
418 view = query->view;
419 if( !view )
420 return ERROR_FUNCTION_FAILED;
421 if( !view->ops->close )
422 return ERROR_FUNCTION_FAILED;
423
424 return view->ops->close( view );
425 }
426
427 UINT WINAPI MsiViewClose(MSIHANDLE hView)
428 {
429 MSIQUERY *query;
430 UINT ret;
431
432 TRACE("%d\n", hView );
433
434 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
435 if( !query )
436 return ERROR_INVALID_HANDLE;
437
438 ret = MSI_ViewClose( query );
439 msiobj_release( &query->hdr );
440 return ret;
441 }
442
443 UINT MSI_ViewExecute(MSIQUERY *query, MSIRECORD *rec )
444 {
445 MSIVIEW *view;
446
447 TRACE("%p %p\n", query, rec);
448
449 view = query->view;
450 if( !view )
451 return ERROR_FUNCTION_FAILED;
452 if( !view->ops->execute )
453 return ERROR_FUNCTION_FAILED;
454 query->row = 0;
455
456 return view->ops->execute( view, rec );
457 }
458
459 UINT WINAPI MsiViewExecute(MSIHANDLE hView, MSIHANDLE hRec)
460 {
461 MSIQUERY *query;
462 MSIRECORD *rec = NULL;
463 UINT ret;
464
465 TRACE("%d %d\n", hView, hRec);
466
467 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
468 if( !query )
469 return ERROR_INVALID_HANDLE;
470
471 if( hRec )
472 {
473 rec = msihandle2msiinfo( hRec, MSIHANDLETYPE_RECORD );
474 if( !rec )
475 {
476 ret = ERROR_INVALID_HANDLE;
477 goto out;
478 }
479 }
480
481 msiobj_lock( &rec->hdr );
482 ret = MSI_ViewExecute( query, rec );
483 msiobj_unlock( &rec->hdr );
484
485 out:
486 msiobj_release( &query->hdr );
487 if( rec )
488 msiobj_release( &rec->hdr );
489
490 return ret;
491 }
492
493 static UINT msi_set_record_type_string( MSIRECORD *rec, UINT field,
494 UINT type, BOOL temporary )
495 {
496 static const WCHAR fmt[] = { '%','d',0 };
497 WCHAR szType[0x10];
498
499 if (MSITYPE_IS_BINARY(type))
500 szType[0] = 'v';
501 else if (type & MSITYPE_LOCALIZABLE)
502 szType[0] = 'l';
503 else if (type & MSITYPE_UNKNOWN)
504 szType[0] = 'f';
505 else if (type & MSITYPE_STRING)
506 {
507 if (temporary)
508 szType[0] = 'g';
509 else
510 szType[0] = 's';
511 }
512 else
513 {
514 if (temporary)
515 szType[0] = 'j';
516 else
517 szType[0] = 'i';
518 }
519
520 if (type & MSITYPE_NULLABLE)
521 szType[0] &= ~0x20;
522
523 sprintfW( &szType[1], fmt, (type&0xff) );
524
525 TRACE("type %04x -> %s\n", type, debugstr_w(szType) );
526
527 return MSI_RecordSetStringW( rec, field, szType );
528 }
529
530 UINT MSI_ViewGetColumnInfo( MSIQUERY *query, MSICOLINFO info, MSIRECORD **prec )
531 {
532 UINT r = ERROR_FUNCTION_FAILED, i, count = 0, type;
533 MSIRECORD *rec;
534 MSIVIEW *view = query->view;
535 LPCWSTR name;
536 BOOL temporary;
537
538 if( !view )
539 return ERROR_FUNCTION_FAILED;
540
541 if( !view->ops->get_dimensions )
542 return ERROR_FUNCTION_FAILED;
543
544 r = view->ops->get_dimensions( view, NULL, &count );
545 if( r != ERROR_SUCCESS )
546 return r;
547 if( !count )
548 return ERROR_INVALID_PARAMETER;
549
550 rec = MSI_CreateRecord( count );
551 if( !rec )
552 return ERROR_FUNCTION_FAILED;
553
554 for( i=0; i<count; i++ )
555 {
556 name = NULL;
557 r = view->ops->get_column_info( view, i+1, &name, &type, &temporary, NULL );
558 if( r != ERROR_SUCCESS )
559 continue;
560 if (info == MSICOLINFO_NAMES)
561 MSI_RecordSetStringW( rec, i+1, name );
562 else
563 msi_set_record_type_string( rec, i+1, type, temporary );
564 }
565 *prec = rec;
566 return ERROR_SUCCESS;
567 }
568
569 UINT WINAPI MsiViewGetColumnInfo(MSIHANDLE hView, MSICOLINFO info, MSIHANDLE *hRec)
570 {
571 MSIQUERY *query = NULL;
572 MSIRECORD *rec = NULL;
573 UINT r;
574
575 TRACE("%d %d %p\n", hView, info, hRec);
576
577 if( !hRec )
578 return ERROR_INVALID_PARAMETER;
579
580 if( info != MSICOLINFO_NAMES && info != MSICOLINFO_TYPES )
581 return ERROR_INVALID_PARAMETER;
582
583 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
584 if( !query )
585 return ERROR_INVALID_HANDLE;
586
587 r = MSI_ViewGetColumnInfo( query, info, &rec );
588 if ( r == ERROR_SUCCESS )
589 {
590 *hRec = alloc_msihandle( &rec->hdr );
591 if ( !*hRec )
592 r = ERROR_NOT_ENOUGH_MEMORY;
593 msiobj_release( &rec->hdr );
594 }
595
596 msiobj_release( &query->hdr );
597
598 return r;
599 }
600
601 UINT MSI_ViewModify( MSIQUERY *query, MSIMODIFY mode, MSIRECORD *rec )
602 {
603 MSIVIEW *view = NULL;
604 UINT r;
605
606 if ( !query || !rec )
607 return ERROR_INVALID_HANDLE;
608
609 view = query->view;
610 if ( !view || !view->ops->modify)
611 return ERROR_FUNCTION_FAILED;
612
613 if ( mode == MSIMODIFY_UPDATE && MSI_RecordGetIntPtr( rec, 0 ) != (INT_PTR)query )
614 return ERROR_FUNCTION_FAILED;
615
616 r = view->ops->modify( view, mode, rec, query->row );
617 if (mode == MSIMODIFY_DELETE && r == ERROR_SUCCESS)
618 query->row--;
619
620 return r;
621 }
622
623 UINT WINAPI MsiViewModify( MSIHANDLE hView, MSIMODIFY eModifyMode,
624 MSIHANDLE hRecord)
625 {
626 MSIQUERY *query = NULL;
627 MSIRECORD *rec = NULL;
628 UINT r = ERROR_FUNCTION_FAILED;
629
630 TRACE("%d %x %d\n", hView, eModifyMode, hRecord);
631
632 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
633 if( !query )
634 return ERROR_INVALID_HANDLE;
635
636 rec = msihandle2msiinfo( hRecord, MSIHANDLETYPE_RECORD );
637 r = MSI_ViewModify( query, eModifyMode, rec );
638
639 msiobj_release( &query->hdr );
640 if( rec )
641 msiobj_release( &rec->hdr );
642
643 return r;
644 }
645
646 MSIDBERROR WINAPI MsiViewGetErrorW( MSIHANDLE handle, LPWSTR buffer, LPDWORD buflen )
647 {
648 MSIQUERY *query;
649 const WCHAR *column;
650 MSIDBERROR r;
651 DWORD len;
652
653 TRACE("%u %p %p\n", handle, buffer, buflen);
654
655 if (!buflen)
656 return MSIDBERROR_INVALIDARG;
657
658 query = msihandle2msiinfo( handle, MSIHANDLETYPE_VIEW );
659 if( !query )
660 return MSIDBERROR_INVALIDARG;
661
662 if ((r = query->view->error)) column = query->view->error_column;
663 else column = szEmpty;
664
665 len = strlenW( column );
666 if (buffer)
667 {
668 if (*buflen > len)
669 strcpyW( buffer, column );
670 else
671 r = MSIDBERROR_MOREDATA;
672 }
673 *buflen = len;
674 msiobj_release( &query->hdr );
675 return r;
676 }
677
678 MSIDBERROR WINAPI MsiViewGetErrorA( MSIHANDLE handle, LPSTR buffer, LPDWORD buflen )
679 {
680 MSIQUERY *query;
681 const WCHAR *column;
682 MSIDBERROR r;
683 DWORD len;
684
685 TRACE("%u %p %p\n", handle, buffer, buflen);
686
687 if (!buflen)
688 return MSIDBERROR_INVALIDARG;
689
690 query = msihandle2msiinfo( handle, MSIHANDLETYPE_VIEW );
691 if (!query)
692 return MSIDBERROR_INVALIDARG;
693
694 if ((r = query->view->error)) column = query->view->error_column;
695 else column = szEmpty;
696
697 len = WideCharToMultiByte( CP_ACP, 0, column, -1, NULL, 0, NULL, NULL );
698 if (buffer)
699 {
700 if (*buflen >= len)
701 WideCharToMultiByte( CP_ACP, 0, column, -1, buffer, *buflen, NULL, NULL );
702 else
703 r = MSIDBERROR_MOREDATA;
704 }
705 *buflen = len - 1;
706 msiobj_release( &query->hdr );
707 return r;
708 }
709
710 MSIHANDLE WINAPI MsiGetLastErrorRecord( void )
711 {
712 FIXME("\n");
713 return 0;
714 }
715
716 UINT MSI_DatabaseApplyTransformW( MSIDATABASE *db,
717 LPCWSTR szTransformFile, int iErrorCond )
718 {
719 HRESULT r;
720 UINT ret = ERROR_FUNCTION_FAILED;
721 IStorage *stg = NULL;
722 STATSTG stat;
723
724 TRACE("%p %s %d\n", db, debugstr_w(szTransformFile), iErrorCond);
725
726 r = StgOpenStorage( szTransformFile, NULL,
727 STGM_DIRECT|STGM_READ|STGM_SHARE_DENY_WRITE, NULL, 0, &stg);
728 if ( FAILED(r) )
729 {
730 WARN("failed to open transform 0x%08x\n", r);
731 return ret;
732 }
733
734 r = IStorage_Stat( stg, &stat, STATFLAG_NONAME );
735 if ( FAILED( r ) )
736 goto end;
737
738 if ( !IsEqualGUID( &stat.clsid, &CLSID_MsiTransform ) )
739 goto end;
740
741 if( TRACE_ON( msi ) )
742 enum_stream_names( stg );
743
744 ret = msi_table_apply_transform( db, stg );
745
746 end:
747 IStorage_Release( stg );
748
749 return ret;
750 }
751
752 UINT WINAPI MsiDatabaseApplyTransformW( MSIHANDLE hdb,
753 LPCWSTR szTransformFile, int iErrorCond)
754 {
755 MSIDATABASE *db;
756 UINT r;
757
758 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
759 if( !db )
760 {
761 IWineMsiRemoteDatabase *remote_database;
762
763 remote_database = (IWineMsiRemoteDatabase *)msi_get_remote( hdb );
764 if ( !remote_database )
765 return ERROR_INVALID_HANDLE;
766
767 IWineMsiRemoteDatabase_Release( remote_database );
768 WARN("MsiDatabaseApplyTransform not allowed during a custom action!\n");
769
770 return ERROR_SUCCESS;
771 }
772
773 r = MSI_DatabaseApplyTransformW( db, szTransformFile, iErrorCond );
774 msiobj_release( &db->hdr );
775 return r;
776 }
777
778 UINT WINAPI MsiDatabaseApplyTransformA( MSIHANDLE hdb,
779 LPCSTR szTransformFile, int iErrorCond)
780 {
781 LPWSTR wstr;
782 UINT ret;
783
784 TRACE("%d %s %d\n", hdb, debugstr_a(szTransformFile), iErrorCond);
785
786 wstr = strdupAtoW( szTransformFile );
787 if( szTransformFile && !wstr )
788 return ERROR_NOT_ENOUGH_MEMORY;
789
790 ret = MsiDatabaseApplyTransformW( hdb, wstr, iErrorCond);
791
792 msi_free( wstr );
793
794 return ret;
795 }
796
797 UINT WINAPI MsiDatabaseGenerateTransformA( MSIHANDLE hdb, MSIHANDLE hdbref,
798 LPCSTR szTransformFile, int iReserved1, int iReserved2 )
799 {
800 FIXME("%d %d %s %d %d\n", hdb, hdbref,
801 debugstr_a(szTransformFile), iReserved1, iReserved2);
802 return ERROR_CALL_NOT_IMPLEMENTED;
803 }
804
805 UINT WINAPI MsiDatabaseGenerateTransformW( MSIHANDLE hdb, MSIHANDLE hdbref,
806 LPCWSTR szTransformFile, int iReserved1, int iReserved2 )
807 {
808 FIXME("%d %d %s %d %d\n", hdb, hdbref,
809 debugstr_w(szTransformFile), iReserved1, iReserved2);
810 return ERROR_CALL_NOT_IMPLEMENTED;
811 }
812
813 UINT WINAPI MsiDatabaseCommit( MSIHANDLE hdb )
814 {
815 MSIDATABASE *db;
816 UINT r;
817
818 TRACE("%d\n", hdb);
819
820 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
821 if( !db )
822 {
823 IWineMsiRemoteDatabase *remote_database;
824
825 remote_database = (IWineMsiRemoteDatabase *)msi_get_remote( hdb );
826 if ( !remote_database )
827 return ERROR_INVALID_HANDLE;
828
829 IWineMsiRemoteDatabase_Release( remote_database );
830 WARN("not allowed during a custom action!\n");
831
832 return ERROR_SUCCESS;
833 }
834
835 if (db->mode == MSIDBOPEN_READONLY)
836 {
837 msiobj_release( &db->hdr );
838 return ERROR_SUCCESS;
839 }
840
841 /* FIXME: lock the database */
842
843 r = msi_commit_streams( db );
844 if (r != ERROR_SUCCESS) ERR("Failed to commit streams!\n");
845 else
846 {
847 r = MSI_CommitTables( db );
848 if (r != ERROR_SUCCESS) ERR("Failed to commit tables!\n");
849 }
850
851 /* FIXME: unlock the database */
852
853 msiobj_release( &db->hdr );
854
855 if (r == ERROR_SUCCESS)
856 {
857 msi_free( db->deletefile );
858 db->deletefile = NULL;
859 }
860
861 return r;
862 }
863
864 struct msi_primary_key_record_info
865 {
866 DWORD n;
867 MSIRECORD *rec;
868 };
869
870 static UINT msi_primary_key_iterator( MSIRECORD *rec, LPVOID param )
871 {
872 struct msi_primary_key_record_info *info = param;
873 LPCWSTR name, table;
874 DWORD type;
875
876 type = MSI_RecordGetInteger( rec, 4 );
877 if( type & MSITYPE_KEY )
878 {
879 info->n++;
880 if( info->rec )
881 {
882 if ( info->n == 1 )
883 {
884 table = MSI_RecordGetString( rec, 1 );
885 MSI_RecordSetStringW( info->rec, 0, table);
886 }
887
888 name = MSI_RecordGetString( rec, 3 );
889 MSI_RecordSetStringW( info->rec, info->n, name );
890 }
891 }
892
893 return ERROR_SUCCESS;
894 }
895
896 UINT MSI_DatabaseGetPrimaryKeys( MSIDATABASE *db,
897 LPCWSTR table, MSIRECORD **prec )
898 {
899 static const WCHAR sql[] = {
900 's','e','l','e','c','t',' ','*',' ',
901 'f','r','o','m',' ','`','_','C','o','l','u','m','n','s','`',' ',
902 'w','h','e','r','e',' ',
903 '`','T','a','b','l','e','`',' ','=',' ','\'','%','s','\'',0 };
904 struct msi_primary_key_record_info info;
905 MSIQUERY *query = NULL;
906 UINT r;
907
908 if (!TABLE_Exists( db, table ))
909 return ERROR_INVALID_TABLE;
910
911 r = MSI_OpenQuery( db, &query, sql, table );
912 if( r != ERROR_SUCCESS )
913 return r;
914
915 /* count the number of primary key records */
916 info.n = 0;
917 info.rec = 0;
918 r = MSI_IterateRecords( query, 0, msi_primary_key_iterator, &info );
919 if( r == ERROR_SUCCESS )
920 {
921 TRACE("Found %d primary keys\n", info.n );
922
923 /* allocate a record and fill in the names of the tables */
924 info.rec = MSI_CreateRecord( info.n );
925 info.n = 0;
926 r = MSI_IterateRecords( query, 0, msi_primary_key_iterator, &info );
927 if( r == ERROR_SUCCESS )
928 *prec = info.rec;
929 else
930 msiobj_release( &info.rec->hdr );
931 }
932 msiobj_release( &query->hdr );
933
934 return r;
935 }
936
937 UINT WINAPI MsiDatabaseGetPrimaryKeysW( MSIHANDLE hdb,
938 LPCWSTR table, MSIHANDLE* phRec )
939 {
940 MSIRECORD *rec = NULL;
941 MSIDATABASE *db;
942 UINT r;
943
944 TRACE("%d %s %p\n", hdb, debugstr_w(table), phRec);
945
946 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
947 if( !db )
948 {
949 HRESULT hr;
950 IWineMsiRemoteDatabase *remote_database;
951
952 remote_database = (IWineMsiRemoteDatabase *)msi_get_remote( hdb );
953 if ( !remote_database )
954 return ERROR_INVALID_HANDLE;
955
956 hr = IWineMsiRemoteDatabase_GetPrimaryKeys( remote_database, table, phRec );
957 IWineMsiRemoteDatabase_Release( remote_database );
958
959 if (FAILED(hr))
960 {
961 if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
962 return HRESULT_CODE(hr);
963
964 return ERROR_FUNCTION_FAILED;
965 }
966
967 return ERROR_SUCCESS;
968 }
969
970 r = MSI_DatabaseGetPrimaryKeys( db, table, &rec );
971 if( r == ERROR_SUCCESS )
972 {
973 *phRec = alloc_msihandle( &rec->hdr );
974 if (! *phRec)
975 r = ERROR_NOT_ENOUGH_MEMORY;
976 msiobj_release( &rec->hdr );
977 }
978 msiobj_release( &db->hdr );
979
980 return r;
981 }
982
983 UINT WINAPI MsiDatabaseGetPrimaryKeysA(MSIHANDLE hdb,
984 LPCSTR table, MSIHANDLE* phRec)
985 {
986 LPWSTR szwTable = NULL;
987 UINT r;
988
989 TRACE("%d %s %p\n", hdb, debugstr_a(table), phRec);
990
991 if( table )
992 {
993 szwTable = strdupAtoW( table );
994 if( !szwTable )
995 return ERROR_OUTOFMEMORY;
996 }
997 r = MsiDatabaseGetPrimaryKeysW( hdb, szwTable, phRec );
998 msi_free( szwTable );
999
1000 return r;
1001 }
1002
1003 MSICONDITION WINAPI MsiDatabaseIsTablePersistentA(
1004 MSIHANDLE hDatabase, LPCSTR szTableName)
1005 {
1006 LPWSTR szwTableName = NULL;
1007 MSICONDITION r;
1008
1009 TRACE("%x %s\n", hDatabase, debugstr_a(szTableName));
1010
1011 if( szTableName )
1012 {
1013 szwTableName = strdupAtoW( szTableName );
1014 if( !szwTableName )
1015 return MSICONDITION_ERROR;
1016 }
1017 r = MsiDatabaseIsTablePersistentW( hDatabase, szwTableName );
1018 msi_free( szwTableName );
1019
1020 return r;
1021 }
1022
1023 MSICONDITION WINAPI MsiDatabaseIsTablePersistentW(
1024 MSIHANDLE hDatabase, LPCWSTR szTableName)
1025 {
1026 MSIDATABASE *db;
1027 MSICONDITION r;
1028
1029 TRACE("%x %s\n", hDatabase, debugstr_w(szTableName));
1030
1031 db = msihandle2msiinfo( hDatabase, MSIHANDLETYPE_DATABASE );
1032 if( !db )
1033 {
1034 HRESULT hr;
1035 MSICONDITION condition;
1036 IWineMsiRemoteDatabase *remote_database;
1037
1038 remote_database = (IWineMsiRemoteDatabase *)msi_get_remote( hDatabase );
1039 if ( !remote_database )
1040 return MSICONDITION_ERROR;
1041
1042 hr = IWineMsiRemoteDatabase_IsTablePersistent( remote_database,
1043 szTableName, &condition );
1044 IWineMsiRemoteDatabase_Release( remote_database );
1045
1046 if (FAILED(hr))
1047 return MSICONDITION_ERROR;
1048
1049 return condition;
1050 }
1051
1052 r = MSI_DatabaseIsTablePersistent( db, szTableName );
1053
1054 msiobj_release( &db->hdr );
1055
1056 return r;
1057 }