windows.networking.hostname/tests: Check if passed HSTRING is duplicated.
[wine.git] / dlls / msi / msiquery.c
blobe16719f53d9919d416b9c04939997300d9d10a6e
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 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, const char *szQuery, MSIHANDLE *phView )
90 UINT r;
91 WCHAR *szwQuery;
93 TRACE( "%lu, %s, %p\n", hdb, debugstr_a(szQuery), phView );
95 if( szQuery )
97 szwQuery = strdupAtoW( szQuery );
98 if( !szwQuery )
99 return ERROR_FUNCTION_FAILED;
101 else
102 szwQuery = NULL;
104 r = MsiDatabaseOpenViewW( hdb, szwQuery, phView);
106 free( szwQuery );
107 return r;
110 UINT MSI_DatabaseOpenViewW( MSIDATABASE *db, const WCHAR *szQuery, MSIQUERY **pView )
112 MSIQUERY *query;
113 UINT r;
115 TRACE( "%s, %p\n", debugstr_w(szQuery), pView );
117 /* pre allocate a handle to hold a pointer to the view */
118 query = alloc_msiobject( MSIHANDLETYPE_VIEW, sizeof (MSIQUERY),
119 MSI_CloseView );
120 if( !query )
121 return ERROR_FUNCTION_FAILED;
123 msiobj_addref( &db->hdr );
124 query->db = db;
125 list_init( &query->mem );
127 r = MSI_ParseSQL( db, szQuery, &query->view, &query->mem );
128 if( r == ERROR_SUCCESS )
130 msiobj_addref( &query->hdr );
131 *pView = query;
134 msiobj_release( &query->hdr );
135 return r;
138 UINT WINAPIV MSI_OpenQuery( MSIDATABASE *db, MSIQUERY **view, LPCWSTR fmt, ... )
140 UINT r;
141 int size = 100, res;
142 LPWSTR query;
144 /* construct the string */
145 for (;;)
147 va_list va;
148 query = malloc(size * sizeof(WCHAR));
149 va_start(va, fmt);
150 res = vswprintf(query, size, fmt, va);
151 va_end(va);
152 if (res == -1) size *= 2;
153 else if (res >= size) size = res + 1;
154 else break;
155 free(query);
157 /* perform the query */
158 r = MSI_DatabaseOpenViewW(db, query, view);
159 free(query);
160 return r;
163 UINT MSI_IterateRecords( MSIQUERY *view, LPDWORD count,
164 record_func func, LPVOID param )
166 MSIRECORD *rec = NULL;
167 UINT r, n = 0, max = 0;
169 r = MSI_ViewExecute( view, NULL );
170 if( r != ERROR_SUCCESS )
171 return r;
173 if( count )
174 max = *count;
176 /* iterate a query */
177 for( n = 0; (max == 0) || (n < max); n++ )
179 r = MSI_ViewFetch( view, &rec );
180 if( r != ERROR_SUCCESS )
181 break;
182 if (func)
183 r = func( rec, param );
184 msiobj_release( &rec->hdr );
185 if( r != ERROR_SUCCESS )
186 break;
189 MSI_ViewClose( view );
191 if( count )
192 *count = n;
194 if( r == ERROR_NO_MORE_ITEMS )
195 r = ERROR_SUCCESS;
197 return r;
200 /* return a single record from a query */
201 MSIRECORD * WINAPIV MSI_QueryGetRecord( MSIDATABASE *db, LPCWSTR fmt, ... )
203 MSIRECORD *rec = NULL;
204 MSIQUERY *view = NULL;
205 UINT r;
206 int size = 100, res;
207 LPWSTR query;
209 /* construct the string */
210 for (;;)
212 va_list va;
213 query = malloc(size * sizeof(WCHAR));
214 va_start(va, fmt);
215 res = vswprintf(query, size, fmt, va);
216 va_end(va);
217 if (res == -1) size *= 2;
218 else if (res >= size) size = res + 1;
219 else break;
220 free(query);
222 /* perform the query */
223 r = MSI_DatabaseOpenViewW(db, query, &view);
224 free(query);
226 if( r == ERROR_SUCCESS )
228 MSI_ViewExecute( view, NULL );
229 MSI_ViewFetch( view, &rec );
230 MSI_ViewClose( view );
231 msiobj_release( &view->hdr );
233 return rec;
236 UINT WINAPI MsiDatabaseOpenViewW(MSIHANDLE hdb,
237 LPCWSTR szQuery, MSIHANDLE *phView)
239 MSIDATABASE *db;
240 MSIQUERY *query = NULL;
241 UINT ret;
243 TRACE("%s %p\n", debugstr_w(szQuery), phView);
245 if (!phView)
246 return ERROR_INVALID_PARAMETER;
248 if (!szQuery)
249 return ERROR_BAD_QUERY_SYNTAX;
251 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
252 if( !db )
254 MSIHANDLE remote, remote_view;
256 if (!(remote = msi_get_remote(hdb)))
257 return ERROR_INVALID_HANDLE;
259 __TRY
261 ret = remote_DatabaseOpenView(remote, szQuery, &remote_view);
263 __EXCEPT(rpc_filter)
265 ret = GetExceptionCode();
267 __ENDTRY
269 if (!ret)
270 *phView = alloc_msi_remote_handle(remote_view);
271 return ret;
274 ret = MSI_DatabaseOpenViewW( db, szQuery, &query );
275 if( ret == ERROR_SUCCESS )
277 *phView = alloc_msihandle( &query->hdr );
278 if (! *phView)
279 ret = ERROR_NOT_ENOUGH_MEMORY;
280 msiobj_release( &query->hdr );
282 msiobj_release( &db->hdr );
284 return ret;
287 UINT msi_view_refresh_row(MSIDATABASE *db, MSIVIEW *view, UINT row, MSIRECORD *rec)
289 UINT row_count = 0, col_count = 0, i, ival, ret, type;
291 TRACE("%p %p %d %p\n", db, view, row, rec);
293 ret = view->ops->get_dimensions(view, &row_count, &col_count);
294 if (ret)
295 return ret;
297 if (!col_count)
298 return ERROR_INVALID_PARAMETER;
300 for (i = 1; i <= col_count; i++)
302 ret = view->ops->get_column_info(view, i, NULL, &type, NULL, NULL);
303 if (ret)
305 ERR("Error getting column type for %d\n", i);
306 continue;
309 if (MSITYPE_IS_BINARY(type))
311 IStream *stm = NULL;
313 ret = view->ops->fetch_stream(view, row, i, &stm);
314 if ((ret == ERROR_SUCCESS) && stm)
316 MSI_RecordSetIStream(rec, i, stm);
317 IStream_Release(stm);
319 else
320 WARN("failed to get stream\n");
322 continue;
325 ret = view->ops->fetch_int(view, row, i, &ival);
326 if (ret)
328 ERR("Error fetching data for %d\n", i);
329 continue;
332 if (! (type & MSITYPE_VALID))
333 ERR("Invalid type!\n");
335 if (type & MSITYPE_STRING)
337 int len;
338 const WCHAR *sval = msi_string_lookup(db->strings, ival, &len);
339 msi_record_set_string(rec, i, sval, len);
341 else
343 if ((type & MSI_DATASIZEMASK) == 2)
344 MSI_RecordSetInteger(rec, i, ival ? ival - (1<<15) : MSI_NULL_INTEGER);
345 else
346 MSI_RecordSetInteger(rec, i, ival - (1u<<31));
350 return ERROR_SUCCESS;
353 UINT msi_view_get_row(MSIDATABASE *db, MSIVIEW *view, UINT row, MSIRECORD **rec)
355 UINT row_count = 0, col_count = 0, r;
356 MSIRECORD *object;
358 TRACE("view %p, row %u, rec %p.\n", view, row, rec);
360 if ((r = view->ops->get_dimensions(view, &row_count, &col_count)))
361 return r;
363 if (row >= row_count)
364 return ERROR_NO_MORE_ITEMS;
366 if (!(object = MSI_CreateRecord( col_count )))
367 return ERROR_OUTOFMEMORY;
369 if ((r = msi_view_refresh_row(db, view, row, object)))
370 msiobj_release( &object->hdr );
371 else
372 *rec = object;
374 return r;
377 UINT MSI_ViewFetch(MSIQUERY *query, MSIRECORD **prec)
379 MSIVIEW *view;
380 UINT r;
382 TRACE("%p %p\n", query, prec );
384 view = query->view;
385 if( !view )
386 return ERROR_FUNCTION_FAILED;
388 r = msi_view_get_row(query->db, view, query->row, prec);
389 if (r == ERROR_SUCCESS)
391 query->row ++;
392 (*prec)->cookie = (UINT64)(ULONG_PTR)query;
393 MSI_RecordSetInteger(*prec, 0, 1);
395 else if (r == ERROR_NO_MORE_ITEMS)
397 /* end of view; reset cursor to first row */
398 query->row = 0;
401 return r;
404 UINT WINAPI MsiViewFetch( MSIHANDLE hView, MSIHANDLE *record )
406 MSIQUERY *query;
407 MSIRECORD *rec = NULL;
408 UINT ret;
410 TRACE( "%lu, %p\n", hView, record );
412 if( !record )
413 return ERROR_INVALID_PARAMETER;
414 *record = 0;
416 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
417 if (!query)
419 struct wire_record *wire_rec = NULL;
420 MSIHANDLE remote;
422 if (!(remote = msi_get_remote(hView)))
423 return ERROR_INVALID_HANDLE;
425 __TRY
427 ret = remote_ViewFetch(remote, &wire_rec);
429 __EXCEPT(rpc_filter)
431 ret = GetExceptionCode();
433 __ENDTRY
435 if (!ret)
437 ret = unmarshal_record(wire_rec, record);
438 free_remote_record(wire_rec);
440 return ret;
442 ret = MSI_ViewFetch( query, &rec );
443 if( ret == ERROR_SUCCESS )
445 *record = alloc_msihandle( &rec->hdr );
446 if (! *record)
447 ret = ERROR_NOT_ENOUGH_MEMORY;
448 msiobj_release( &rec->hdr );
450 msiobj_release( &query->hdr );
451 return ret;
454 UINT MSI_ViewClose(MSIQUERY *query)
456 MSIVIEW *view;
458 TRACE("%p\n", query );
460 view = query->view;
461 if( !view )
462 return ERROR_FUNCTION_FAILED;
463 if( !view->ops->close )
464 return ERROR_FUNCTION_FAILED;
466 return view->ops->close( view );
469 UINT WINAPI MsiViewClose( MSIHANDLE hView )
471 MSIQUERY *query;
472 UINT ret;
474 TRACE( "%lu\n", hView );
476 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
477 if (!query)
479 MSIHANDLE remote;
481 if (!(remote = msi_get_remote(hView)))
482 return ERROR_INVALID_HANDLE;
484 __TRY
486 ret = remote_ViewClose(remote);
488 __EXCEPT(rpc_filter)
490 ret = GetExceptionCode();
492 __ENDTRY
494 return ret;
497 ret = MSI_ViewClose( query );
498 msiobj_release( &query->hdr );
499 return ret;
502 UINT MSI_ViewExecute(MSIQUERY *query, MSIRECORD *rec )
504 MSIVIEW *view;
506 TRACE("%p %p\n", query, rec);
508 view = query->view;
509 if( !view )
510 return ERROR_FUNCTION_FAILED;
511 if( !view->ops->execute )
512 return ERROR_FUNCTION_FAILED;
513 query->row = 0;
515 return view->ops->execute( view, rec );
518 UINT WINAPI MsiViewExecute( MSIHANDLE hView, MSIHANDLE hRec )
520 MSIQUERY *query;
521 MSIRECORD *rec = NULL;
522 UINT ret;
524 TRACE( "%lu, %lu\n", hView, hRec );
526 if( hRec )
528 rec = msihandle2msiinfo( hRec, MSIHANDLETYPE_RECORD );
529 if( !rec )
530 return ERROR_INVALID_HANDLE;
533 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
534 if( !query )
536 MSIHANDLE remote;
538 if (!(remote = msi_get_remote(hView)))
539 return ERROR_INVALID_HANDLE;
541 __TRY
543 ret = remote_ViewExecute(remote, rec ? (struct wire_record *)&rec->count : NULL);
545 __EXCEPT(rpc_filter)
547 ret = GetExceptionCode();
549 __ENDTRY
551 if (rec)
552 msiobj_release(&rec->hdr);
553 return ret;
556 msiobj_lock( &rec->hdr );
557 ret = MSI_ViewExecute( query, rec );
558 msiobj_unlock( &rec->hdr );
560 msiobj_release( &query->hdr );
561 if( rec )
562 msiobj_release( &rec->hdr );
564 return ret;
567 static UINT set_record_type_string( MSIRECORD *rec, UINT field, UINT type, BOOL temporary )
569 WCHAR szType[0x10];
571 if (MSITYPE_IS_BINARY(type))
572 szType[0] = 'v';
573 else if (type & MSITYPE_LOCALIZABLE)
574 szType[0] = 'l';
575 else if (type & MSITYPE_UNKNOWN)
576 szType[0] = 'f';
577 else if (type & MSITYPE_STRING)
579 if (temporary)
580 szType[0] = 'g';
581 else
582 szType[0] = 's';
584 else
586 if (temporary)
587 szType[0] = 'j';
588 else
589 szType[0] = 'i';
592 if (type & MSITYPE_NULLABLE)
593 szType[0] &= ~0x20;
595 swprintf( &szType[1], ARRAY_SIZE(szType) - 1, L"%d", (type&0xff) );
597 TRACE("type %04x -> %s\n", type, debugstr_w(szType) );
599 return MSI_RecordSetStringW( rec, field, szType );
602 UINT MSI_ViewGetColumnInfo( MSIQUERY *query, MSICOLINFO info, MSIRECORD **prec )
604 UINT r = ERROR_FUNCTION_FAILED, i, count = 0, type;
605 MSIRECORD *rec;
606 MSIVIEW *view = query->view;
607 LPCWSTR name;
608 BOOL temporary;
610 if( !view )
611 return ERROR_FUNCTION_FAILED;
613 if( !view->ops->get_dimensions )
614 return ERROR_FUNCTION_FAILED;
616 r = view->ops->get_dimensions( view, NULL, &count );
617 if( r != ERROR_SUCCESS )
618 return r;
619 if( !count )
620 return ERROR_INVALID_PARAMETER;
622 rec = MSI_CreateRecord( count );
623 if( !rec )
624 return ERROR_FUNCTION_FAILED;
626 for( i=0; i<count; i++ )
628 name = NULL;
629 r = view->ops->get_column_info( view, i+1, &name, &type, &temporary, NULL );
630 if( r != ERROR_SUCCESS )
631 continue;
632 if (info == MSICOLINFO_NAMES)
633 MSI_RecordSetStringW( rec, i+1, name );
634 else
635 set_record_type_string( rec, i+1, type, temporary );
637 *prec = rec;
638 return ERROR_SUCCESS;
641 UINT WINAPI MsiViewGetColumnInfo( MSIHANDLE hView, MSICOLINFO info, MSIHANDLE *hRec )
643 MSIQUERY *query = NULL;
644 MSIRECORD *rec = NULL;
645 UINT r;
647 TRACE( "%lu, %d, %p\n", hView, info, hRec );
649 if( !hRec )
650 return ERROR_INVALID_PARAMETER;
652 if( info != MSICOLINFO_NAMES && info != MSICOLINFO_TYPES )
653 return ERROR_INVALID_PARAMETER;
655 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
656 if (!query)
658 struct wire_record *wire_rec = NULL;
659 MSIHANDLE remote;
661 if (!(remote = msi_get_remote(hView)))
662 return ERROR_INVALID_HANDLE;
664 __TRY
666 r = remote_ViewGetColumnInfo(remote, info, &wire_rec);
668 __EXCEPT(rpc_filter)
670 r = GetExceptionCode();
672 __ENDTRY
674 if (!r)
676 r = unmarshal_record(wire_rec, hRec);
677 free_remote_record(wire_rec);
680 return r;
683 r = MSI_ViewGetColumnInfo( query, info, &rec );
684 if ( r == ERROR_SUCCESS )
686 *hRec = alloc_msihandle( &rec->hdr );
687 if ( !*hRec )
688 r = ERROR_NOT_ENOUGH_MEMORY;
689 msiobj_release( &rec->hdr );
692 msiobj_release( &query->hdr );
694 return r;
697 UINT MSI_ViewModify( MSIQUERY *query, MSIMODIFY mode, MSIRECORD *rec )
699 MSIVIEW *view = NULL;
700 UINT r;
702 if ( !query || !rec )
703 return ERROR_INVALID_HANDLE;
705 view = query->view;
706 if ( !view || !view->ops->modify)
707 return ERROR_FUNCTION_FAILED;
709 if ( mode == MSIMODIFY_UPDATE && rec->cookie != (UINT64)(ULONG_PTR)query )
710 return ERROR_FUNCTION_FAILED;
712 r = view->ops->modify( view, mode, rec, query->row - 1 );
713 if (mode == MSIMODIFY_DELETE && r == ERROR_SUCCESS)
714 query->row--;
716 return r;
719 UINT WINAPI MsiViewModify( MSIHANDLE hView, MSIMODIFY eModifyMode, MSIHANDLE hRecord )
721 MSIQUERY *query = NULL;
722 MSIRECORD *rec = NULL;
723 UINT r = ERROR_FUNCTION_FAILED;
725 TRACE( "%lu, %#x, %lu\n", hView, eModifyMode, hRecord );
727 rec = msihandle2msiinfo( hRecord, MSIHANDLETYPE_RECORD );
729 if (!rec)
730 return ERROR_INVALID_HANDLE;
732 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
733 if (!query)
735 struct wire_record *wire_refreshed = NULL;
736 MSIHANDLE remote;
738 if (!(remote = msi_get_remote(hView)))
739 return ERROR_INVALID_HANDLE;
741 __TRY
743 r = remote_ViewModify(remote, eModifyMode,
744 (struct wire_record *)&rec->count, &wire_refreshed);
746 __EXCEPT(rpc_filter)
748 r = GetExceptionCode();
750 __ENDTRY
752 if (!r && (eModifyMode == MSIMODIFY_REFRESH || eModifyMode == MSIMODIFY_SEEK))
754 r = copy_remote_record(wire_refreshed, hRecord);
755 free_remote_record(wire_refreshed);
758 msiobj_release(&rec->hdr);
759 return r;
762 r = MSI_ViewModify( query, eModifyMode, rec );
764 msiobj_release( &query->hdr );
765 msiobj_release(&rec->hdr);
766 return r;
769 MSIDBERROR WINAPI MsiViewGetErrorW( MSIHANDLE handle, WCHAR *buffer, DWORD *buflen )
771 MSIQUERY *query;
772 const WCHAR *column;
773 MSIDBERROR r;
775 TRACE( "%lu, %p, %p\n", handle, buffer, buflen );
777 if (!buflen)
778 return MSIDBERROR_INVALIDARG;
780 if (!(query = msihandle2msiinfo(handle, MSIHANDLETYPE_VIEW)))
782 WCHAR *remote_column = NULL;
783 MSIHANDLE remote;
785 if (!(remote = msi_get_remote(handle)))
786 return MSIDBERROR_INVALIDARG;
788 if (!*buflen)
789 return MSIDBERROR_FUNCTIONERROR;
791 __TRY
793 r = remote_ViewGetError(remote, &remote_column);
795 __EXCEPT(rpc_filter)
797 r = GetExceptionCode();
799 __ENDTRY;
801 if (msi_strncpyW(remote_column ? remote_column : L"", -1, buffer, buflen) == ERROR_MORE_DATA)
802 r = MSIDBERROR_MOREDATA;
804 if (remote_column)
805 midl_user_free(remote_column);
807 return r;
810 if ((r = query->view->error)) column = query->view->error_column;
811 else column = L"";
813 if (msi_strncpyW(column, -1, buffer, buflen) == ERROR_MORE_DATA)
814 r = MSIDBERROR_MOREDATA;
816 msiobj_release( &query->hdr );
817 return r;
820 MSIDBERROR WINAPI MsiViewGetErrorA( MSIHANDLE handle, char *buffer, DWORD *buflen )
822 MSIQUERY *query;
823 const WCHAR *column;
824 MSIDBERROR r;
826 TRACE( "%lu, %p, %p\n", handle, buffer, buflen );
828 if (!buflen)
829 return MSIDBERROR_INVALIDARG;
831 if (!(query = msihandle2msiinfo(handle, MSIHANDLETYPE_VIEW)))
833 WCHAR *remote_column = NULL;
834 MSIHANDLE remote;
836 if (!(remote = msi_get_remote(handle)))
837 return MSIDBERROR_INVALIDARG;
839 if (!*buflen)
840 return MSIDBERROR_FUNCTIONERROR;
842 __TRY
844 r = remote_ViewGetError(remote, &remote_column);
846 __EXCEPT(rpc_filter)
848 r = GetExceptionCode();
850 __ENDTRY;
852 if (msi_strncpyWtoA(remote_column ? remote_column : L"", -1, buffer, buflen, FALSE) == ERROR_MORE_DATA)
853 r = MSIDBERROR_MOREDATA;
855 if (remote_column)
856 midl_user_free(remote_column);
858 return r;
861 if ((r = query->view->error)) column = query->view->error_column;
862 else column = L"";
864 if (msi_strncpyWtoA(column, -1, buffer, buflen, FALSE) == ERROR_MORE_DATA)
865 r = MSIDBERROR_MOREDATA;
867 msiobj_release( &query->hdr );
868 return r;
871 MSIHANDLE WINAPI MsiGetLastErrorRecord( void )
873 FIXME("\n");
874 return 0;
877 UINT MSI_DatabaseApplyTransformW( MSIDATABASE *db, const WCHAR *transform, int error_cond )
879 HRESULT hr;
880 UINT ret = ERROR_FUNCTION_FAILED;
881 IStorage *stg;
882 STATSTG stat;
884 TRACE( "%p %s %08x\n", db, debugstr_w(transform), error_cond );
886 if (*transform == ':')
888 hr = IStorage_OpenStorage( db->storage, transform + 1, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
889 if (FAILED( hr ))
891 WARN( "failed to open substorage transform %#lx\n", hr );
892 return ERROR_FUNCTION_FAILED;
895 else
897 hr = StgOpenStorage( transform, NULL, STGM_DIRECT|STGM_READ|STGM_SHARE_DENY_WRITE, NULL, 0, &stg );
898 if (FAILED( hr ))
900 WARN( "failed to open file transform %#lx\n", hr );
901 return ERROR_FUNCTION_FAILED;
905 hr = IStorage_Stat( stg, &stat, STATFLAG_NONAME );
906 if (FAILED( hr )) goto end;
907 if (!IsEqualGUID( &stat.clsid, &CLSID_MsiTransform )) goto end;
908 if (TRACE_ON( msi )) enum_stream_names( stg );
910 ret = msi_table_apply_transform( db, stg, error_cond );
912 end:
913 IStorage_Release( stg );
914 return ret;
917 UINT WINAPI MsiDatabaseApplyTransformW( MSIHANDLE hdb, const WCHAR *transform, int error_cond )
919 MSIDATABASE *db;
920 UINT r;
922 if (error_cond & ~MSITRANSFORM_ERROR_VIEWTRANSFORM) FIXME( "ignoring error conditions\n" );
924 if (!(db = msihandle2msiinfo(hdb, MSIHANDLETYPE_DATABASE)))
925 return ERROR_INVALID_HANDLE;
927 r = MSI_DatabaseApplyTransformW( db, transform, error_cond );
928 msiobj_release( &db->hdr );
929 return r;
932 UINT WINAPI MsiDatabaseApplyTransformA( MSIHANDLE hdb, const char *transform, int error_cond )
934 WCHAR *wstr;
935 UINT ret;
937 TRACE( "%lu, %s, %#x\n", hdb, debugstr_a(transform), error_cond );
939 wstr = strdupAtoW( transform );
940 if (transform && !wstr)
941 return ERROR_NOT_ENOUGH_MEMORY;
943 ret = MsiDatabaseApplyTransformW( hdb, wstr, error_cond );
944 free( wstr );
945 return ret;
948 UINT WINAPI MsiDatabaseGenerateTransformA( MSIHANDLE hdb, MSIHANDLE hdbref, const char *szTransformFile,
949 int iReserved1, int iReserved2 )
951 FIXME( "%lu, %lu, %s, %d, %d\n", hdb, hdbref, debugstr_a(szTransformFile), iReserved1, iReserved2 );
952 return ERROR_CALL_NOT_IMPLEMENTED;
955 UINT WINAPI MsiDatabaseGenerateTransformW( MSIHANDLE hdb, MSIHANDLE hdbref, const WCHAR *szTransformFile,
956 int iReserved1, int iReserved2 )
958 FIXME( "%lu, %lu, %s, %d, %d\n", hdb, hdbref, debugstr_w(szTransformFile), iReserved1, iReserved2 );
959 return ERROR_CALL_NOT_IMPLEMENTED;
962 UINT WINAPI MsiDatabaseCommit( MSIHANDLE hdb )
964 MSIDATABASE *db;
965 UINT r;
967 TRACE( "%lu\n", hdb );
969 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
970 if( !db )
972 MSIHANDLE remote;
974 if (!(remote = msi_get_remote(hdb)))
975 return ERROR_INVALID_HANDLE;
977 WARN("not allowed during a custom action!\n");
979 return ERROR_SUCCESS;
982 if (db->mode == MSI_OPEN_READONLY)
984 msiobj_release( &db->hdr );
985 return ERROR_SUCCESS;
988 /* FIXME: lock the database */
990 r = msi_commit_streams( db );
991 if (r != ERROR_SUCCESS) ERR("Failed to commit streams!\n");
992 else
994 r = MSI_CommitTables( db );
995 if (r != ERROR_SUCCESS) ERR("Failed to commit tables!\n");
998 /* FIXME: unlock the database */
1000 msiobj_release( &db->hdr );
1002 if (r == ERROR_SUCCESS)
1004 free( db->deletefile );
1005 db->deletefile = NULL;
1008 return r;
1011 struct primary_key_record_info
1013 DWORD n;
1014 MSIRECORD *rec;
1017 static UINT primary_key_iterator( MSIRECORD *rec, void *param )
1019 struct primary_key_record_info *info = param;
1020 LPCWSTR name, table;
1021 DWORD type;
1023 type = MSI_RecordGetInteger( rec, 4 );
1024 if( type & MSITYPE_KEY )
1026 info->n++;
1027 if( info->rec )
1029 if ( info->n == 1 )
1031 table = MSI_RecordGetString( rec, 1 );
1032 MSI_RecordSetStringW( info->rec, 0, table);
1035 name = MSI_RecordGetString( rec, 3 );
1036 MSI_RecordSetStringW( info->rec, info->n, name );
1040 return ERROR_SUCCESS;
1043 UINT MSI_DatabaseGetPrimaryKeys( MSIDATABASE *db, const WCHAR *table, MSIRECORD **prec )
1045 struct primary_key_record_info info;
1046 MSIQUERY *query = NULL;
1047 UINT r;
1049 if (!TABLE_Exists( db, table ))
1050 return ERROR_INVALID_TABLE;
1052 r = MSI_OpenQuery( db, &query, L"SELECT * FROM `_Columns` WHERE `Table` = '%s'", table );
1053 if( r != ERROR_SUCCESS )
1054 return r;
1056 /* count the number of primary key records */
1057 info.n = 0;
1058 info.rec = 0;
1059 r = MSI_IterateRecords( query, 0, primary_key_iterator, &info );
1060 if( r == ERROR_SUCCESS )
1062 TRACE( "found %lu primary keys\n", info.n );
1064 /* allocate a record and fill in the names of the tables */
1065 info.rec = MSI_CreateRecord( info.n );
1066 info.n = 0;
1067 r = MSI_IterateRecords( query, 0, primary_key_iterator, &info );
1068 if( r == ERROR_SUCCESS )
1069 *prec = info.rec;
1070 else
1071 msiobj_release( &info.rec->hdr );
1073 msiobj_release( &query->hdr );
1075 return r;
1078 UINT WINAPI MsiDatabaseGetPrimaryKeysW( MSIHANDLE hdb, const WCHAR *table, MSIHANDLE *phRec )
1080 MSIRECORD *rec = NULL;
1081 MSIDATABASE *db;
1082 UINT r;
1084 TRACE( "%lu, %s, %p\n", hdb, debugstr_w(table), phRec );
1086 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
1087 if( !db )
1089 struct wire_record *wire_rec = NULL;
1090 MSIHANDLE remote;
1092 if (!(remote = msi_get_remote(hdb)))
1093 return ERROR_INVALID_HANDLE;
1095 __TRY
1097 r = remote_DatabaseGetPrimaryKeys(remote, table, &wire_rec);
1099 __EXCEPT(rpc_filter)
1101 r = GetExceptionCode();
1103 __ENDTRY
1105 if (!r)
1107 r = unmarshal_record(wire_rec, phRec);
1108 free_remote_record(wire_rec);
1111 return r;
1114 r = MSI_DatabaseGetPrimaryKeys( db, table, &rec );
1115 if( r == ERROR_SUCCESS )
1117 *phRec = alloc_msihandle( &rec->hdr );
1118 if (! *phRec)
1119 r = ERROR_NOT_ENOUGH_MEMORY;
1120 msiobj_release( &rec->hdr );
1122 msiobj_release( &db->hdr );
1124 return r;
1127 UINT WINAPI MsiDatabaseGetPrimaryKeysA( MSIHANDLE hdb, const char *table, MSIHANDLE *phRec )
1129 WCHAR *szwTable = NULL;
1130 UINT r;
1132 TRACE( "%lu, %s, %p\n", hdb, debugstr_a(table), phRec );
1134 if( table )
1136 szwTable = strdupAtoW( table );
1137 if( !szwTable )
1138 return ERROR_OUTOFMEMORY;
1140 r = MsiDatabaseGetPrimaryKeysW( hdb, szwTable, phRec );
1141 free( szwTable );
1143 return r;
1146 MSICONDITION WINAPI MsiDatabaseIsTablePersistentA( MSIHANDLE hDatabase, const char *szTableName )
1148 WCHAR *szwTableName = NULL;
1149 MSICONDITION r;
1151 TRACE( "%lu, %s\n", hDatabase, debugstr_a(szTableName) );
1153 if( szTableName )
1155 szwTableName = strdupAtoW( szTableName );
1156 if( !szwTableName )
1157 return MSICONDITION_ERROR;
1159 r = MsiDatabaseIsTablePersistentW( hDatabase, szwTableName );
1160 free( szwTableName );
1162 return r;
1165 MSICONDITION WINAPI MsiDatabaseIsTablePersistentW( MSIHANDLE hDatabase, const WCHAR *szTableName )
1167 MSIDATABASE *db;
1168 MSICONDITION r;
1170 TRACE( "%lu, %s\n", hDatabase, debugstr_w(szTableName) );
1172 db = msihandle2msiinfo( hDatabase, MSIHANDLETYPE_DATABASE );
1173 if( !db )
1175 MSIHANDLE remote;
1177 if (!(remote = msi_get_remote(hDatabase)))
1178 return MSICONDITION_ERROR;
1180 __TRY
1182 r = remote_DatabaseIsTablePersistent(remote, szTableName);
1184 __EXCEPT(rpc_filter)
1186 r = MSICONDITION_ERROR;
1188 __ENDTRY
1190 return r;
1193 r = MSI_DatabaseIsTablePersistent( db, szTableName );
1195 msiobj_release( &db->hdr );
1197 return r;
1200 UINT __cdecl s_remote_ViewClose(MSIHANDLE view)
1202 return MsiViewClose(view);
1205 UINT __cdecl s_remote_ViewExecute(MSIHANDLE view, struct wire_record *remote_rec)
1207 MSIHANDLE rec = 0;
1208 UINT r;
1210 if ((r = unmarshal_record(remote_rec, &rec)))
1211 return r;
1213 r = MsiViewExecute(view, rec);
1215 MsiCloseHandle(rec);
1216 return r;
1219 UINT __cdecl s_remote_ViewFetch(MSIHANDLE view, struct wire_record **rec)
1221 MSIHANDLE handle;
1222 UINT r = MsiViewFetch(view, &handle);
1223 *rec = NULL;
1224 if (!r)
1225 *rec = marshal_record(handle);
1226 MsiCloseHandle(handle);
1227 return r;
1230 UINT __cdecl s_remote_ViewGetColumnInfo(MSIHANDLE view, MSICOLINFO info, struct wire_record **rec)
1232 MSIHANDLE handle;
1233 UINT r = MsiViewGetColumnInfo(view, info, &handle);
1234 *rec = NULL;
1235 if (!r)
1236 *rec = marshal_record(handle);
1237 MsiCloseHandle(handle);
1238 return r;
1241 MSIDBERROR __cdecl s_remote_ViewGetError(MSIHANDLE view, LPWSTR *column)
1243 WCHAR empty[1];
1244 DWORD size = 1;
1245 UINT r;
1247 r = MsiViewGetErrorW(view, empty, &size);
1248 if (r == MSIDBERROR_MOREDATA)
1250 if (!(*column = midl_user_allocate(++size * sizeof(WCHAR))))
1251 return MSIDBERROR_FUNCTIONERROR;
1252 r = MsiViewGetErrorW(view, *column, &size);
1254 return r;
1257 UINT __cdecl s_remote_ViewModify(MSIHANDLE view, MSIMODIFY mode,
1258 struct wire_record *remote_rec, struct wire_record **remote_refreshed)
1260 MSIHANDLE handle = 0;
1261 UINT r;
1263 if ((r = unmarshal_record(remote_rec, &handle)))
1264 return r;
1266 r = MsiViewModify(view, mode, handle);
1267 *remote_refreshed = NULL;
1268 if (!r && (mode == MSIMODIFY_REFRESH || mode == MSIMODIFY_SEEK))
1269 *remote_refreshed = marshal_record(handle);
1271 MsiCloseHandle(handle);
1272 return r;