usp10: Handle dangling joiners when processing Indic GlyphProps.
[wine.git] / dlls / msi / msiquery.c
blob0f2e3777dc32b2fd2c5af9f11e6a6d6754d10378
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/unicode.h"
30 #include "msi.h"
31 #include "msiquery.h"
32 #include "objbase.h"
33 #include "objidl.h"
34 #include "msipriv.h"
35 #include "winnls.h"
37 #include "query.h"
38 #include "msiserver.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 = strcmpW( name, col_name );
77 if( table_name )
78 x |= strcmpW( 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 if( !szQuery)
120 return ERROR_INVALID_PARAMETER;
122 /* pre allocate a handle to hold a pointer to the view */
123 query = alloc_msiobject( MSIHANDLETYPE_VIEW, sizeof (MSIQUERY),
124 MSI_CloseView );
125 if( !query )
126 return ERROR_FUNCTION_FAILED;
128 msiobj_addref( &db->hdr );
129 query->db = db;
130 list_init( &query->mem );
132 r = MSI_ParseSQL( db, szQuery, &query->view, &query->mem );
133 if( r == ERROR_SUCCESS )
135 msiobj_addref( &query->hdr );
136 *pView = query;
139 msiobj_release( &query->hdr );
140 return r;
143 UINT MSI_OpenQuery( MSIDATABASE *db, MSIQUERY **view, LPCWSTR fmt, ... )
145 UINT r;
146 int size = 100, res;
147 LPWSTR query;
149 /* construct the string */
150 for (;;)
152 va_list va;
153 query = msi_alloc( size*sizeof(WCHAR) );
154 va_start(va, fmt);
155 res = vsnprintfW(query, size, fmt, va);
156 va_end(va);
157 if (res == -1) size *= 2;
158 else if (res >= size) size = res + 1;
159 else break;
160 msi_free( query );
162 /* perform the query */
163 r = MSI_DatabaseOpenViewW(db, query, view);
164 msi_free(query);
165 return r;
168 UINT MSI_IterateRecords( MSIQUERY *view, LPDWORD count,
169 record_func func, LPVOID param )
171 MSIRECORD *rec = NULL;
172 UINT r, n = 0, max = 0;
174 r = MSI_ViewExecute( view, NULL );
175 if( r != ERROR_SUCCESS )
176 return r;
178 if( count )
179 max = *count;
181 /* iterate a query */
182 for( n = 0; (max == 0) || (n < max); n++ )
184 r = MSI_ViewFetch( view, &rec );
185 if( r != ERROR_SUCCESS )
186 break;
187 if (func)
188 r = func( rec, param );
189 msiobj_release( &rec->hdr );
190 if( r != ERROR_SUCCESS )
191 break;
194 MSI_ViewClose( view );
196 if( count )
197 *count = n;
199 if( r == ERROR_NO_MORE_ITEMS )
200 r = ERROR_SUCCESS;
202 return r;
205 /* return a single record from a query */
206 MSIRECORD *MSI_QueryGetRecord( MSIDATABASE *db, LPCWSTR fmt, ... )
208 MSIRECORD *rec = NULL;
209 MSIQUERY *view = NULL;
210 UINT r;
211 int size = 100, res;
212 LPWSTR query;
214 /* construct the string */
215 for (;;)
217 va_list va;
218 query = msi_alloc( size*sizeof(WCHAR) );
219 va_start(va, fmt);
220 res = vsnprintfW(query, size, fmt, va);
221 va_end(va);
222 if (res == -1) size *= 2;
223 else if (res >= size) size = res + 1;
224 else break;
225 msi_free( query );
227 /* perform the query */
228 r = MSI_DatabaseOpenViewW(db, query, &view);
229 msi_free(query);
231 if( r == ERROR_SUCCESS )
233 MSI_ViewExecute( view, NULL );
234 MSI_ViewFetch( view, &rec );
235 MSI_ViewClose( view );
236 msiobj_release( &view->hdr );
238 return rec;
241 UINT WINAPI MsiDatabaseOpenViewW(MSIHANDLE hdb,
242 LPCWSTR szQuery, MSIHANDLE *phView)
244 MSIDATABASE *db;
245 MSIQUERY *query = NULL;
246 UINT ret;
248 TRACE("%s %p\n", debugstr_w(szQuery), phView);
250 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
251 if( !db )
253 HRESULT hr;
254 IWineMsiRemoteDatabase *remote_database;
256 remote_database = (IWineMsiRemoteDatabase *)msi_get_remote( hdb );
257 if ( !remote_database )
258 return ERROR_INVALID_HANDLE;
260 hr = IWineMsiRemoteDatabase_OpenView( remote_database, szQuery, phView );
261 IWineMsiRemoteDatabase_Release( remote_database );
263 if (FAILED(hr))
265 if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
266 return HRESULT_CODE(hr);
268 return ERROR_FUNCTION_FAILED;
271 return ERROR_SUCCESS;
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_get_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 if (row >= row_count)
301 return ERROR_NO_MORE_ITEMS;
303 *rec = MSI_CreateRecord(col_count);
304 if (!*rec)
305 return ERROR_FUNCTION_FAILED;
307 for (i = 1; i <= col_count; i++)
309 ret = view->ops->get_column_info(view, i, NULL, &type, NULL, NULL);
310 if (ret)
312 ERR("Error getting column type for %d\n", i);
313 continue;
316 if (MSITYPE_IS_BINARY(type))
318 IStream *stm = NULL;
320 ret = view->ops->fetch_stream(view, row, i, &stm);
321 if ((ret == ERROR_SUCCESS) && stm)
323 MSI_RecordSetIStream(*rec, i, stm);
324 IStream_Release(stm);
326 else
327 WARN("failed to get stream\n");
329 continue;
332 ret = view->ops->fetch_int(view, row, i, &ival);
333 if (ret)
335 ERR("Error fetching data for %d\n", i);
336 continue;
339 if (! (type & MSITYPE_VALID))
340 ERR("Invalid type!\n");
342 /* check if it's nul (0) - if so, don't set anything */
343 if (!ival)
344 continue;
346 if (type & MSITYPE_STRING)
348 LPCWSTR sval;
350 sval = msi_string_lookup_id(db->strings, ival);
351 MSI_RecordSetStringW(*rec, i, sval);
353 else
355 if ((type & MSI_DATASIZEMASK) == 2)
356 MSI_RecordSetInteger(*rec, i, ival - (1<<15));
357 else
358 MSI_RecordSetInteger(*rec, i, ival - (1<<31));
362 return ERROR_SUCCESS;
365 UINT MSI_ViewFetch(MSIQUERY *query, MSIRECORD **prec)
367 MSIVIEW *view;
368 UINT r;
370 TRACE("%p %p\n", query, prec );
372 view = query->view;
373 if( !view )
374 return ERROR_FUNCTION_FAILED;
376 r = msi_view_get_row(query->db, view, query->row, prec);
377 if (r == ERROR_SUCCESS)
379 query->row ++;
380 MSI_RecordSetIntPtr(*prec, 0, (INT_PTR)query);
383 return r;
386 UINT WINAPI MsiViewFetch(MSIHANDLE hView, MSIHANDLE *record)
388 MSIQUERY *query;
389 MSIRECORD *rec = NULL;
390 UINT ret;
392 TRACE("%d %p\n", hView, record);
394 if( !record )
395 return ERROR_INVALID_PARAMETER;
396 *record = 0;
398 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
399 if( !query )
400 return ERROR_INVALID_HANDLE;
401 ret = MSI_ViewFetch( query, &rec );
402 if( ret == ERROR_SUCCESS )
404 *record = alloc_msihandle( &rec->hdr );
405 if (! *record)
406 ret = ERROR_NOT_ENOUGH_MEMORY;
407 msiobj_release( &rec->hdr );
409 msiobj_release( &query->hdr );
410 return ret;
413 UINT MSI_ViewClose(MSIQUERY *query)
415 MSIVIEW *view;
417 TRACE("%p\n", query );
419 view = query->view;
420 if( !view )
421 return ERROR_FUNCTION_FAILED;
422 if( !view->ops->close )
423 return ERROR_FUNCTION_FAILED;
425 return view->ops->close( view );
428 UINT WINAPI MsiViewClose(MSIHANDLE hView)
430 MSIQUERY *query;
431 UINT ret;
433 TRACE("%d\n", hView );
435 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
436 if( !query )
437 return ERROR_INVALID_HANDLE;
439 ret = MSI_ViewClose( query );
440 msiobj_release( &query->hdr );
441 return ret;
444 UINT MSI_ViewExecute(MSIQUERY *query, MSIRECORD *rec )
446 MSIVIEW *view;
448 TRACE("%p %p\n", query, rec);
450 view = query->view;
451 if( !view )
452 return ERROR_FUNCTION_FAILED;
453 if( !view->ops->execute )
454 return ERROR_FUNCTION_FAILED;
455 query->row = 0;
457 return view->ops->execute( view, rec );
460 UINT WINAPI MsiViewExecute(MSIHANDLE hView, MSIHANDLE hRec)
462 MSIQUERY *query;
463 MSIRECORD *rec = NULL;
464 UINT ret;
466 TRACE("%d %d\n", hView, hRec);
468 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
469 if( !query )
470 return ERROR_INVALID_HANDLE;
472 if( hRec )
474 rec = msihandle2msiinfo( hRec, MSIHANDLETYPE_RECORD );
475 if( !rec )
477 ret = ERROR_INVALID_HANDLE;
478 goto out;
482 msiobj_lock( &rec->hdr );
483 ret = MSI_ViewExecute( query, rec );
484 msiobj_unlock( &rec->hdr );
486 out:
487 msiobj_release( &query->hdr );
488 if( rec )
489 msiobj_release( &rec->hdr );
491 return ret;
494 static UINT msi_set_record_type_string( MSIRECORD *rec, UINT field,
495 UINT type, BOOL temporary )
497 static const WCHAR fmt[] = { '%','d',0 };
498 WCHAR szType[0x10];
500 if (MSITYPE_IS_BINARY(type))
501 szType[0] = 'v';
502 else if (type & MSITYPE_LOCALIZABLE)
503 szType[0] = 'l';
504 else if (type & MSITYPE_STRING)
506 if (temporary)
507 szType[0] = 'g';
508 else
509 szType[0] = 's';
511 else
513 if (temporary)
514 szType[0] = 'j';
515 else
516 szType[0] = 'i';
519 if (type & MSITYPE_NULLABLE)
520 szType[0] &= ~0x20;
522 sprintfW( &szType[1], fmt, (type&0xff) );
524 TRACE("type %04x -> %s\n", type, debugstr_w(szType) );
526 return MSI_RecordSetStringW( rec, field, szType );
529 UINT MSI_ViewGetColumnInfo( MSIQUERY *query, MSICOLINFO info, MSIRECORD **prec )
531 UINT r = ERROR_FUNCTION_FAILED, i, count = 0, type;
532 MSIRECORD *rec;
533 MSIVIEW *view = query->view;
534 LPCWSTR name;
535 BOOL temporary;
537 if( !view )
538 return ERROR_FUNCTION_FAILED;
540 if( !view->ops->get_dimensions )
541 return ERROR_FUNCTION_FAILED;
543 r = view->ops->get_dimensions( view, NULL, &count );
544 if( r != ERROR_SUCCESS )
545 return r;
546 if( !count )
547 return ERROR_INVALID_PARAMETER;
549 rec = MSI_CreateRecord( count );
550 if( !rec )
551 return ERROR_FUNCTION_FAILED;
553 for( i=0; i<count; i++ )
555 name = NULL;
556 r = view->ops->get_column_info( view, i+1, &name, &type, &temporary, NULL );
557 if( r != ERROR_SUCCESS )
558 continue;
559 if (info == MSICOLINFO_NAMES)
560 MSI_RecordSetStringW( rec, i+1, name );
561 else
562 msi_set_record_type_string( rec, i+1, type, temporary );
564 *prec = rec;
565 return ERROR_SUCCESS;
568 UINT WINAPI MsiViewGetColumnInfo(MSIHANDLE hView, MSICOLINFO info, MSIHANDLE *hRec)
570 MSIQUERY *query = NULL;
571 MSIRECORD *rec = NULL;
572 UINT r;
574 TRACE("%d %d %p\n", hView, info, hRec);
576 if( !hRec )
577 return ERROR_INVALID_PARAMETER;
579 if( info != MSICOLINFO_NAMES && info != MSICOLINFO_TYPES )
580 return ERROR_INVALID_PARAMETER;
582 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
583 if( !query )
584 return ERROR_INVALID_HANDLE;
586 r = MSI_ViewGetColumnInfo( query, info, &rec );
587 if ( r == ERROR_SUCCESS )
589 *hRec = alloc_msihandle( &rec->hdr );
590 if ( !*hRec )
591 r = ERROR_NOT_ENOUGH_MEMORY;
592 msiobj_release( &rec->hdr );
595 msiobj_release( &query->hdr );
597 return r;
600 UINT MSI_ViewModify( MSIQUERY *query, MSIMODIFY mode, MSIRECORD *rec )
602 MSIVIEW *view = NULL;
603 UINT r;
605 if ( !query || !rec )
606 return ERROR_INVALID_HANDLE;
608 view = query->view;
609 if ( !view || !view->ops->modify)
610 return ERROR_FUNCTION_FAILED;
612 if ( mode == MSIMODIFY_UPDATE && MSI_RecordGetIntPtr( rec, 0 ) != (INT_PTR)query )
613 return ERROR_FUNCTION_FAILED;
615 r = view->ops->modify( view, mode, rec, query->row );
616 if (mode == MSIMODIFY_DELETE && r == ERROR_SUCCESS)
617 query->row--;
619 return r;
622 UINT WINAPI MsiViewModify( MSIHANDLE hView, MSIMODIFY eModifyMode,
623 MSIHANDLE hRecord)
625 MSIQUERY *query = NULL;
626 MSIRECORD *rec = NULL;
627 UINT r = ERROR_FUNCTION_FAILED;
629 TRACE("%d %x %d\n", hView, eModifyMode, hRecord);
631 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
632 if( !query )
633 return ERROR_INVALID_HANDLE;
635 rec = msihandle2msiinfo( hRecord, MSIHANDLETYPE_RECORD );
636 r = MSI_ViewModify( query, eModifyMode, rec );
638 msiobj_release( &query->hdr );
639 if( rec )
640 msiobj_release( &rec->hdr );
642 return r;
645 MSIDBERROR WINAPI MsiViewGetErrorW( MSIHANDLE handle, LPWSTR buffer, LPDWORD buflen )
647 MSIQUERY *query;
648 const WCHAR *column;
649 MSIDBERROR r;
650 DWORD len;
652 TRACE("%u %p %p\n", handle, buffer, buflen);
654 if (!buflen)
655 return MSIDBERROR_INVALIDARG;
657 query = msihandle2msiinfo( handle, MSIHANDLETYPE_VIEW );
658 if( !query )
659 return MSIDBERROR_INVALIDARG;
661 if ((r = query->view->error)) column = query->view->error_column;
662 else column = szEmpty;
664 len = strlenW( column );
665 if (buffer)
667 if (*buflen > len)
668 strcpyW( buffer, column );
669 else
670 r = MSIDBERROR_MOREDATA;
672 *buflen = len;
673 msiobj_release( &query->hdr );
674 return r;
677 MSIDBERROR WINAPI MsiViewGetErrorA( MSIHANDLE handle, LPSTR buffer, LPDWORD buflen )
679 MSIQUERY *query;
680 const WCHAR *column;
681 MSIDBERROR r;
682 DWORD len;
684 TRACE("%u %p %p\n", handle, buffer, buflen);
686 if (!buflen)
687 return MSIDBERROR_INVALIDARG;
689 query = msihandle2msiinfo( handle, MSIHANDLETYPE_VIEW );
690 if (!query)
691 return MSIDBERROR_INVALIDARG;
693 if ((r = query->view->error)) column = query->view->error_column;
694 else column = szEmpty;
696 len = WideCharToMultiByte( CP_ACP, 0, column, -1, NULL, 0, NULL, NULL );
697 if (buffer)
699 if (*buflen >= len)
700 WideCharToMultiByte( CP_ACP, 0, column, -1, buffer, *buflen, NULL, NULL );
701 else
702 r = MSIDBERROR_MOREDATA;
704 *buflen = len - 1;
705 msiobj_release( &query->hdr );
706 return r;
709 MSIHANDLE WINAPI MsiGetLastErrorRecord( void )
711 FIXME("\n");
712 return 0;
715 UINT MSI_DatabaseApplyTransformW( MSIDATABASE *db,
716 LPCWSTR szTransformFile, int iErrorCond )
718 HRESULT r;
719 UINT ret = ERROR_FUNCTION_FAILED;
720 IStorage *stg = NULL;
721 STATSTG stat;
723 TRACE("%p %s %d\n", db, debugstr_w(szTransformFile), iErrorCond);
725 r = StgOpenStorage( szTransformFile, NULL,
726 STGM_DIRECT|STGM_READ|STGM_SHARE_DENY_WRITE, NULL, 0, &stg);
727 if ( FAILED(r) )
729 WARN("failed to open transform 0x%08x\n", r);
730 return ret;
733 r = IStorage_Stat( stg, &stat, STATFLAG_NONAME );
734 if ( FAILED( r ) )
735 goto end;
737 if ( !IsEqualGUID( &stat.clsid, &CLSID_MsiTransform ) )
738 goto end;
740 if( TRACE_ON( msi ) )
741 enum_stream_names( stg );
743 ret = msi_table_apply_transform( db, stg );
745 end:
746 IStorage_Release( stg );
748 return ret;
751 UINT WINAPI MsiDatabaseApplyTransformW( MSIHANDLE hdb,
752 LPCWSTR szTransformFile, int iErrorCond)
754 MSIDATABASE *db;
755 UINT r;
757 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
758 if( !db )
760 IWineMsiRemoteDatabase *remote_database;
762 remote_database = (IWineMsiRemoteDatabase *)msi_get_remote( hdb );
763 if ( !remote_database )
764 return ERROR_INVALID_HANDLE;
766 IWineMsiRemoteDatabase_Release( remote_database );
767 WARN("MsiDatabaseApplyTransform not allowed during a custom action!\n");
769 return ERROR_SUCCESS;
772 r = MSI_DatabaseApplyTransformW( db, szTransformFile, iErrorCond );
773 msiobj_release( &db->hdr );
774 return r;
777 UINT WINAPI MsiDatabaseApplyTransformA( MSIHANDLE hdb,
778 LPCSTR szTransformFile, int iErrorCond)
780 LPWSTR wstr;
781 UINT ret;
783 TRACE("%d %s %d\n", hdb, debugstr_a(szTransformFile), iErrorCond);
785 wstr = strdupAtoW( szTransformFile );
786 if( szTransformFile && !wstr )
787 return ERROR_NOT_ENOUGH_MEMORY;
789 ret = MsiDatabaseApplyTransformW( hdb, wstr, iErrorCond);
791 msi_free( wstr );
793 return ret;
796 UINT WINAPI MsiDatabaseGenerateTransformA( MSIHANDLE hdb, MSIHANDLE hdbref,
797 LPCSTR szTransformFile, int iReserved1, int iReserved2 )
799 FIXME("%d %d %s %d %d\n", hdb, hdbref,
800 debugstr_a(szTransformFile), iReserved1, iReserved2);
801 return ERROR_CALL_NOT_IMPLEMENTED;
804 UINT WINAPI MsiDatabaseGenerateTransformW( MSIHANDLE hdb, MSIHANDLE hdbref,
805 LPCWSTR szTransformFile, int iReserved1, int iReserved2 )
807 FIXME("%d %d %s %d %d\n", hdb, hdbref,
808 debugstr_w(szTransformFile), iReserved1, iReserved2);
809 return ERROR_CALL_NOT_IMPLEMENTED;
812 UINT WINAPI MsiDatabaseCommit( MSIHANDLE hdb )
814 MSIDATABASE *db;
815 UINT r;
817 TRACE("%d\n", hdb);
819 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
820 if( !db )
822 IWineMsiRemoteDatabase *remote_database;
824 remote_database = (IWineMsiRemoteDatabase *)msi_get_remote( hdb );
825 if ( !remote_database )
826 return ERROR_INVALID_HANDLE;
828 IWineMsiRemoteDatabase_Release( remote_database );
829 WARN("not allowed during a custom action!\n");
831 return ERROR_SUCCESS;
834 if (db->mode == MSIDBOPEN_READONLY)
836 msiobj_release( &db->hdr );
837 return ERROR_SUCCESS;
840 /* FIXME: lock the database */
842 r = MSI_CommitTables( db );
843 if (r != ERROR_SUCCESS) ERR("Failed to commit tables!\n");
845 /* FIXME: unlock the database */
847 msiobj_release( &db->hdr );
849 if (r == ERROR_SUCCESS)
851 msi_free( db->deletefile );
852 db->deletefile = NULL;
855 return r;
858 struct msi_primary_key_record_info
860 DWORD n;
861 MSIRECORD *rec;
864 static UINT msi_primary_key_iterator( MSIRECORD *rec, LPVOID param )
866 struct msi_primary_key_record_info *info = param;
867 LPCWSTR name, table;
868 DWORD type;
870 type = MSI_RecordGetInteger( rec, 4 );
871 if( type & MSITYPE_KEY )
873 info->n++;
874 if( info->rec )
876 if ( info->n == 1 )
878 table = MSI_RecordGetString( rec, 1 );
879 MSI_RecordSetStringW( info->rec, 0, table);
882 name = MSI_RecordGetString( rec, 3 );
883 MSI_RecordSetStringW( info->rec, info->n, name );
887 return ERROR_SUCCESS;
890 UINT MSI_DatabaseGetPrimaryKeys( MSIDATABASE *db,
891 LPCWSTR table, MSIRECORD **prec )
893 static const WCHAR sql[] = {
894 's','e','l','e','c','t',' ','*',' ',
895 'f','r','o','m',' ','`','_','C','o','l','u','m','n','s','`',' ',
896 'w','h','e','r','e',' ',
897 '`','T','a','b','l','e','`',' ','=',' ','\'','%','s','\'',0 };
898 struct msi_primary_key_record_info info;
899 MSIQUERY *query = NULL;
900 UINT r;
902 if (!TABLE_Exists( db, table ))
903 return ERROR_INVALID_TABLE;
905 r = MSI_OpenQuery( db, &query, sql, table );
906 if( r != ERROR_SUCCESS )
907 return r;
909 /* count the number of primary key records */
910 info.n = 0;
911 info.rec = 0;
912 r = MSI_IterateRecords( query, 0, msi_primary_key_iterator, &info );
913 if( r == ERROR_SUCCESS )
915 TRACE("Found %d primary keys\n", info.n );
917 /* allocate a record and fill in the names of the tables */
918 info.rec = MSI_CreateRecord( info.n );
919 info.n = 0;
920 r = MSI_IterateRecords( query, 0, msi_primary_key_iterator, &info );
921 if( r == ERROR_SUCCESS )
922 *prec = info.rec;
923 else
924 msiobj_release( &info.rec->hdr );
926 msiobj_release( &query->hdr );
928 return r;
931 UINT WINAPI MsiDatabaseGetPrimaryKeysW( MSIHANDLE hdb,
932 LPCWSTR table, MSIHANDLE* phRec )
934 MSIRECORD *rec = NULL;
935 MSIDATABASE *db;
936 UINT r;
938 TRACE("%d %s %p\n", hdb, debugstr_w(table), phRec);
940 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
941 if( !db )
943 HRESULT hr;
944 IWineMsiRemoteDatabase *remote_database;
946 remote_database = (IWineMsiRemoteDatabase *)msi_get_remote( hdb );
947 if ( !remote_database )
948 return ERROR_INVALID_HANDLE;
950 hr = IWineMsiRemoteDatabase_GetPrimaryKeys( remote_database, table, phRec );
951 IWineMsiRemoteDatabase_Release( remote_database );
953 if (FAILED(hr))
955 if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
956 return HRESULT_CODE(hr);
958 return ERROR_FUNCTION_FAILED;
961 return ERROR_SUCCESS;
964 r = MSI_DatabaseGetPrimaryKeys( db, table, &rec );
965 if( r == ERROR_SUCCESS )
967 *phRec = alloc_msihandle( &rec->hdr );
968 if (! *phRec)
969 r = ERROR_NOT_ENOUGH_MEMORY;
970 msiobj_release( &rec->hdr );
972 msiobj_release( &db->hdr );
974 return r;
977 UINT WINAPI MsiDatabaseGetPrimaryKeysA(MSIHANDLE hdb,
978 LPCSTR table, MSIHANDLE* phRec)
980 LPWSTR szwTable = NULL;
981 UINT r;
983 TRACE("%d %s %p\n", hdb, debugstr_a(table), phRec);
985 if( table )
987 szwTable = strdupAtoW( table );
988 if( !szwTable )
989 return ERROR_OUTOFMEMORY;
991 r = MsiDatabaseGetPrimaryKeysW( hdb, szwTable, phRec );
992 msi_free( szwTable );
994 return r;
997 MSICONDITION WINAPI MsiDatabaseIsTablePersistentA(
998 MSIHANDLE hDatabase, LPCSTR szTableName)
1000 LPWSTR szwTableName = NULL;
1001 MSICONDITION r;
1003 TRACE("%x %s\n", hDatabase, debugstr_a(szTableName));
1005 if( szTableName )
1007 szwTableName = strdupAtoW( szTableName );
1008 if( !szwTableName )
1009 return MSICONDITION_ERROR;
1011 r = MsiDatabaseIsTablePersistentW( hDatabase, szwTableName );
1012 msi_free( szwTableName );
1014 return r;
1017 MSICONDITION WINAPI MsiDatabaseIsTablePersistentW(
1018 MSIHANDLE hDatabase, LPCWSTR szTableName)
1020 MSIDATABASE *db;
1021 MSICONDITION r;
1023 TRACE("%x %s\n", hDatabase, debugstr_w(szTableName));
1025 db = msihandle2msiinfo( hDatabase, MSIHANDLETYPE_DATABASE );
1026 if( !db )
1028 HRESULT hr;
1029 MSICONDITION condition;
1030 IWineMsiRemoteDatabase *remote_database;
1032 remote_database = (IWineMsiRemoteDatabase *)msi_get_remote( hDatabase );
1033 if ( !remote_database )
1034 return MSICONDITION_ERROR;
1036 hr = IWineMsiRemoteDatabase_IsTablePersistent( remote_database,
1037 szTableName, &condition );
1038 IWineMsiRemoteDatabase_Release( remote_database );
1040 if (FAILED(hr))
1041 return MSICONDITION_ERROR;
1043 return condition;
1046 r = MSI_DatabaseIsTablePersistent( db, szTableName );
1048 msiobj_release( &db->hdr );
1050 return r;