winedbg: Don't dereference possibly NULL thread pointer.
[wine/zf.git] / dlls / msi / msiquery.c
blob4ee9a973917bdd00a915043f2584af838730c544
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 __ms_va_list va;
150 query = msi_alloc( size*sizeof(WCHAR) );
151 __ms_va_start(va, fmt);
152 res = vswprintf(query, size, fmt, va);
153 __ms_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 __ms_va_list va;
215 query = msi_alloc( size*sizeof(WCHAR) );
216 __ms_va_start(va, fmt);
217 res = vswprintf(query, size, fmt, va);
218 __ms_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);
398 return r;
401 UINT WINAPI MsiViewFetch(MSIHANDLE hView, MSIHANDLE *record)
403 MSIQUERY *query;
404 MSIRECORD *rec = NULL;
405 UINT ret;
407 TRACE("%d %p\n", hView, record);
409 if( !record )
410 return ERROR_INVALID_PARAMETER;
411 *record = 0;
413 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
414 if (!query)
416 struct wire_record *wire_rec = NULL;
417 MSIHANDLE remote;
419 if (!(remote = msi_get_remote(hView)))
420 return ERROR_INVALID_HANDLE;
422 __TRY
424 ret = remote_ViewFetch(remote, &wire_rec);
426 __EXCEPT(rpc_filter)
428 ret = GetExceptionCode();
430 __ENDTRY
432 if (!ret)
434 ret = unmarshal_record(wire_rec, record);
435 free_remote_record(wire_rec);
437 return ret;
439 ret = MSI_ViewFetch( query, &rec );
440 if( ret == ERROR_SUCCESS )
442 *record = alloc_msihandle( &rec->hdr );
443 if (! *record)
444 ret = ERROR_NOT_ENOUGH_MEMORY;
445 msiobj_release( &rec->hdr );
447 msiobj_release( &query->hdr );
448 return ret;
451 UINT MSI_ViewClose(MSIQUERY *query)
453 MSIVIEW *view;
455 TRACE("%p\n", query );
457 view = query->view;
458 if( !view )
459 return ERROR_FUNCTION_FAILED;
460 if( !view->ops->close )
461 return ERROR_FUNCTION_FAILED;
463 return view->ops->close( view );
466 UINT WINAPI MsiViewClose(MSIHANDLE hView)
468 MSIQUERY *query;
469 UINT ret;
471 TRACE("%d\n", hView );
473 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
474 if (!query)
476 MSIHANDLE remote;
478 if (!(remote = msi_get_remote(hView)))
479 return ERROR_INVALID_HANDLE;
481 __TRY
483 ret = remote_ViewClose(remote);
485 __EXCEPT(rpc_filter)
487 ret = GetExceptionCode();
489 __ENDTRY
491 return ret;
494 ret = MSI_ViewClose( query );
495 msiobj_release( &query->hdr );
496 return ret;
499 UINT MSI_ViewExecute(MSIQUERY *query, MSIRECORD *rec )
501 MSIVIEW *view;
503 TRACE("%p %p\n", query, rec);
505 view = query->view;
506 if( !view )
507 return ERROR_FUNCTION_FAILED;
508 if( !view->ops->execute )
509 return ERROR_FUNCTION_FAILED;
510 query->row = 0;
512 return view->ops->execute( view, rec );
515 UINT WINAPI MsiViewExecute(MSIHANDLE hView, MSIHANDLE hRec)
517 MSIQUERY *query;
518 MSIRECORD *rec = NULL;
519 UINT ret;
521 TRACE("%d %d\n", hView, hRec);
523 if( hRec )
525 rec = msihandle2msiinfo( hRec, MSIHANDLETYPE_RECORD );
526 if( !rec )
527 return ERROR_INVALID_HANDLE;
530 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
531 if( !query )
533 MSIHANDLE remote;
535 if (!(remote = msi_get_remote(hView)))
536 return ERROR_INVALID_HANDLE;
538 __TRY
540 ret = remote_ViewExecute(remote, rec ? (struct wire_record *)&rec->count : NULL);
542 __EXCEPT(rpc_filter)
544 ret = GetExceptionCode();
546 __ENDTRY
548 if (rec)
549 msiobj_release(&rec->hdr);
550 return ret;
553 msiobj_lock( &rec->hdr );
554 ret = MSI_ViewExecute( query, rec );
555 msiobj_unlock( &rec->hdr );
557 msiobj_release( &query->hdr );
558 if( rec )
559 msiobj_release( &rec->hdr );
561 return ret;
564 static UINT msi_set_record_type_string( MSIRECORD *rec, UINT field,
565 UINT type, BOOL temporary )
567 WCHAR szType[0x10];
569 if (MSITYPE_IS_BINARY(type))
570 szType[0] = 'v';
571 else if (type & MSITYPE_LOCALIZABLE)
572 szType[0] = 'l';
573 else if (type & MSITYPE_UNKNOWN)
574 szType[0] = 'f';
575 else if (type & MSITYPE_STRING)
577 if (temporary)
578 szType[0] = 'g';
579 else
580 szType[0] = 's';
582 else
584 if (temporary)
585 szType[0] = 'j';
586 else
587 szType[0] = 'i';
590 if (type & MSITYPE_NULLABLE)
591 szType[0] &= ~0x20;
593 swprintf( &szType[1], ARRAY_SIZE(szType) - 1, L"%d", (type&0xff) );
595 TRACE("type %04x -> %s\n", type, debugstr_w(szType) );
597 return MSI_RecordSetStringW( rec, field, szType );
600 UINT MSI_ViewGetColumnInfo( MSIQUERY *query, MSICOLINFO info, MSIRECORD **prec )
602 UINT r = ERROR_FUNCTION_FAILED, i, count = 0, type;
603 MSIRECORD *rec;
604 MSIVIEW *view = query->view;
605 LPCWSTR name;
606 BOOL temporary;
608 if( !view )
609 return ERROR_FUNCTION_FAILED;
611 if( !view->ops->get_dimensions )
612 return ERROR_FUNCTION_FAILED;
614 r = view->ops->get_dimensions( view, NULL, &count );
615 if( r != ERROR_SUCCESS )
616 return r;
617 if( !count )
618 return ERROR_INVALID_PARAMETER;
620 rec = MSI_CreateRecord( count );
621 if( !rec )
622 return ERROR_FUNCTION_FAILED;
624 for( i=0; i<count; i++ )
626 name = NULL;
627 r = view->ops->get_column_info( view, i+1, &name, &type, &temporary, NULL );
628 if( r != ERROR_SUCCESS )
629 continue;
630 if (info == MSICOLINFO_NAMES)
631 MSI_RecordSetStringW( rec, i+1, name );
632 else
633 msi_set_record_type_string( rec, i+1, type, temporary );
635 *prec = rec;
636 return ERROR_SUCCESS;
639 UINT WINAPI MsiViewGetColumnInfo(MSIHANDLE hView, MSICOLINFO info, MSIHANDLE *hRec)
641 MSIQUERY *query = NULL;
642 MSIRECORD *rec = NULL;
643 UINT r;
645 TRACE("%d %d %p\n", hView, info, hRec);
647 if( !hRec )
648 return ERROR_INVALID_PARAMETER;
650 if( info != MSICOLINFO_NAMES && info != MSICOLINFO_TYPES )
651 return ERROR_INVALID_PARAMETER;
653 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
654 if (!query)
656 struct wire_record *wire_rec = NULL;
657 MSIHANDLE remote;
659 if (!(remote = msi_get_remote(hView)))
660 return ERROR_INVALID_HANDLE;
662 __TRY
664 r = remote_ViewGetColumnInfo(remote, info, &wire_rec);
666 __EXCEPT(rpc_filter)
668 r = GetExceptionCode();
670 __ENDTRY
672 if (!r)
674 r = unmarshal_record(wire_rec, hRec);
675 free_remote_record(wire_rec);
678 return r;
681 r = MSI_ViewGetColumnInfo( query, info, &rec );
682 if ( r == ERROR_SUCCESS )
684 *hRec = alloc_msihandle( &rec->hdr );
685 if ( !*hRec )
686 r = ERROR_NOT_ENOUGH_MEMORY;
687 msiobj_release( &rec->hdr );
690 msiobj_release( &query->hdr );
692 return r;
695 UINT MSI_ViewModify( MSIQUERY *query, MSIMODIFY mode, MSIRECORD *rec )
697 MSIVIEW *view = NULL;
698 UINT r;
700 if ( !query || !rec )
701 return ERROR_INVALID_HANDLE;
703 view = query->view;
704 if ( !view || !view->ops->modify)
705 return ERROR_FUNCTION_FAILED;
707 if ( mode == MSIMODIFY_UPDATE && rec->cookie != (UINT64)(ULONG_PTR)query )
708 return ERROR_FUNCTION_FAILED;
710 r = view->ops->modify( view, mode, rec, query->row - 1 );
711 if (mode == MSIMODIFY_DELETE && r == ERROR_SUCCESS)
712 query->row--;
714 return r;
717 UINT WINAPI MsiViewModify( MSIHANDLE hView, MSIMODIFY eModifyMode,
718 MSIHANDLE hRecord)
720 MSIQUERY *query = NULL;
721 MSIRECORD *rec = NULL;
722 UINT r = ERROR_FUNCTION_FAILED;
724 TRACE("%d %x %d\n", hView, eModifyMode, hRecord);
726 rec = msihandle2msiinfo( hRecord, MSIHANDLETYPE_RECORD );
728 if (!rec)
729 return ERROR_INVALID_HANDLE;
731 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
732 if (!query)
734 struct wire_record *wire_refreshed = NULL;
735 MSIHANDLE remote;
737 if (!(remote = msi_get_remote(hView)))
738 return ERROR_INVALID_HANDLE;
740 __TRY
742 r = remote_ViewModify(remote, eModifyMode,
743 (struct wire_record *)&rec->count, &wire_refreshed);
745 __EXCEPT(rpc_filter)
747 r = GetExceptionCode();
749 __ENDTRY
751 if (!r && (eModifyMode == MSIMODIFY_REFRESH || eModifyMode == MSIMODIFY_SEEK))
753 r = copy_remote_record(wire_refreshed, hRecord);
754 free_remote_record(wire_refreshed);
757 msiobj_release(&rec->hdr);
758 return r;
761 r = MSI_ViewModify( query, eModifyMode, rec );
763 msiobj_release( &query->hdr );
764 msiobj_release(&rec->hdr);
765 return r;
768 MSIDBERROR WINAPI MsiViewGetErrorW( MSIHANDLE handle, LPWSTR buffer, LPDWORD buflen )
770 MSIQUERY *query;
771 const WCHAR *column;
772 MSIDBERROR r;
774 TRACE("%u %p %p\n", handle, buffer, buflen);
776 if (!buflen)
777 return MSIDBERROR_INVALIDARG;
779 if (!(query = msihandle2msiinfo(handle, MSIHANDLETYPE_VIEW)))
781 WCHAR *remote_column = NULL;
782 MSIHANDLE remote;
784 if (!(remote = msi_get_remote(handle)))
785 return MSIDBERROR_INVALIDARG;
787 if (!*buflen)
788 return MSIDBERROR_FUNCTIONERROR;
790 __TRY
792 r = remote_ViewGetError(remote, &remote_column);
794 __EXCEPT(rpc_filter)
796 r = GetExceptionCode();
798 __ENDTRY;
800 if (msi_strncpyW(remote_column ? remote_column : L"", -1, buffer, buflen) == ERROR_MORE_DATA)
801 r = MSIDBERROR_MOREDATA;
803 if (remote_column)
804 midl_user_free(remote_column);
806 return r;
809 if ((r = query->view->error)) column = query->view->error_column;
810 else column = L"";
812 if (msi_strncpyW(column, -1, buffer, buflen) == ERROR_MORE_DATA)
813 r = MSIDBERROR_MOREDATA;
815 msiobj_release( &query->hdr );
816 return r;
819 MSIDBERROR WINAPI MsiViewGetErrorA( MSIHANDLE handle, LPSTR buffer, LPDWORD buflen )
821 MSIQUERY *query;
822 const WCHAR *column;
823 MSIDBERROR r;
825 TRACE("%u %p %p\n", handle, buffer, buflen);
827 if (!buflen)
828 return MSIDBERROR_INVALIDARG;
830 if (!(query = msihandle2msiinfo(handle, MSIHANDLETYPE_VIEW)))
832 WCHAR *remote_column = NULL;
833 MSIHANDLE remote;
835 if (!(remote = msi_get_remote(handle)))
836 return MSIDBERROR_INVALIDARG;
838 if (!*buflen)
839 return MSIDBERROR_FUNCTIONERROR;
841 __TRY
843 r = remote_ViewGetError(remote, &remote_column);
845 __EXCEPT(rpc_filter)
847 r = GetExceptionCode();
849 __ENDTRY;
851 if (msi_strncpyWtoA(remote_column ? remote_column : L"", -1, buffer, buflen, FALSE) == ERROR_MORE_DATA)
852 r = MSIDBERROR_MOREDATA;
854 if (remote_column)
855 midl_user_free(remote_column);
857 return r;
860 if ((r = query->view->error)) column = query->view->error_column;
861 else column = L"";
863 if (msi_strncpyWtoA(column, -1, buffer, buflen, FALSE) == ERROR_MORE_DATA)
864 r = MSIDBERROR_MOREDATA;
866 msiobj_release( &query->hdr );
867 return r;
870 MSIHANDLE WINAPI MsiGetLastErrorRecord( void )
872 FIXME("\n");
873 return 0;
876 UINT MSI_DatabaseApplyTransformW( MSIDATABASE *db, const WCHAR *transform, int error_cond )
878 HRESULT hr;
879 UINT ret = ERROR_FUNCTION_FAILED;
880 IStorage *stg;
881 STATSTG stat;
883 TRACE( "%p %s %08x\n", db, debugstr_w(transform), error_cond );
885 if (*transform == ':')
887 hr = IStorage_OpenStorage( db->storage, transform + 1, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
888 if (FAILED( hr ))
890 WARN( "failed to open substorage transform 0x%08x\n", hr );
891 return ERROR_FUNCTION_FAILED;
894 else
896 hr = StgOpenStorage( transform, NULL, STGM_DIRECT|STGM_READ|STGM_SHARE_DENY_WRITE, NULL, 0, &stg );
897 if (FAILED( hr ))
899 WARN( "failed to open file transform 0x%08x\n", hr );
900 return ERROR_FUNCTION_FAILED;
904 hr = IStorage_Stat( stg, &stat, STATFLAG_NONAME );
905 if (FAILED( hr )) goto end;
906 if (!IsEqualGUID( &stat.clsid, &CLSID_MsiTransform )) goto end;
907 if (TRACE_ON( msi )) enum_stream_names( stg );
909 ret = msi_table_apply_transform( db, stg, error_cond );
911 end:
912 IStorage_Release( stg );
913 return ret;
916 UINT WINAPI MsiDatabaseApplyTransformW( MSIHANDLE hdb, const WCHAR *transform, int error_cond )
918 MSIDATABASE *db;
919 UINT r;
921 if (error_cond & ~MSITRANSFORM_ERROR_VIEWTRANSFORM) FIXME( "ignoring error conditions\n" );
923 if (!(db = msihandle2msiinfo(hdb, MSIHANDLETYPE_DATABASE)))
924 return ERROR_INVALID_HANDLE;
926 r = MSI_DatabaseApplyTransformW( db, transform, error_cond );
927 msiobj_release( &db->hdr );
928 return r;
931 UINT WINAPI MsiDatabaseApplyTransformA( MSIHANDLE hdb, const char *transform, int error_cond )
933 WCHAR *wstr;
934 UINT ret;
936 TRACE( "%d %s %08x\n", hdb, debugstr_a(transform), error_cond );
938 wstr = strdupAtoW( transform );
939 if (transform && !wstr)
940 return ERROR_NOT_ENOUGH_MEMORY;
942 ret = MsiDatabaseApplyTransformW( hdb, wstr, error_cond );
943 msi_free( wstr );
944 return ret;
947 UINT WINAPI MsiDatabaseGenerateTransformA( MSIHANDLE hdb, MSIHANDLE hdbref,
948 LPCSTR szTransformFile, int iReserved1, int iReserved2 )
950 FIXME("%d %d %s %d %d\n", hdb, hdbref,
951 debugstr_a(szTransformFile), iReserved1, iReserved2);
952 return ERROR_CALL_NOT_IMPLEMENTED;
955 UINT WINAPI MsiDatabaseGenerateTransformW( MSIHANDLE hdb, MSIHANDLE hdbref,
956 LPCWSTR szTransformFile, int iReserved1, int iReserved2 )
958 FIXME("%d %d %s %d %d\n", hdb, hdbref,
959 debugstr_w(szTransformFile), iReserved1, iReserved2);
960 return ERROR_CALL_NOT_IMPLEMENTED;
963 UINT WINAPI MsiDatabaseCommit( MSIHANDLE hdb )
965 MSIDATABASE *db;
966 UINT r;
968 TRACE("%d\n", hdb);
970 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
971 if( !db )
973 MSIHANDLE remote;
975 if (!(remote = msi_get_remote(hdb)))
976 return ERROR_INVALID_HANDLE;
978 WARN("not allowed during a custom action!\n");
980 return ERROR_SUCCESS;
983 if (db->mode == MSI_OPEN_READONLY)
985 msiobj_release( &db->hdr );
986 return ERROR_SUCCESS;
989 /* FIXME: lock the database */
991 r = msi_commit_streams( db );
992 if (r != ERROR_SUCCESS) ERR("Failed to commit streams!\n");
993 else
995 r = MSI_CommitTables( db );
996 if (r != ERROR_SUCCESS) ERR("Failed to commit tables!\n");
999 /* FIXME: unlock the database */
1001 msiobj_release( &db->hdr );
1003 if (r == ERROR_SUCCESS)
1005 msi_free( db->deletefile );
1006 db->deletefile = NULL;
1009 return r;
1012 struct msi_primary_key_record_info
1014 DWORD n;
1015 MSIRECORD *rec;
1018 static UINT msi_primary_key_iterator( MSIRECORD *rec, LPVOID param )
1020 struct msi_primary_key_record_info *info = param;
1021 LPCWSTR name, table;
1022 DWORD type;
1024 type = MSI_RecordGetInteger( rec, 4 );
1025 if( type & MSITYPE_KEY )
1027 info->n++;
1028 if( info->rec )
1030 if ( info->n == 1 )
1032 table = MSI_RecordGetString( rec, 1 );
1033 MSI_RecordSetStringW( info->rec, 0, table);
1036 name = MSI_RecordGetString( rec, 3 );
1037 MSI_RecordSetStringW( info->rec, info->n, name );
1041 return ERROR_SUCCESS;
1044 UINT MSI_DatabaseGetPrimaryKeys( MSIDATABASE *db,
1045 LPCWSTR table, MSIRECORD **prec )
1047 struct msi_primary_key_record_info info;
1048 MSIQUERY *query = NULL;
1049 UINT r;
1051 if (!TABLE_Exists( db, table ))
1052 return ERROR_INVALID_TABLE;
1054 r = MSI_OpenQuery( db, &query, L"SELECT * FROM `_Columns` WHERE `Table` = '%s'", table );
1055 if( r != ERROR_SUCCESS )
1056 return r;
1058 /* count the number of primary key records */
1059 info.n = 0;
1060 info.rec = 0;
1061 r = MSI_IterateRecords( query, 0, msi_primary_key_iterator, &info );
1062 if( r == ERROR_SUCCESS )
1064 TRACE("Found %d primary keys\n", info.n );
1066 /* allocate a record and fill in the names of the tables */
1067 info.rec = MSI_CreateRecord( info.n );
1068 info.n = 0;
1069 r = MSI_IterateRecords( query, 0, msi_primary_key_iterator, &info );
1070 if( r == ERROR_SUCCESS )
1071 *prec = info.rec;
1072 else
1073 msiobj_release( &info.rec->hdr );
1075 msiobj_release( &query->hdr );
1077 return r;
1080 UINT WINAPI MsiDatabaseGetPrimaryKeysW( MSIHANDLE hdb,
1081 LPCWSTR table, MSIHANDLE* phRec )
1083 MSIRECORD *rec = NULL;
1084 MSIDATABASE *db;
1085 UINT r;
1087 TRACE("%d %s %p\n", hdb, debugstr_w(table), phRec);
1089 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
1090 if( !db )
1092 struct wire_record *wire_rec = NULL;
1093 MSIHANDLE remote;
1095 if (!(remote = msi_get_remote(hdb)))
1096 return ERROR_INVALID_HANDLE;
1098 __TRY
1100 r = remote_DatabaseGetPrimaryKeys(remote, table, &wire_rec);
1102 __EXCEPT(rpc_filter)
1104 r = GetExceptionCode();
1106 __ENDTRY
1108 if (!r)
1110 r = unmarshal_record(wire_rec, phRec);
1111 free_remote_record(wire_rec);
1114 return r;
1117 r = MSI_DatabaseGetPrimaryKeys( db, table, &rec );
1118 if( r == ERROR_SUCCESS )
1120 *phRec = alloc_msihandle( &rec->hdr );
1121 if (! *phRec)
1122 r = ERROR_NOT_ENOUGH_MEMORY;
1123 msiobj_release( &rec->hdr );
1125 msiobj_release( &db->hdr );
1127 return r;
1130 UINT WINAPI MsiDatabaseGetPrimaryKeysA(MSIHANDLE hdb,
1131 LPCSTR table, MSIHANDLE* phRec)
1133 LPWSTR szwTable = NULL;
1134 UINT r;
1136 TRACE("%d %s %p\n", hdb, debugstr_a(table), phRec);
1138 if( table )
1140 szwTable = strdupAtoW( table );
1141 if( !szwTable )
1142 return ERROR_OUTOFMEMORY;
1144 r = MsiDatabaseGetPrimaryKeysW( hdb, szwTable, phRec );
1145 msi_free( szwTable );
1147 return r;
1150 MSICONDITION WINAPI MsiDatabaseIsTablePersistentA(
1151 MSIHANDLE hDatabase, LPCSTR szTableName)
1153 LPWSTR szwTableName = NULL;
1154 MSICONDITION r;
1156 TRACE("%x %s\n", hDatabase, debugstr_a(szTableName));
1158 if( szTableName )
1160 szwTableName = strdupAtoW( szTableName );
1161 if( !szwTableName )
1162 return MSICONDITION_ERROR;
1164 r = MsiDatabaseIsTablePersistentW( hDatabase, szwTableName );
1165 msi_free( szwTableName );
1167 return r;
1170 MSICONDITION WINAPI MsiDatabaseIsTablePersistentW(
1171 MSIHANDLE hDatabase, LPCWSTR szTableName)
1173 MSIDATABASE *db;
1174 MSICONDITION r;
1176 TRACE("%x %s\n", hDatabase, debugstr_w(szTableName));
1178 db = msihandle2msiinfo( hDatabase, MSIHANDLETYPE_DATABASE );
1179 if( !db )
1181 MSIHANDLE remote;
1183 if (!(remote = msi_get_remote(hDatabase)))
1184 return MSICONDITION_ERROR;
1186 __TRY
1188 r = remote_DatabaseIsTablePersistent(remote, szTableName);
1190 __EXCEPT(rpc_filter)
1192 r = MSICONDITION_ERROR;
1194 __ENDTRY
1196 return r;
1199 r = MSI_DatabaseIsTablePersistent( db, szTableName );
1201 msiobj_release( &db->hdr );
1203 return r;
1206 UINT __cdecl s_remote_ViewClose(MSIHANDLE view)
1208 return MsiViewClose(view);
1211 UINT __cdecl s_remote_ViewExecute(MSIHANDLE view, struct wire_record *remote_rec)
1213 MSIHANDLE rec = 0;
1214 UINT r;
1216 if ((r = unmarshal_record(remote_rec, &rec)))
1217 return r;
1219 r = MsiViewExecute(view, rec);
1221 MsiCloseHandle(rec);
1222 return r;
1225 UINT __cdecl s_remote_ViewFetch(MSIHANDLE view, struct wire_record **rec)
1227 MSIHANDLE handle;
1228 UINT r = MsiViewFetch(view, &handle);
1229 *rec = NULL;
1230 if (!r)
1231 *rec = marshal_record(handle);
1232 MsiCloseHandle(handle);
1233 return r;
1236 UINT __cdecl s_remote_ViewGetColumnInfo(MSIHANDLE view, MSICOLINFO info, struct wire_record **rec)
1238 MSIHANDLE handle;
1239 UINT r = MsiViewGetColumnInfo(view, info, &handle);
1240 *rec = NULL;
1241 if (!r)
1242 *rec = marshal_record(handle);
1243 MsiCloseHandle(handle);
1244 return r;
1247 MSIDBERROR __cdecl s_remote_ViewGetError(MSIHANDLE view, LPWSTR *column)
1249 WCHAR empty[1];
1250 DWORD size = 1;
1251 UINT r;
1253 r = MsiViewGetErrorW(view, empty, &size);
1254 if (r == MSIDBERROR_MOREDATA)
1256 if (!(*column = midl_user_allocate(++size * sizeof(WCHAR))))
1257 return MSIDBERROR_FUNCTIONERROR;
1258 r = MsiViewGetErrorW(view, *column, &size);
1260 return r;
1263 UINT __cdecl s_remote_ViewModify(MSIHANDLE view, MSIMODIFY mode,
1264 struct wire_record *remote_rec, struct wire_record **remote_refreshed)
1266 MSIHANDLE handle = 0;
1267 UINT r;
1269 if ((r = unmarshal_record(remote_rec, &handle)))
1270 return r;
1272 r = MsiViewModify(view, mode, handle);
1273 *remote_refreshed = NULL;
1274 if (!r && (mode == MSIMODIFY_REFRESH || mode == MSIMODIFY_SEEK))
1275 *remote_refreshed = marshal_record(handle);
1277 MsiCloseHandle(handle);
1278 return r;