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