user32: Remove _wassert workaround.
[wine.git] / dlls / msi / msiquery.c
blobb3a499a0788db9ad9ca05b6083a183e16129d915
1 /*
2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2002-2005 Mike McCormack for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
23 #define COBJMACROS
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winerror.h"
28 #include "wine/debug.h"
29 #include "wine/exception.h"
30 #include "msi.h"
31 #include "msiquery.h"
32 #include "objbase.h"
33 #include "objidl.h"
34 #include "winnls.h"
36 #include "msipriv.h"
37 #include "query.h"
38 #include "winemsi.h"
40 #include "initguid.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(msi);
44 static void MSI_CloseView( MSIOBJECTHDR *arg )
46 MSIQUERY *query = (MSIQUERY*) arg;
47 struct list *ptr, *t;
49 if( query->view && query->view->ops->delete )
50 query->view->ops->delete( query->view );
51 msiobj_release( &query->db->hdr );
53 LIST_FOR_EACH_SAFE( ptr, t, &query->mem )
55 msi_free( ptr );
59 UINT VIEW_find_column( MSIVIEW *table, LPCWSTR name, LPCWSTR table_name, UINT *n )
61 LPCWSTR col_name, haystack_table_name;
62 UINT i, count, r;
64 r = table->ops->get_dimensions( table, NULL, &count );
65 if( r != ERROR_SUCCESS )
66 return r;
68 for( i=1; i<=count; i++ )
70 INT x;
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 = wcscmp( name, col_name );
77 if( table_name )
78 x |= wcscmp( table_name, haystack_table_name );
79 if( !x )
81 *n = i;
82 return ERROR_SUCCESS;
85 return ERROR_INVALID_PARAMETER;
88 UINT WINAPI MsiDatabaseOpenViewA(MSIHANDLE hdb,
89 LPCSTR szQuery, MSIHANDLE *phView)
91 UINT r;
92 LPWSTR szwQuery;
94 TRACE("%d %s %p\n", hdb, debugstr_a(szQuery), phView);
96 if( szQuery )
98 szwQuery = strdupAtoW( szQuery );
99 if( !szwQuery )
100 return ERROR_FUNCTION_FAILED;
102 else
103 szwQuery = NULL;
105 r = MsiDatabaseOpenViewW( hdb, szwQuery, phView);
107 msi_free( szwQuery );
108 return r;
111 UINT MSI_DatabaseOpenViewW(MSIDATABASE *db,
112 LPCWSTR szQuery, MSIQUERY **pView)
114 MSIQUERY *query;
115 UINT r;
117 TRACE("%s %p\n", debugstr_w(szQuery), pView);
119 /* pre allocate a handle to hold a pointer to the view */
120 query = alloc_msiobject( MSIHANDLETYPE_VIEW, sizeof (MSIQUERY),
121 MSI_CloseView );
122 if( !query )
123 return ERROR_FUNCTION_FAILED;
125 msiobj_addref( &db->hdr );
126 query->db = db;
127 list_init( &query->mem );
129 r = MSI_ParseSQL( db, szQuery, &query->view, &query->mem );
130 if( r == ERROR_SUCCESS )
132 msiobj_addref( &query->hdr );
133 *pView = query;
136 msiobj_release( &query->hdr );
137 return r;
140 UINT WINAPIV MSI_OpenQuery( MSIDATABASE *db, MSIQUERY **view, LPCWSTR fmt, ... )
142 UINT r;
143 int size = 100, res;
144 LPWSTR query;
146 /* construct the string */
147 for (;;)
149 va_list va;
150 query = msi_alloc( size*sizeof(WCHAR) );
151 va_start(va, fmt);
152 res = vswprintf(query, size, fmt, va);
153 va_end(va);
154 if (res == -1) size *= 2;
155 else if (res >= size) size = res + 1;
156 else break;
157 msi_free( query );
159 /* perform the query */
160 r = MSI_DatabaseOpenViewW(db, query, view);
161 msi_free(query);
162 return r;
165 UINT MSI_IterateRecords( MSIQUERY *view, LPDWORD count,
166 record_func func, LPVOID param )
168 MSIRECORD *rec = NULL;
169 UINT r, n = 0, max = 0;
171 r = MSI_ViewExecute( view, NULL );
172 if( r != ERROR_SUCCESS )
173 return r;
175 if( count )
176 max = *count;
178 /* iterate a query */
179 for( n = 0; (max == 0) || (n < max); n++ )
181 r = MSI_ViewFetch( view, &rec );
182 if( r != ERROR_SUCCESS )
183 break;
184 if (func)
185 r = func( rec, param );
186 msiobj_release( &rec->hdr );
187 if( r != ERROR_SUCCESS )
188 break;
191 MSI_ViewClose( view );
193 if( count )
194 *count = n;
196 if( r == ERROR_NO_MORE_ITEMS )
197 r = ERROR_SUCCESS;
199 return r;
202 /* return a single record from a query */
203 MSIRECORD * WINAPIV MSI_QueryGetRecord( MSIDATABASE *db, LPCWSTR fmt, ... )
205 MSIRECORD *rec = NULL;
206 MSIQUERY *view = NULL;
207 UINT r;
208 int size = 100, res;
209 LPWSTR query;
211 /* construct the string */
212 for (;;)
214 va_list va;
215 query = msi_alloc( size*sizeof(WCHAR) );
216 va_start(va, fmt);
217 res = vswprintf(query, size, fmt, va);
218 va_end(va);
219 if (res == -1) size *= 2;
220 else if (res >= size) size = res + 1;
221 else break;
222 msi_free( query );
224 /* perform the query */
225 r = MSI_DatabaseOpenViewW(db, query, &view);
226 msi_free(query);
228 if( r == ERROR_SUCCESS )
230 MSI_ViewExecute( view, NULL );
231 MSI_ViewFetch( view, &rec );
232 MSI_ViewClose( view );
233 msiobj_release( &view->hdr );
235 return rec;
238 UINT WINAPI MsiDatabaseOpenViewW(MSIHANDLE hdb,
239 LPCWSTR szQuery, MSIHANDLE *phView)
241 MSIDATABASE *db;
242 MSIQUERY *query = NULL;
243 UINT ret;
245 TRACE("%s %p\n", debugstr_w(szQuery), phView);
247 if (!phView)
248 return ERROR_INVALID_PARAMETER;
250 if (!szQuery)
251 return ERROR_BAD_QUERY_SYNTAX;
253 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
254 if( !db )
256 MSIHANDLE remote, remote_view;
258 if (!(remote = msi_get_remote(hdb)))
259 return ERROR_INVALID_HANDLE;
261 __TRY
263 ret = remote_DatabaseOpenView(remote, szQuery, &remote_view);
265 __EXCEPT(rpc_filter)
267 ret = GetExceptionCode();
269 __ENDTRY
271 if (!ret)
272 *phView = alloc_msi_remote_handle(remote_view);
273 return ret;
276 ret = MSI_DatabaseOpenViewW( db, szQuery, &query );
277 if( ret == ERROR_SUCCESS )
279 *phView = alloc_msihandle( &query->hdr );
280 if (! *phView)
281 ret = ERROR_NOT_ENOUGH_MEMORY;
282 msiobj_release( &query->hdr );
284 msiobj_release( &db->hdr );
286 return ret;
289 UINT msi_view_refresh_row(MSIDATABASE *db, MSIVIEW *view, UINT row, MSIRECORD *rec)
291 UINT row_count = 0, col_count = 0, i, ival, ret, type;
293 TRACE("%p %p %d %p\n", db, view, row, rec);
295 ret = view->ops->get_dimensions(view, &row_count, &col_count);
296 if (ret)
297 return ret;
299 if (!col_count)
300 return ERROR_INVALID_PARAMETER;
302 for (i = 1; i <= col_count; i++)
304 ret = view->ops->get_column_info(view, i, NULL, &type, NULL, NULL);
305 if (ret)
307 ERR("Error getting column type for %d\n", i);
308 continue;
311 if (MSITYPE_IS_BINARY(type))
313 IStream *stm = NULL;
315 ret = view->ops->fetch_stream(view, row, i, &stm);
316 if ((ret == ERROR_SUCCESS) && stm)
318 MSI_RecordSetIStream(rec, i, stm);
319 IStream_Release(stm);
321 else
322 WARN("failed to get stream\n");
324 continue;
327 ret = view->ops->fetch_int(view, row, i, &ival);
328 if (ret)
330 ERR("Error fetching data for %d\n", i);
331 continue;
334 if (! (type & MSITYPE_VALID))
335 ERR("Invalid type!\n");
337 if (type & MSITYPE_STRING)
339 int len;
340 const WCHAR *sval = msi_string_lookup(db->strings, ival, &len);
341 msi_record_set_string(rec, i, sval, len);
343 else
345 if ((type & MSI_DATASIZEMASK) == 2)
346 MSI_RecordSetInteger(rec, i, ival ? ival - (1<<15) : MSI_NULL_INTEGER);
347 else
348 MSI_RecordSetInteger(rec, i, ival - (1u<<31));
352 return ERROR_SUCCESS;
355 UINT msi_view_get_row(MSIDATABASE *db, MSIVIEW *view, UINT row, MSIRECORD **rec)
357 UINT row_count = 0, col_count = 0, r;
358 MSIRECORD *object;
360 TRACE("view %p, row %u, rec %p.\n", view, row, rec);
362 if ((r = view->ops->get_dimensions(view, &row_count, &col_count)))
363 return r;
365 if (row >= row_count)
366 return ERROR_NO_MORE_ITEMS;
368 if (!(object = MSI_CreateRecord( col_count )))
369 return ERROR_OUTOFMEMORY;
371 if ((r = msi_view_refresh_row(db, view, row, object)))
372 msiobj_release( &object->hdr );
373 else
374 *rec = object;
376 return r;
379 UINT MSI_ViewFetch(MSIQUERY *query, MSIRECORD **prec)
381 MSIVIEW *view;
382 UINT r;
384 TRACE("%p %p\n", query, prec );
386 view = query->view;
387 if( !view )
388 return ERROR_FUNCTION_FAILED;
390 r = msi_view_get_row(query->db, view, query->row, prec);
391 if (r == ERROR_SUCCESS)
393 query->row ++;
394 (*prec)->cookie = (UINT64)(ULONG_PTR)query;
395 MSI_RecordSetInteger(*prec, 0, 1);
397 else if (r == ERROR_NO_MORE_ITEMS)
399 /* end of view; reset cursor to first row */
400 query->row = 0;
403 return r;
406 UINT WINAPI MsiViewFetch(MSIHANDLE hView, MSIHANDLE *record)
408 MSIQUERY *query;
409 MSIRECORD *rec = NULL;
410 UINT ret;
412 TRACE("%d %p\n", hView, record);
414 if( !record )
415 return ERROR_INVALID_PARAMETER;
416 *record = 0;
418 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
419 if (!query)
421 struct wire_record *wire_rec = NULL;
422 MSIHANDLE remote;
424 if (!(remote = msi_get_remote(hView)))
425 return ERROR_INVALID_HANDLE;
427 __TRY
429 ret = remote_ViewFetch(remote, &wire_rec);
431 __EXCEPT(rpc_filter)
433 ret = GetExceptionCode();
435 __ENDTRY
437 if (!ret)
439 ret = unmarshal_record(wire_rec, record);
440 free_remote_record(wire_rec);
442 return ret;
444 ret = MSI_ViewFetch( query, &rec );
445 if( ret == ERROR_SUCCESS )
447 *record = alloc_msihandle( &rec->hdr );
448 if (! *record)
449 ret = ERROR_NOT_ENOUGH_MEMORY;
450 msiobj_release( &rec->hdr );
452 msiobj_release( &query->hdr );
453 return ret;
456 UINT MSI_ViewClose(MSIQUERY *query)
458 MSIVIEW *view;
460 TRACE("%p\n", query );
462 view = query->view;
463 if( !view )
464 return ERROR_FUNCTION_FAILED;
465 if( !view->ops->close )
466 return ERROR_FUNCTION_FAILED;
468 return view->ops->close( view );
471 UINT WINAPI MsiViewClose(MSIHANDLE hView)
473 MSIQUERY *query;
474 UINT ret;
476 TRACE("%d\n", hView );
478 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
479 if (!query)
481 MSIHANDLE remote;
483 if (!(remote = msi_get_remote(hView)))
484 return ERROR_INVALID_HANDLE;
486 __TRY
488 ret = remote_ViewClose(remote);
490 __EXCEPT(rpc_filter)
492 ret = GetExceptionCode();
494 __ENDTRY
496 return ret;
499 ret = MSI_ViewClose( query );
500 msiobj_release( &query->hdr );
501 return ret;
504 UINT MSI_ViewExecute(MSIQUERY *query, MSIRECORD *rec )
506 MSIVIEW *view;
508 TRACE("%p %p\n", query, rec);
510 view = query->view;
511 if( !view )
512 return ERROR_FUNCTION_FAILED;
513 if( !view->ops->execute )
514 return ERROR_FUNCTION_FAILED;
515 query->row = 0;
517 return view->ops->execute( view, rec );
520 UINT WINAPI MsiViewExecute(MSIHANDLE hView, MSIHANDLE hRec)
522 MSIQUERY *query;
523 MSIRECORD *rec = NULL;
524 UINT ret;
526 TRACE("%d %d\n", hView, hRec);
528 if( hRec )
530 rec = msihandle2msiinfo( hRec, MSIHANDLETYPE_RECORD );
531 if( !rec )
532 return ERROR_INVALID_HANDLE;
535 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
536 if( !query )
538 MSIHANDLE remote;
540 if (!(remote = msi_get_remote(hView)))
541 return ERROR_INVALID_HANDLE;
543 __TRY
545 ret = remote_ViewExecute(remote, rec ? (struct wire_record *)&rec->count : NULL);
547 __EXCEPT(rpc_filter)
549 ret = GetExceptionCode();
551 __ENDTRY
553 if (rec)
554 msiobj_release(&rec->hdr);
555 return ret;
558 msiobj_lock( &rec->hdr );
559 ret = MSI_ViewExecute( query, rec );
560 msiobj_unlock( &rec->hdr );
562 msiobj_release( &query->hdr );
563 if( rec )
564 msiobj_release( &rec->hdr );
566 return ret;
569 static UINT msi_set_record_type_string( MSIRECORD *rec, UINT field,
570 UINT type, BOOL temporary )
572 WCHAR szType[0x10];
574 if (MSITYPE_IS_BINARY(type))
575 szType[0] = 'v';
576 else if (type & MSITYPE_LOCALIZABLE)
577 szType[0] = 'l';
578 else if (type & MSITYPE_UNKNOWN)
579 szType[0] = 'f';
580 else if (type & MSITYPE_STRING)
582 if (temporary)
583 szType[0] = 'g';
584 else
585 szType[0] = 's';
587 else
589 if (temporary)
590 szType[0] = 'j';
591 else
592 szType[0] = 'i';
595 if (type & MSITYPE_NULLABLE)
596 szType[0] &= ~0x20;
598 swprintf( &szType[1], ARRAY_SIZE(szType) - 1, L"%d", (type&0xff) );
600 TRACE("type %04x -> %s\n", type, debugstr_w(szType) );
602 return MSI_RecordSetStringW( rec, field, szType );
605 UINT MSI_ViewGetColumnInfo( MSIQUERY *query, MSICOLINFO info, MSIRECORD **prec )
607 UINT r = ERROR_FUNCTION_FAILED, i, count = 0, type;
608 MSIRECORD *rec;
609 MSIVIEW *view = query->view;
610 LPCWSTR name;
611 BOOL temporary;
613 if( !view )
614 return ERROR_FUNCTION_FAILED;
616 if( !view->ops->get_dimensions )
617 return ERROR_FUNCTION_FAILED;
619 r = view->ops->get_dimensions( view, NULL, &count );
620 if( r != ERROR_SUCCESS )
621 return r;
622 if( !count )
623 return ERROR_INVALID_PARAMETER;
625 rec = MSI_CreateRecord( count );
626 if( !rec )
627 return ERROR_FUNCTION_FAILED;
629 for( i=0; i<count; i++ )
631 name = NULL;
632 r = view->ops->get_column_info( view, i+1, &name, &type, &temporary, NULL );
633 if( r != ERROR_SUCCESS )
634 continue;
635 if (info == MSICOLINFO_NAMES)
636 MSI_RecordSetStringW( rec, i+1, name );
637 else
638 msi_set_record_type_string( rec, i+1, type, temporary );
640 *prec = rec;
641 return ERROR_SUCCESS;
644 UINT WINAPI MsiViewGetColumnInfo(MSIHANDLE hView, MSICOLINFO info, MSIHANDLE *hRec)
646 MSIQUERY *query = NULL;
647 MSIRECORD *rec = NULL;
648 UINT r;
650 TRACE("%d %d %p\n", hView, info, hRec);
652 if( !hRec )
653 return ERROR_INVALID_PARAMETER;
655 if( info != MSICOLINFO_NAMES && info != MSICOLINFO_TYPES )
656 return ERROR_INVALID_PARAMETER;
658 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
659 if (!query)
661 struct wire_record *wire_rec = NULL;
662 MSIHANDLE remote;
664 if (!(remote = msi_get_remote(hView)))
665 return ERROR_INVALID_HANDLE;
667 __TRY
669 r = remote_ViewGetColumnInfo(remote, info, &wire_rec);
671 __EXCEPT(rpc_filter)
673 r = GetExceptionCode();
675 __ENDTRY
677 if (!r)
679 r = unmarshal_record(wire_rec, hRec);
680 free_remote_record(wire_rec);
683 return r;
686 r = MSI_ViewGetColumnInfo( query, info, &rec );
687 if ( r == ERROR_SUCCESS )
689 *hRec = alloc_msihandle( &rec->hdr );
690 if ( !*hRec )
691 r = ERROR_NOT_ENOUGH_MEMORY;
692 msiobj_release( &rec->hdr );
695 msiobj_release( &query->hdr );
697 return r;
700 UINT MSI_ViewModify( MSIQUERY *query, MSIMODIFY mode, MSIRECORD *rec )
702 MSIVIEW *view = NULL;
703 UINT r;
705 if ( !query || !rec )
706 return ERROR_INVALID_HANDLE;
708 view = query->view;
709 if ( !view || !view->ops->modify)
710 return ERROR_FUNCTION_FAILED;
712 if ( mode == MSIMODIFY_UPDATE && rec->cookie != (UINT64)(ULONG_PTR)query )
713 return ERROR_FUNCTION_FAILED;
715 r = view->ops->modify( view, mode, rec, query->row - 1 );
716 if (mode == MSIMODIFY_DELETE && r == ERROR_SUCCESS)
717 query->row--;
719 return r;
722 UINT WINAPI MsiViewModify( MSIHANDLE hView, MSIMODIFY eModifyMode,
723 MSIHANDLE hRecord)
725 MSIQUERY *query = NULL;
726 MSIRECORD *rec = NULL;
727 UINT r = ERROR_FUNCTION_FAILED;
729 TRACE("%d %x %d\n", hView, eModifyMode, hRecord);
731 rec = msihandle2msiinfo( hRecord, MSIHANDLETYPE_RECORD );
733 if (!rec)
734 return ERROR_INVALID_HANDLE;
736 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
737 if (!query)
739 struct wire_record *wire_refreshed = NULL;
740 MSIHANDLE remote;
742 if (!(remote = msi_get_remote(hView)))
743 return ERROR_INVALID_HANDLE;
745 __TRY
747 r = remote_ViewModify(remote, eModifyMode,
748 (struct wire_record *)&rec->count, &wire_refreshed);
750 __EXCEPT(rpc_filter)
752 r = GetExceptionCode();
754 __ENDTRY
756 if (!r && (eModifyMode == MSIMODIFY_REFRESH || eModifyMode == MSIMODIFY_SEEK))
758 r = copy_remote_record(wire_refreshed, hRecord);
759 free_remote_record(wire_refreshed);
762 msiobj_release(&rec->hdr);
763 return r;
766 r = MSI_ViewModify( query, eModifyMode, rec );
768 msiobj_release( &query->hdr );
769 msiobj_release(&rec->hdr);
770 return r;
773 MSIDBERROR WINAPI MsiViewGetErrorW( MSIHANDLE handle, LPWSTR buffer, LPDWORD buflen )
775 MSIQUERY *query;
776 const WCHAR *column;
777 MSIDBERROR r;
779 TRACE("%u %p %p\n", handle, buffer, buflen);
781 if (!buflen)
782 return MSIDBERROR_INVALIDARG;
784 if (!(query = msihandle2msiinfo(handle, MSIHANDLETYPE_VIEW)))
786 WCHAR *remote_column = NULL;
787 MSIHANDLE remote;
789 if (!(remote = msi_get_remote(handle)))
790 return MSIDBERROR_INVALIDARG;
792 if (!*buflen)
793 return MSIDBERROR_FUNCTIONERROR;
795 __TRY
797 r = remote_ViewGetError(remote, &remote_column);
799 __EXCEPT(rpc_filter)
801 r = GetExceptionCode();
803 __ENDTRY;
805 if (msi_strncpyW(remote_column ? remote_column : L"", -1, buffer, buflen) == ERROR_MORE_DATA)
806 r = MSIDBERROR_MOREDATA;
808 if (remote_column)
809 midl_user_free(remote_column);
811 return r;
814 if ((r = query->view->error)) column = query->view->error_column;
815 else column = L"";
817 if (msi_strncpyW(column, -1, buffer, buflen) == ERROR_MORE_DATA)
818 r = MSIDBERROR_MOREDATA;
820 msiobj_release( &query->hdr );
821 return r;
824 MSIDBERROR WINAPI MsiViewGetErrorA( MSIHANDLE handle, LPSTR buffer, LPDWORD buflen )
826 MSIQUERY *query;
827 const WCHAR *column;
828 MSIDBERROR r;
830 TRACE("%u %p %p\n", handle, buffer, buflen);
832 if (!buflen)
833 return MSIDBERROR_INVALIDARG;
835 if (!(query = msihandle2msiinfo(handle, MSIHANDLETYPE_VIEW)))
837 WCHAR *remote_column = NULL;
838 MSIHANDLE remote;
840 if (!(remote = msi_get_remote(handle)))
841 return MSIDBERROR_INVALIDARG;
843 if (!*buflen)
844 return MSIDBERROR_FUNCTIONERROR;
846 __TRY
848 r = remote_ViewGetError(remote, &remote_column);
850 __EXCEPT(rpc_filter)
852 r = GetExceptionCode();
854 __ENDTRY;
856 if (msi_strncpyWtoA(remote_column ? remote_column : L"", -1, buffer, buflen, FALSE) == ERROR_MORE_DATA)
857 r = MSIDBERROR_MOREDATA;
859 if (remote_column)
860 midl_user_free(remote_column);
862 return r;
865 if ((r = query->view->error)) column = query->view->error_column;
866 else column = L"";
868 if (msi_strncpyWtoA(column, -1, buffer, buflen, FALSE) == ERROR_MORE_DATA)
869 r = MSIDBERROR_MOREDATA;
871 msiobj_release( &query->hdr );
872 return r;
875 MSIHANDLE WINAPI MsiGetLastErrorRecord( void )
877 FIXME("\n");
878 return 0;
881 UINT MSI_DatabaseApplyTransformW( MSIDATABASE *db, const WCHAR *transform, int error_cond )
883 HRESULT hr;
884 UINT ret = ERROR_FUNCTION_FAILED;
885 IStorage *stg;
886 STATSTG stat;
888 TRACE( "%p %s %08x\n", db, debugstr_w(transform), error_cond );
890 if (*transform == ':')
892 hr = IStorage_OpenStorage( db->storage, transform + 1, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
893 if (FAILED( hr ))
895 WARN( "failed to open substorage transform 0x%08x\n", hr );
896 return ERROR_FUNCTION_FAILED;
899 else
901 hr = StgOpenStorage( transform, NULL, STGM_DIRECT|STGM_READ|STGM_SHARE_DENY_WRITE, NULL, 0, &stg );
902 if (FAILED( hr ))
904 WARN( "failed to open file transform 0x%08x\n", hr );
905 return ERROR_FUNCTION_FAILED;
909 hr = IStorage_Stat( stg, &stat, STATFLAG_NONAME );
910 if (FAILED( hr )) goto end;
911 if (!IsEqualGUID( &stat.clsid, &CLSID_MsiTransform )) goto end;
912 if (TRACE_ON( msi )) enum_stream_names( stg );
914 ret = msi_table_apply_transform( db, stg, error_cond );
916 end:
917 IStorage_Release( stg );
918 return ret;
921 UINT WINAPI MsiDatabaseApplyTransformW( MSIHANDLE hdb, const WCHAR *transform, int error_cond )
923 MSIDATABASE *db;
924 UINT r;
926 if (error_cond & ~MSITRANSFORM_ERROR_VIEWTRANSFORM) FIXME( "ignoring error conditions\n" );
928 if (!(db = msihandle2msiinfo(hdb, MSIHANDLETYPE_DATABASE)))
929 return ERROR_INVALID_HANDLE;
931 r = MSI_DatabaseApplyTransformW( db, transform, error_cond );
932 msiobj_release( &db->hdr );
933 return r;
936 UINT WINAPI MsiDatabaseApplyTransformA( MSIHANDLE hdb, const char *transform, int error_cond )
938 WCHAR *wstr;
939 UINT ret;
941 TRACE( "%d %s %08x\n", hdb, debugstr_a(transform), error_cond );
943 wstr = strdupAtoW( transform );
944 if (transform && !wstr)
945 return ERROR_NOT_ENOUGH_MEMORY;
947 ret = MsiDatabaseApplyTransformW( hdb, wstr, error_cond );
948 msi_free( wstr );
949 return ret;
952 UINT WINAPI MsiDatabaseGenerateTransformA( MSIHANDLE hdb, MSIHANDLE hdbref,
953 LPCSTR szTransformFile, int iReserved1, int iReserved2 )
955 FIXME("%d %d %s %d %d\n", hdb, hdbref,
956 debugstr_a(szTransformFile), iReserved1, iReserved2);
957 return ERROR_CALL_NOT_IMPLEMENTED;
960 UINT WINAPI MsiDatabaseGenerateTransformW( MSIHANDLE hdb, MSIHANDLE hdbref,
961 LPCWSTR szTransformFile, int iReserved1, int iReserved2 )
963 FIXME("%d %d %s %d %d\n", hdb, hdbref,
964 debugstr_w(szTransformFile), iReserved1, iReserved2);
965 return ERROR_CALL_NOT_IMPLEMENTED;
968 UINT WINAPI MsiDatabaseCommit( MSIHANDLE hdb )
970 MSIDATABASE *db;
971 UINT r;
973 TRACE("%d\n", hdb);
975 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
976 if( !db )
978 MSIHANDLE remote;
980 if (!(remote = msi_get_remote(hdb)))
981 return ERROR_INVALID_HANDLE;
983 WARN("not allowed during a custom action!\n");
985 return ERROR_SUCCESS;
988 if (db->mode == MSI_OPEN_READONLY)
990 msiobj_release( &db->hdr );
991 return ERROR_SUCCESS;
994 /* FIXME: lock the database */
996 r = msi_commit_streams( db );
997 if (r != ERROR_SUCCESS) ERR("Failed to commit streams!\n");
998 else
1000 r = MSI_CommitTables( db );
1001 if (r != ERROR_SUCCESS) ERR("Failed to commit tables!\n");
1004 /* FIXME: unlock the database */
1006 msiobj_release( &db->hdr );
1008 if (r == ERROR_SUCCESS)
1010 msi_free( db->deletefile );
1011 db->deletefile = NULL;
1014 return r;
1017 struct msi_primary_key_record_info
1019 DWORD n;
1020 MSIRECORD *rec;
1023 static UINT msi_primary_key_iterator( MSIRECORD *rec, LPVOID param )
1025 struct msi_primary_key_record_info *info = param;
1026 LPCWSTR name, table;
1027 DWORD type;
1029 type = MSI_RecordGetInteger( rec, 4 );
1030 if( type & MSITYPE_KEY )
1032 info->n++;
1033 if( info->rec )
1035 if ( info->n == 1 )
1037 table = MSI_RecordGetString( rec, 1 );
1038 MSI_RecordSetStringW( info->rec, 0, table);
1041 name = MSI_RecordGetString( rec, 3 );
1042 MSI_RecordSetStringW( info->rec, info->n, name );
1046 return ERROR_SUCCESS;
1049 UINT MSI_DatabaseGetPrimaryKeys( MSIDATABASE *db,
1050 LPCWSTR table, MSIRECORD **prec )
1052 struct msi_primary_key_record_info info;
1053 MSIQUERY *query = NULL;
1054 UINT r;
1056 if (!TABLE_Exists( db, table ))
1057 return ERROR_INVALID_TABLE;
1059 r = MSI_OpenQuery( db, &query, L"SELECT * FROM `_Columns` WHERE `Table` = '%s'", table );
1060 if( r != ERROR_SUCCESS )
1061 return r;
1063 /* count the number of primary key records */
1064 info.n = 0;
1065 info.rec = 0;
1066 r = MSI_IterateRecords( query, 0, msi_primary_key_iterator, &info );
1067 if( r == ERROR_SUCCESS )
1069 TRACE("Found %d primary keys\n", info.n );
1071 /* allocate a record and fill in the names of the tables */
1072 info.rec = MSI_CreateRecord( info.n );
1073 info.n = 0;
1074 r = MSI_IterateRecords( query, 0, msi_primary_key_iterator, &info );
1075 if( r == ERROR_SUCCESS )
1076 *prec = info.rec;
1077 else
1078 msiobj_release( &info.rec->hdr );
1080 msiobj_release( &query->hdr );
1082 return r;
1085 UINT WINAPI MsiDatabaseGetPrimaryKeysW( MSIHANDLE hdb,
1086 LPCWSTR table, MSIHANDLE* phRec )
1088 MSIRECORD *rec = NULL;
1089 MSIDATABASE *db;
1090 UINT r;
1092 TRACE("%d %s %p\n", hdb, debugstr_w(table), phRec);
1094 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
1095 if( !db )
1097 struct wire_record *wire_rec = NULL;
1098 MSIHANDLE remote;
1100 if (!(remote = msi_get_remote(hdb)))
1101 return ERROR_INVALID_HANDLE;
1103 __TRY
1105 r = remote_DatabaseGetPrimaryKeys(remote, table, &wire_rec);
1107 __EXCEPT(rpc_filter)
1109 r = GetExceptionCode();
1111 __ENDTRY
1113 if (!r)
1115 r = unmarshal_record(wire_rec, phRec);
1116 free_remote_record(wire_rec);
1119 return r;
1122 r = MSI_DatabaseGetPrimaryKeys( db, table, &rec );
1123 if( r == ERROR_SUCCESS )
1125 *phRec = alloc_msihandle( &rec->hdr );
1126 if (! *phRec)
1127 r = ERROR_NOT_ENOUGH_MEMORY;
1128 msiobj_release( &rec->hdr );
1130 msiobj_release( &db->hdr );
1132 return r;
1135 UINT WINAPI MsiDatabaseGetPrimaryKeysA(MSIHANDLE hdb,
1136 LPCSTR table, MSIHANDLE* phRec)
1138 LPWSTR szwTable = NULL;
1139 UINT r;
1141 TRACE("%d %s %p\n", hdb, debugstr_a(table), phRec);
1143 if( table )
1145 szwTable = strdupAtoW( table );
1146 if( !szwTable )
1147 return ERROR_OUTOFMEMORY;
1149 r = MsiDatabaseGetPrimaryKeysW( hdb, szwTable, phRec );
1150 msi_free( szwTable );
1152 return r;
1155 MSICONDITION WINAPI MsiDatabaseIsTablePersistentA(
1156 MSIHANDLE hDatabase, LPCSTR szTableName)
1158 LPWSTR szwTableName = NULL;
1159 MSICONDITION r;
1161 TRACE("%x %s\n", hDatabase, debugstr_a(szTableName));
1163 if( szTableName )
1165 szwTableName = strdupAtoW( szTableName );
1166 if( !szwTableName )
1167 return MSICONDITION_ERROR;
1169 r = MsiDatabaseIsTablePersistentW( hDatabase, szwTableName );
1170 msi_free( szwTableName );
1172 return r;
1175 MSICONDITION WINAPI MsiDatabaseIsTablePersistentW(
1176 MSIHANDLE hDatabase, LPCWSTR szTableName)
1178 MSIDATABASE *db;
1179 MSICONDITION r;
1181 TRACE("%x %s\n", hDatabase, debugstr_w(szTableName));
1183 db = msihandle2msiinfo( hDatabase, MSIHANDLETYPE_DATABASE );
1184 if( !db )
1186 MSIHANDLE remote;
1188 if (!(remote = msi_get_remote(hDatabase)))
1189 return MSICONDITION_ERROR;
1191 __TRY
1193 r = remote_DatabaseIsTablePersistent(remote, szTableName);
1195 __EXCEPT(rpc_filter)
1197 r = MSICONDITION_ERROR;
1199 __ENDTRY
1201 return r;
1204 r = MSI_DatabaseIsTablePersistent( db, szTableName );
1206 msiobj_release( &db->hdr );
1208 return r;
1211 UINT __cdecl s_remote_ViewClose(MSIHANDLE view)
1213 return MsiViewClose(view);
1216 UINT __cdecl s_remote_ViewExecute(MSIHANDLE view, struct wire_record *remote_rec)
1218 MSIHANDLE rec = 0;
1219 UINT r;
1221 if ((r = unmarshal_record(remote_rec, &rec)))
1222 return r;
1224 r = MsiViewExecute(view, rec);
1226 MsiCloseHandle(rec);
1227 return r;
1230 UINT __cdecl s_remote_ViewFetch(MSIHANDLE view, struct wire_record **rec)
1232 MSIHANDLE handle;
1233 UINT r = MsiViewFetch(view, &handle);
1234 *rec = NULL;
1235 if (!r)
1236 *rec = marshal_record(handle);
1237 MsiCloseHandle(handle);
1238 return r;
1241 UINT __cdecl s_remote_ViewGetColumnInfo(MSIHANDLE view, MSICOLINFO info, struct wire_record **rec)
1243 MSIHANDLE handle;
1244 UINT r = MsiViewGetColumnInfo(view, info, &handle);
1245 *rec = NULL;
1246 if (!r)
1247 *rec = marshal_record(handle);
1248 MsiCloseHandle(handle);
1249 return r;
1252 MSIDBERROR __cdecl s_remote_ViewGetError(MSIHANDLE view, LPWSTR *column)
1254 WCHAR empty[1];
1255 DWORD size = 1;
1256 UINT r;
1258 r = MsiViewGetErrorW(view, empty, &size);
1259 if (r == MSIDBERROR_MOREDATA)
1261 if (!(*column = midl_user_allocate(++size * sizeof(WCHAR))))
1262 return MSIDBERROR_FUNCTIONERROR;
1263 r = MsiViewGetErrorW(view, *column, &size);
1265 return r;
1268 UINT __cdecl s_remote_ViewModify(MSIHANDLE view, MSIMODIFY mode,
1269 struct wire_record *remote_rec, struct wire_record **remote_refreshed)
1271 MSIHANDLE handle = 0;
1272 UINT r;
1274 if ((r = unmarshal_record(remote_rec, &handle)))
1275 return r;
1277 r = MsiViewModify(view, mode, handle);
1278 *remote_refreshed = NULL;
1279 if (!r && (mode == MSIMODIFY_REFRESH || mode == MSIMODIFY_SEEK))
1280 *remote_refreshed = marshal_record(handle);
1282 MsiCloseHandle(handle);
1283 return r;