b9733820a69045e2cccb468a7c5ef61150f4cdad
[reactos.git] / reactos / 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, UINT *n )
60 {
61 LPWSTR col_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 col_name = NULL;
73 r = table->ops->get_column_info( table, i, &col_name, NULL, NULL );
74 if( r != ERROR_SUCCESS )
75 return r;
76 x = lstrcmpW( name, col_name );
77 msi_free( col_name );
78 if( !x )
79 {
80 *n = i;
81 return ERROR_SUCCESS;
82 }
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, (BSTR)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);
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 LPCWSTR sval;
349
350 sval = msi_string_lookup_id(db->strings, ival);
351 MSI_RecordSetStringW(*rec, i, sval);
352 }
353 else
354 {
355 if ((type & MSI_DATASIZEMASK) == 2)
356 MSI_RecordSetInteger(*rec, i, ival - (1<<15));
357 else
358 MSI_RecordSetInteger(*rec, i, ival - (1<<31));
359 }
360 }
361
362 return ERROR_SUCCESS;
363 }
364
365 UINT MSI_ViewFetch(MSIQUERY *query, MSIRECORD **prec)
366 {
367 MSIVIEW *view;
368 UINT r;
369
370 TRACE("%p %p\n", query, prec );
371
372 view = query->view;
373 if( !view )
374 return ERROR_FUNCTION_FAILED;
375
376 r = msi_view_get_row(query->db, view, query->row, prec);
377 if (r == ERROR_SUCCESS)
378 {
379 query->row ++;
380 MSI_RecordSetInteger(*prec, 0, (int)query);
381 }
382
383 return r;
384 }
385
386 UINT WINAPI MsiViewFetch(MSIHANDLE hView, MSIHANDLE *record)
387 {
388 MSIQUERY *query;
389 MSIRECORD *rec = NULL;
390 UINT ret;
391
392 TRACE("%d %p\n", hView, record);
393
394 if( !record )
395 return ERROR_INVALID_PARAMETER;
396 *record = 0;
397
398 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
399 if( !query )
400 return ERROR_INVALID_HANDLE;
401 ret = MSI_ViewFetch( query, &rec );
402 if( ret == ERROR_SUCCESS )
403 {
404 *record = alloc_msihandle( &rec->hdr );
405 if (! *record)
406 ret = ERROR_NOT_ENOUGH_MEMORY;
407 msiobj_release( &rec->hdr );
408 }
409 msiobj_release( &query->hdr );
410 return ret;
411 }
412
413 UINT MSI_ViewClose(MSIQUERY *query)
414 {
415 MSIVIEW *view;
416
417 TRACE("%p\n", query );
418
419 view = query->view;
420 if( !view )
421 return ERROR_FUNCTION_FAILED;
422 if( !view->ops->close )
423 return ERROR_FUNCTION_FAILED;
424
425 return view->ops->close( view );
426 }
427
428 UINT WINAPI MsiViewClose(MSIHANDLE hView)
429 {
430 MSIQUERY *query;
431 UINT ret;
432
433 TRACE("%d\n", hView );
434
435 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
436 if( !query )
437 return ERROR_INVALID_HANDLE;
438
439 ret = MSI_ViewClose( query );
440 msiobj_release( &query->hdr );
441 return ret;
442 }
443
444 UINT MSI_ViewExecute(MSIQUERY *query, MSIRECORD *rec )
445 {
446 MSIVIEW *view;
447
448 TRACE("%p %p\n", query, rec);
449
450 view = query->view;
451 if( !view )
452 return ERROR_FUNCTION_FAILED;
453 if( !view->ops->execute )
454 return ERROR_FUNCTION_FAILED;
455 query->row = 0;
456
457 return view->ops->execute( view, rec );
458 }
459
460 UINT WINAPI MsiViewExecute(MSIHANDLE hView, MSIHANDLE hRec)
461 {
462 MSIQUERY *query;
463 MSIRECORD *rec = NULL;
464 UINT ret;
465
466 TRACE("%d %d\n", hView, hRec);
467
468 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
469 if( !query )
470 return ERROR_INVALID_HANDLE;
471
472 if( hRec )
473 {
474 rec = msihandle2msiinfo( hRec, MSIHANDLETYPE_RECORD );
475 if( !rec )
476 {
477 ret = ERROR_INVALID_HANDLE;
478 goto out;
479 }
480 }
481
482 msiobj_lock( &rec->hdr );
483 ret = MSI_ViewExecute( query, rec );
484 msiobj_unlock( &rec->hdr );
485
486 out:
487 msiobj_release( &query->hdr );
488 if( rec )
489 msiobj_release( &rec->hdr );
490
491 return ret;
492 }
493
494 static UINT msi_set_record_type_string( MSIRECORD *rec, UINT field,
495 UINT type, BOOL temporary )
496 {
497 static const WCHAR fmt[] = { '%','d',0 };
498 WCHAR szType[0x10];
499
500 if (MSITYPE_IS_BINARY(type))
501 szType[0] = 'v';
502 else if (type & MSITYPE_LOCALIZABLE)
503 szType[0] = 'l';
504 else if (type & MSITYPE_STRING)
505 {
506 if (temporary)
507 szType[0] = 'g';
508 else
509 szType[0] = 's';
510 }
511 else
512 {
513 if (temporary)
514 szType[0] = 'j';
515 else
516 szType[0] = 'i';
517 }
518
519 if (type & MSITYPE_NULLABLE)
520 szType[0] &= ~0x20;
521
522 sprintfW( &szType[1], fmt, (type&0xff) );
523
524 TRACE("type %04x -> %s\n", type, debugstr_w(szType) );
525
526 return MSI_RecordSetStringW( rec, field, szType );
527 }
528
529 UINT MSI_ViewGetColumnInfo( MSIQUERY *query, MSICOLINFO info, MSIRECORD **prec )
530 {
531 UINT r = ERROR_FUNCTION_FAILED, i, count = 0, type;
532 MSIRECORD *rec;
533 MSIVIEW *view = query->view;
534 LPWSTR name;
535 BOOL temporary;
536
537 if( !view )
538 return ERROR_FUNCTION_FAILED;
539
540 if( !view->ops->get_dimensions )
541 return ERROR_FUNCTION_FAILED;
542
543 r = view->ops->get_dimensions( view, NULL, &count );
544 if( r != ERROR_SUCCESS )
545 return r;
546 if( !count )
547 return ERROR_INVALID_PARAMETER;
548
549 rec = MSI_CreateRecord( count );
550 if( !rec )
551 return ERROR_FUNCTION_FAILED;
552
553 for( i=0; i<count; i++ )
554 {
555 name = NULL;
556 r = view->ops->get_column_info( view, i+1, &name, &type, &temporary );
557 if( r != ERROR_SUCCESS )
558 continue;
559 if (info == MSICOLINFO_NAMES)
560 MSI_RecordSetStringW( rec, i+1, name );
561 else
562 msi_set_record_type_string( rec, i+1, type, temporary );
563 msi_free( name );
564 }
565
566 *prec = rec;
567 return ERROR_SUCCESS;
568 }
569
570 UINT WINAPI MsiViewGetColumnInfo(MSIHANDLE hView, MSICOLINFO info, MSIHANDLE *hRec)
571 {
572 MSIQUERY *query = NULL;
573 MSIRECORD *rec = NULL;
574 UINT r;
575
576 TRACE("%d %d %p\n", hView, info, hRec);
577
578 if( !hRec )
579 return ERROR_INVALID_PARAMETER;
580
581 if( info != MSICOLINFO_NAMES && info != MSICOLINFO_TYPES )
582 return ERROR_INVALID_PARAMETER;
583
584 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
585 if( !query )
586 return ERROR_INVALID_HANDLE;
587
588 r = MSI_ViewGetColumnInfo( query, info, &rec );
589 if ( r == ERROR_SUCCESS )
590 {
591 *hRec = alloc_msihandle( &rec->hdr );
592 if ( !*hRec )
593 r = ERROR_NOT_ENOUGH_MEMORY;
594 msiobj_release( &rec->hdr );
595 }
596
597 msiobj_release( &query->hdr );
598
599 return r;
600 }
601
602 UINT MSI_ViewModify( MSIQUERY *query, MSIMODIFY mode, MSIRECORD *rec )
603 {
604 MSIVIEW *view = NULL;
605 UINT r;
606
607 if ( !query || !rec )
608 return ERROR_INVALID_HANDLE;
609
610 view = query->view;
611 if ( !view || !view->ops->modify)
612 return ERROR_FUNCTION_FAILED;
613
614 if ( mode == MSIMODIFY_UPDATE && MSI_RecordGetInteger( rec, 0 ) != (int)query )
615 return ERROR_FUNCTION_FAILED;
616
617 r = view->ops->modify( view, mode, rec, query->row );
618 if (mode == MSIMODIFY_DELETE && r == ERROR_SUCCESS)
619 query->row--;
620
621 return r;
622 }
623
624 UINT WINAPI MsiViewModify( MSIHANDLE hView, MSIMODIFY eModifyMode,
625 MSIHANDLE hRecord)
626 {
627 MSIQUERY *query = NULL;
628 MSIRECORD *rec = NULL;
629 UINT r = ERROR_FUNCTION_FAILED;
630
631 TRACE("%d %x %d\n", hView, eModifyMode, hRecord);
632
633 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
634 if( !query )
635 return ERROR_INVALID_HANDLE;
636
637 rec = msihandle2msiinfo( hRecord, MSIHANDLETYPE_RECORD );
638 r = MSI_ViewModify( query, eModifyMode, rec );
639
640 msiobj_release( &query->hdr );
641 if( rec )
642 msiobj_release( &rec->hdr );
643
644 return r;
645 }
646
647 MSIDBERROR WINAPI MsiViewGetErrorW( MSIHANDLE handle, LPWSTR szColumnNameBuffer,
648 LPDWORD pcchBuf )
649 {
650 MSIQUERY *query = NULL;
651 static const WCHAR szError[] = { 0 };
652 MSIDBERROR r = MSIDBERROR_NOERROR;
653 DWORD len;
654
655 FIXME("%d %p %p - returns empty error string\n",
656 handle, szColumnNameBuffer, pcchBuf );
657
658 if( !pcchBuf )
659 return MSIDBERROR_INVALIDARG;
660
661 query = msihandle2msiinfo( handle, MSIHANDLETYPE_VIEW );
662 if( !query )
663 return MSIDBERROR_INVALIDARG;
664
665 len = strlenW( szError );
666 if( szColumnNameBuffer )
667 {
668 if( *pcchBuf > len )
669 lstrcpyW( szColumnNameBuffer, szError );
670 else
671 r = MSIDBERROR_MOREDATA;
672 }
673 *pcchBuf = len;
674
675 msiobj_release( &query->hdr );
676 return r;
677 }
678
679 MSIDBERROR WINAPI MsiViewGetErrorA( MSIHANDLE handle, LPSTR szColumnNameBuffer,
680 LPDWORD pcchBuf )
681 {
682 static const CHAR szError[] = { 0 };
683 MSIQUERY *query = NULL;
684 MSIDBERROR r = MSIDBERROR_NOERROR;
685 DWORD len;
686
687 FIXME("%d %p %p - returns empty error string\n",
688 handle, szColumnNameBuffer, pcchBuf );
689
690 if( !pcchBuf )
691 return MSIDBERROR_INVALIDARG;
692
693 query = msihandle2msiinfo( handle, MSIHANDLETYPE_VIEW );
694 if( !query )
695 return MSIDBERROR_INVALIDARG;
696
697 len = strlen( szError );
698 if( szColumnNameBuffer )
699 {
700 if( *pcchBuf > len )
701 lstrcpyA( szColumnNameBuffer, szError );
702 else
703 r = MSIDBERROR_MOREDATA;
704 }
705 *pcchBuf = len;
706
707 msiobj_release( &query->hdr );
708 return r;
709 }
710
711 MSIHANDLE WINAPI MsiGetLastErrorRecord( void )
712 {
713 FIXME("\n");
714 return 0;
715 }
716
717 UINT MSI_DatabaseApplyTransformW( MSIDATABASE *db,
718 LPCWSTR szTransformFile, int iErrorCond )
719 {
720 HRESULT r;
721 UINT ret = ERROR_FUNCTION_FAILED;
722 IStorage *stg = NULL;
723 STATSTG stat;
724
725 TRACE("%p %s %d\n", db, debugstr_w(szTransformFile), iErrorCond);
726
727 r = StgOpenStorage( szTransformFile, NULL,
728 STGM_DIRECT|STGM_READ|STGM_SHARE_DENY_WRITE, NULL, 0, &stg);
729 if ( FAILED(r) )
730 return ret;
731
732 r = IStorage_Stat( stg, &stat, STATFLAG_NONAME );
733 if ( FAILED( r ) )
734 goto end;
735
736 if ( !IsEqualGUID( &stat.clsid, &CLSID_MsiTransform ) )
737 goto end;
738
739 if( TRACE_ON( msi ) )
740 enum_stream_names( stg );
741
742 ret = msi_table_apply_transform( db, stg );
743
744 end:
745 IStorage_Release( stg );
746
747 return ret;
748 }
749
750 UINT WINAPI MsiDatabaseApplyTransformW( MSIHANDLE hdb,
751 LPCWSTR szTransformFile, int iErrorCond)
752 {
753 MSIDATABASE *db;
754 UINT r;
755
756 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
757 if( !db )
758 {
759 IWineMsiRemoteDatabase *remote_database;
760
761 remote_database = (IWineMsiRemoteDatabase *)msi_get_remote( hdb );
762 if ( !remote_database )
763 return ERROR_INVALID_HANDLE;
764
765 IWineMsiRemoteDatabase_Release( remote_database );
766 WARN("MsiDatabaseApplyTransform not allowed during a custom action!\n");
767
768 return ERROR_SUCCESS;
769 }
770
771 r = MSI_DatabaseApplyTransformW( db, szTransformFile, iErrorCond );
772 msiobj_release( &db->hdr );
773 return r;
774 }
775
776 UINT WINAPI MsiDatabaseApplyTransformA( MSIHANDLE hdb,
777 LPCSTR szTransformFile, int iErrorCond)
778 {
779 LPWSTR wstr;
780 UINT ret;
781
782 TRACE("%d %s %d\n", hdb, debugstr_a(szTransformFile), iErrorCond);
783
784 wstr = strdupAtoW( szTransformFile );
785 if( szTransformFile && !wstr )
786 return ERROR_NOT_ENOUGH_MEMORY;
787
788 ret = MsiDatabaseApplyTransformW( hdb, wstr, iErrorCond);
789
790 msi_free( wstr );
791
792 return ret;
793 }
794
795 UINT WINAPI MsiDatabaseGenerateTransformA( MSIHANDLE hdb, MSIHANDLE hdbref,
796 LPCSTR szTransformFile, int iReserved1, int iReserved2 )
797 {
798 FIXME("%d %d %s %d %d\n", hdb, hdbref,
799 debugstr_a(szTransformFile), iReserved1, iReserved2);
800 return ERROR_CALL_NOT_IMPLEMENTED;
801 }
802
803 UINT WINAPI MsiDatabaseGenerateTransformW( MSIHANDLE hdb, MSIHANDLE hdbref,
804 LPCWSTR szTransformFile, int iReserved1, int iReserved2 )
805 {
806 FIXME("%d %d %s %d %d\n", hdb, hdbref,
807 debugstr_w(szTransformFile), iReserved1, iReserved2);
808 return ERROR_CALL_NOT_IMPLEMENTED;
809 }
810
811 UINT WINAPI MsiDatabaseCommit( MSIHANDLE hdb )
812 {
813 MSIDATABASE *db;
814 UINT r;
815
816 TRACE("%d\n", hdb);
817
818 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
819 if( !db )
820 {
821 IWineMsiRemoteDatabase *remote_database;
822
823 remote_database = (IWineMsiRemoteDatabase *)msi_get_remote( hdb );
824 if ( !remote_database )
825 return ERROR_INVALID_HANDLE;
826
827 IWineMsiRemoteDatabase_Release( remote_database );
828 WARN("MsiDatabaseCommit not allowed during a custom action!\n");
829
830 return ERROR_SUCCESS;
831 }
832
833 /* FIXME: lock the database */
834
835 r = MSI_CommitTables( db );
836 if (r != ERROR_SUCCESS) ERR("Failed to commit tables!\n");
837
838 /* FIXME: unlock the database */
839
840 msiobj_release( &db->hdr );
841
842 if (r == ERROR_SUCCESS)
843 {
844 msi_free( db->deletefile );
845 db->deletefile = NULL;
846 }
847
848 return r;
849 }
850
851 struct msi_primary_key_record_info
852 {
853 DWORD n;
854 MSIRECORD *rec;
855 };
856
857 static UINT msi_primary_key_iterator( MSIRECORD *rec, LPVOID param )
858 {
859 struct msi_primary_key_record_info *info = param;
860 LPCWSTR name, table;
861 DWORD type;
862
863 type = MSI_RecordGetInteger( rec, 4 );
864 if( type & MSITYPE_KEY )
865 {
866 info->n++;
867 if( info->rec )
868 {
869 if ( info->n == 1 )
870 {
871 table = MSI_RecordGetString( rec, 1 );
872 MSI_RecordSetStringW( info->rec, 0, table);
873 }
874
875 name = MSI_RecordGetString( rec, 3 );
876 MSI_RecordSetStringW( info->rec, info->n, name );
877 }
878 }
879
880 return ERROR_SUCCESS;
881 }
882
883 UINT MSI_DatabaseGetPrimaryKeys( MSIDATABASE *db,
884 LPCWSTR table, MSIRECORD **prec )
885 {
886 static const WCHAR sql[] = {
887 's','e','l','e','c','t',' ','*',' ',
888 'f','r','o','m',' ','`','_','C','o','l','u','m','n','s','`',' ',
889 'w','h','e','r','e',' ',
890 '`','T','a','b','l','e','`',' ','=',' ','\'','%','s','\'',0 };
891 struct msi_primary_key_record_info info;
892 MSIQUERY *query = NULL;
893 UINT r;
894
895 r = MSI_OpenQuery( db, &query, sql, table );
896 if( r != ERROR_SUCCESS )
897 return r;
898
899 /* count the number of primary key records */
900 info.n = 0;
901 info.rec = 0;
902 r = MSI_IterateRecords( query, 0, msi_primary_key_iterator, &info );
903 if( r == ERROR_SUCCESS )
904 {
905 TRACE("Found %d primary keys\n", info.n );
906
907 /* allocate a record and fill in the names of the tables */
908 info.rec = MSI_CreateRecord( info.n );
909 info.n = 0;
910 r = MSI_IterateRecords( query, 0, msi_primary_key_iterator, &info );
911 if( r == ERROR_SUCCESS )
912 *prec = info.rec;
913 else
914 msiobj_release( &info.rec->hdr );
915 }
916 msiobj_release( &query->hdr );
917
918 return r;
919 }
920
921 UINT WINAPI MsiDatabaseGetPrimaryKeysW( MSIHANDLE hdb,
922 LPCWSTR table, MSIHANDLE* phRec )
923 {
924 MSIRECORD *rec = NULL;
925 MSIDATABASE *db;
926 UINT r;
927
928 TRACE("%d %s %p\n", hdb, debugstr_w(table), phRec);
929
930 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
931 if( !db )
932 {
933 HRESULT hr;
934 IWineMsiRemoteDatabase *remote_database;
935
936 remote_database = (IWineMsiRemoteDatabase *)msi_get_remote( hdb );
937 if ( !remote_database )
938 return ERROR_INVALID_HANDLE;
939
940 hr = IWineMsiRemoteDatabase_GetPrimaryKeys( remote_database, (BSTR)table, phRec );
941 IWineMsiRemoteDatabase_Release( remote_database );
942
943 if (FAILED(hr))
944 {
945 if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
946 return HRESULT_CODE(hr);
947
948 return ERROR_FUNCTION_FAILED;
949 }
950
951 return ERROR_SUCCESS;
952 }
953
954 r = MSI_DatabaseGetPrimaryKeys( db, table, &rec );
955 if( r == ERROR_SUCCESS )
956 {
957 *phRec = alloc_msihandle( &rec->hdr );
958 if (! *phRec)
959 r = ERROR_NOT_ENOUGH_MEMORY;
960 msiobj_release( &rec->hdr );
961 }
962 msiobj_release( &db->hdr );
963
964 return r;
965 }
966
967 UINT WINAPI MsiDatabaseGetPrimaryKeysA(MSIHANDLE hdb,
968 LPCSTR table, MSIHANDLE* phRec)
969 {
970 LPWSTR szwTable = NULL;
971 UINT r;
972
973 TRACE("%d %s %p\n", hdb, debugstr_a(table), phRec);
974
975 if( table )
976 {
977 szwTable = strdupAtoW( table );
978 if( !szwTable )
979 return ERROR_OUTOFMEMORY;
980 }
981 r = MsiDatabaseGetPrimaryKeysW( hdb, szwTable, phRec );
982 msi_free( szwTable );
983
984 return r;
985 }
986
987 MSICONDITION WINAPI MsiDatabaseIsTablePersistentA(
988 MSIHANDLE hDatabase, LPCSTR szTableName)
989 {
990 LPWSTR szwTableName = NULL;
991 MSICONDITION r;
992
993 TRACE("%x %s\n", hDatabase, debugstr_a(szTableName));
994
995 if( szTableName )
996 {
997 szwTableName = strdupAtoW( szTableName );
998 if( !szwTableName )
999 return MSICONDITION_ERROR;
1000 }
1001 r = MsiDatabaseIsTablePersistentW( hDatabase, szwTableName );
1002 msi_free( szwTableName );
1003
1004 return r;
1005 }
1006
1007 MSICONDITION WINAPI MsiDatabaseIsTablePersistentW(
1008 MSIHANDLE hDatabase, LPCWSTR szTableName)
1009 {
1010 MSIDATABASE *db;
1011 MSICONDITION r;
1012
1013 TRACE("%x %s\n", hDatabase, debugstr_w(szTableName));
1014
1015 db = msihandle2msiinfo( hDatabase, MSIHANDLETYPE_DATABASE );
1016 if( !db )
1017 {
1018 HRESULT hr;
1019 MSICONDITION condition;
1020 IWineMsiRemoteDatabase *remote_database;
1021
1022 remote_database = (IWineMsiRemoteDatabase *)msi_get_remote( hDatabase );
1023 if ( !remote_database )
1024 return MSICONDITION_ERROR;
1025
1026 hr = IWineMsiRemoteDatabase_IsTablePersistent( remote_database,
1027 (BSTR)szTableName, &condition );
1028 IWineMsiRemoteDatabase_Release( remote_database );
1029
1030 if (FAILED(hr))
1031 return MSICONDITION_ERROR;
1032
1033 return condition;
1034 }
1035
1036 r = MSI_DatabaseIsTablePersistent( db, szTableName );
1037
1038 msiobj_release( &db->hdr );
1039
1040 return r;
1041 }