mstask: Implement ITask::DeleteTrigger().
[wine.git] / dlls / msi / msiquery.c
blob42ee8c79d025902ccd19db5b7a42553bb4cc6467
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 "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 = 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 /* 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 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 = vsnprintfW(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 *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 = vsnprintfW(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 ret = remote_DatabaseOpenView(remote, szQuery, &remote_view);
262 if (!ret)
263 *phView = alloc_msi_remote_handle(remote_view);
264 return ret;
267 ret = MSI_DatabaseOpenViewW( db, szQuery, &query );
268 if( ret == ERROR_SUCCESS )
270 *phView = alloc_msihandle( &query->hdr );
271 if (! *phView)
272 ret = ERROR_NOT_ENOUGH_MEMORY;
273 msiobj_release( &query->hdr );
275 msiobj_release( &db->hdr );
277 return ret;
280 UINT msi_view_get_row(MSIDATABASE *db, MSIVIEW *view, UINT row, MSIRECORD **rec)
282 UINT row_count = 0, col_count = 0, i, ival, ret, type;
284 TRACE("%p %p %d %p\n", db, view, row, rec);
286 ret = view->ops->get_dimensions(view, &row_count, &col_count);
287 if (ret)
288 return ret;
290 if (!col_count)
291 return ERROR_INVALID_PARAMETER;
293 if (row >= row_count)
294 return ERROR_NO_MORE_ITEMS;
296 *rec = MSI_CreateRecord(col_count);
297 if (!*rec)
298 return ERROR_FUNCTION_FAILED;
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 /* check if it's nul (0) - if so, don't set anything */
336 if (!ival)
337 continue;
339 if (type & MSITYPE_STRING)
341 int len;
342 const WCHAR *sval = msi_string_lookup( db->strings, ival, &len );
343 msi_record_set_string( *rec, i, sval, len );
345 else
347 if ((type & MSI_DATASIZEMASK) == 2)
348 MSI_RecordSetInteger(*rec, i, ival - (1<<15));
349 else
350 MSI_RecordSetInteger(*rec, i, ival - (1u<<31));
354 return ERROR_SUCCESS;
357 UINT MSI_ViewFetch(MSIQUERY *query, MSIRECORD **prec)
359 MSIVIEW *view;
360 UINT r;
362 TRACE("%p %p\n", query, prec );
364 view = query->view;
365 if( !view )
366 return ERROR_FUNCTION_FAILED;
368 r = msi_view_get_row(query->db, view, query->row, prec);
369 if (r == ERROR_SUCCESS)
371 query->row ++;
372 (*prec)->query = query;
373 MSI_RecordSetInteger(*prec, 0, 1);
376 return r;
379 UINT WINAPI MsiViewFetch(MSIHANDLE hView, MSIHANDLE *record)
381 MSIQUERY *query;
382 MSIRECORD *rec = NULL;
383 UINT ret;
385 TRACE("%d %p\n", hView, record);
387 if( !record )
388 return ERROR_INVALID_PARAMETER;
389 *record = 0;
391 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
392 if (!query)
394 struct wire_record *wire_rec = NULL;
395 MSIHANDLE remote;
397 if (!(remote = msi_get_remote(hView)))
398 return ERROR_INVALID_HANDLE;
400 ret = remote_ViewFetch(remote, &wire_rec);
401 if (!ret)
403 ret = unmarshal_record(wire_rec, record);
404 free_remote_record(wire_rec);
406 return ret;
408 ret = MSI_ViewFetch( query, &rec );
409 if( ret == ERROR_SUCCESS )
411 *record = alloc_msihandle( &rec->hdr );
412 if (! *record)
413 ret = ERROR_NOT_ENOUGH_MEMORY;
414 msiobj_release( &rec->hdr );
416 msiobj_release( &query->hdr );
417 return ret;
420 UINT MSI_ViewClose(MSIQUERY *query)
422 MSIVIEW *view;
424 TRACE("%p\n", query );
426 view = query->view;
427 if( !view )
428 return ERROR_FUNCTION_FAILED;
429 if( !view->ops->close )
430 return ERROR_FUNCTION_FAILED;
432 return view->ops->close( view );
435 UINT WINAPI MsiViewClose(MSIHANDLE hView)
437 MSIQUERY *query;
438 UINT ret;
440 TRACE("%d\n", hView );
442 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
443 if (!query)
445 MSIHANDLE remote;
447 if (!(remote = msi_get_remote(hView)))
448 return ERROR_INVALID_HANDLE;
450 return remote_ViewClose(remote);
453 ret = MSI_ViewClose( query );
454 msiobj_release( &query->hdr );
455 return ret;
458 UINT MSI_ViewExecute(MSIQUERY *query, MSIRECORD *rec )
460 MSIVIEW *view;
462 TRACE("%p %p\n", query, rec);
464 view = query->view;
465 if( !view )
466 return ERROR_FUNCTION_FAILED;
467 if( !view->ops->execute )
468 return ERROR_FUNCTION_FAILED;
469 query->row = 0;
471 return view->ops->execute( view, rec );
474 UINT WINAPI MsiViewExecute(MSIHANDLE hView, MSIHANDLE hRec)
476 MSIQUERY *query;
477 MSIRECORD *rec = NULL;
478 UINT ret;
480 TRACE("%d %d\n", hView, hRec);
482 if( hRec )
484 rec = msihandle2msiinfo( hRec, MSIHANDLETYPE_RECORD );
485 if( !rec )
486 return ERROR_INVALID_HANDLE;
489 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
490 if( !query )
492 MSIHANDLE remote;
494 if (!(remote = msi_get_remote(hView)))
495 return ERROR_INVALID_HANDLE;
497 ret = remote_ViewExecute(remote, rec ? (struct wire_record *)&rec->count : NULL);
499 if (rec)
500 msiobj_release(&rec->hdr);
501 return ret;
504 msiobj_lock( &rec->hdr );
505 ret = MSI_ViewExecute( query, rec );
506 msiobj_unlock( &rec->hdr );
508 msiobj_release( &query->hdr );
509 if( rec )
510 msiobj_release( &rec->hdr );
512 return ret;
515 static UINT msi_set_record_type_string( MSIRECORD *rec, UINT field,
516 UINT type, BOOL temporary )
518 static const WCHAR fmt[] = { '%','d',0 };
519 WCHAR szType[0x10];
521 if (MSITYPE_IS_BINARY(type))
522 szType[0] = 'v';
523 else if (type & MSITYPE_LOCALIZABLE)
524 szType[0] = 'l';
525 else if (type & MSITYPE_UNKNOWN)
526 szType[0] = 'f';
527 else if (type & MSITYPE_STRING)
529 if (temporary)
530 szType[0] = 'g';
531 else
532 szType[0] = 's';
534 else
536 if (temporary)
537 szType[0] = 'j';
538 else
539 szType[0] = 'i';
542 if (type & MSITYPE_NULLABLE)
543 szType[0] &= ~0x20;
545 sprintfW( &szType[1], fmt, (type&0xff) );
547 TRACE("type %04x -> %s\n", type, debugstr_w(szType) );
549 return MSI_RecordSetStringW( rec, field, szType );
552 UINT MSI_ViewGetColumnInfo( MSIQUERY *query, MSICOLINFO info, MSIRECORD **prec )
554 UINT r = ERROR_FUNCTION_FAILED, i, count = 0, type;
555 MSIRECORD *rec;
556 MSIVIEW *view = query->view;
557 LPCWSTR name;
558 BOOL temporary;
560 if( !view )
561 return ERROR_FUNCTION_FAILED;
563 if( !view->ops->get_dimensions )
564 return ERROR_FUNCTION_FAILED;
566 r = view->ops->get_dimensions( view, NULL, &count );
567 if( r != ERROR_SUCCESS )
568 return r;
569 if( !count )
570 return ERROR_INVALID_PARAMETER;
572 rec = MSI_CreateRecord( count );
573 if( !rec )
574 return ERROR_FUNCTION_FAILED;
576 for( i=0; i<count; i++ )
578 name = NULL;
579 r = view->ops->get_column_info( view, i+1, &name, &type, &temporary, NULL );
580 if( r != ERROR_SUCCESS )
581 continue;
582 if (info == MSICOLINFO_NAMES)
583 MSI_RecordSetStringW( rec, i+1, name );
584 else
585 msi_set_record_type_string( rec, i+1, type, temporary );
587 *prec = rec;
588 return ERROR_SUCCESS;
591 UINT WINAPI MsiViewGetColumnInfo(MSIHANDLE hView, MSICOLINFO info, MSIHANDLE *hRec)
593 MSIQUERY *query = NULL;
594 MSIRECORD *rec = NULL;
595 UINT r;
597 TRACE("%d %d %p\n", hView, info, hRec);
599 if( !hRec )
600 return ERROR_INVALID_PARAMETER;
602 if( info != MSICOLINFO_NAMES && info != MSICOLINFO_TYPES )
603 return ERROR_INVALID_PARAMETER;
605 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
606 if (!query)
608 struct wire_record *wire_rec = NULL;
609 MSIHANDLE remote;
611 if (!(remote = msi_get_remote(hView)))
612 return ERROR_INVALID_HANDLE;
614 r = remote_ViewGetColumnInfo(remote, info, &wire_rec);
615 if (!r)
617 r = unmarshal_record(wire_rec, hRec);
618 free_remote_record(wire_rec);
621 return r;
624 r = MSI_ViewGetColumnInfo( query, info, &rec );
625 if ( r == ERROR_SUCCESS )
627 *hRec = alloc_msihandle( &rec->hdr );
628 if ( !*hRec )
629 r = ERROR_NOT_ENOUGH_MEMORY;
630 msiobj_release( &rec->hdr );
633 msiobj_release( &query->hdr );
635 return r;
638 UINT MSI_ViewModify( MSIQUERY *query, MSIMODIFY mode, MSIRECORD *rec )
640 MSIVIEW *view = NULL;
641 UINT r;
643 if ( !query || !rec )
644 return ERROR_INVALID_HANDLE;
646 view = query->view;
647 if ( !view || !view->ops->modify)
648 return ERROR_FUNCTION_FAILED;
650 if ( mode == MSIMODIFY_UPDATE && rec->query != query )
651 return ERROR_FUNCTION_FAILED;
653 r = view->ops->modify( view, mode, rec, query->row );
654 if (mode == MSIMODIFY_DELETE && r == ERROR_SUCCESS)
655 query->row--;
657 return r;
660 UINT WINAPI MsiViewModify( MSIHANDLE hView, MSIMODIFY eModifyMode,
661 MSIHANDLE hRecord)
663 MSIQUERY *query = NULL;
664 MSIRECORD *rec = NULL;
665 UINT r = ERROR_FUNCTION_FAILED;
667 TRACE("%d %x %d\n", hView, eModifyMode, hRecord);
669 rec = msihandle2msiinfo( hRecord, MSIHANDLETYPE_RECORD );
671 if (!rec)
672 return ERROR_INVALID_HANDLE;
674 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
675 if (!query)
677 struct wire_record *wire_refreshed = NULL;
678 MSIHANDLE remote;
680 if (!(remote = msi_get_remote(hView)))
681 return ERROR_INVALID_HANDLE;
683 r = remote_ViewModify(remote, eModifyMode,
684 (struct wire_record *)&rec->count, &wire_refreshed);
685 if (!r && (eModifyMode == MSIMODIFY_REFRESH || eModifyMode == MSIMODIFY_SEEK))
687 r = copy_remote_record(wire_refreshed, hRecord);
688 free_remote_record(wire_refreshed);
691 msiobj_release(&rec->hdr);
692 return r;
695 r = MSI_ViewModify( query, eModifyMode, rec );
697 msiobj_release( &query->hdr );
698 msiobj_release(&rec->hdr);
699 return r;
702 MSIDBERROR WINAPI MsiViewGetErrorW( MSIHANDLE handle, LPWSTR buffer, LPDWORD buflen )
704 MSIQUERY *query;
705 const WCHAR *column;
706 MSIDBERROR r;
707 DWORD len;
709 TRACE("%u %p %p\n", handle, buffer, buflen);
711 if (!buflen)
712 return MSIDBERROR_INVALIDARG;
714 query = msihandle2msiinfo( handle, MSIHANDLETYPE_VIEW );
715 if( !query )
716 return MSIDBERROR_INVALIDARG;
718 if ((r = query->view->error)) column = query->view->error_column;
719 else column = szEmpty;
721 len = strlenW( column );
722 if (buffer)
724 if (*buflen > len)
725 strcpyW( buffer, column );
726 else
727 r = MSIDBERROR_MOREDATA;
729 *buflen = len;
730 msiobj_release( &query->hdr );
731 return r;
734 MSIDBERROR WINAPI MsiViewGetErrorA( MSIHANDLE handle, LPSTR buffer, LPDWORD buflen )
736 MSIQUERY *query;
737 const WCHAR *column;
738 MSIDBERROR r;
739 DWORD len;
741 TRACE("%u %p %p\n", handle, buffer, buflen);
743 if (!buflen)
744 return MSIDBERROR_INVALIDARG;
746 query = msihandle2msiinfo( handle, MSIHANDLETYPE_VIEW );
747 if (!query)
748 return MSIDBERROR_INVALIDARG;
750 if ((r = query->view->error)) column = query->view->error_column;
751 else column = szEmpty;
753 len = WideCharToMultiByte( CP_ACP, 0, column, -1, NULL, 0, NULL, NULL );
754 if (buffer)
756 if (*buflen >= len)
757 WideCharToMultiByte( CP_ACP, 0, column, -1, buffer, *buflen, NULL, NULL );
758 else
759 r = MSIDBERROR_MOREDATA;
761 *buflen = len - 1;
762 msiobj_release( &query->hdr );
763 return r;
766 MSIHANDLE WINAPI MsiGetLastErrorRecord( void )
768 FIXME("\n");
769 return 0;
772 UINT MSI_DatabaseApplyTransformW( MSIDATABASE *db,
773 LPCWSTR szTransformFile, int iErrorCond )
775 HRESULT r;
776 UINT ret = ERROR_FUNCTION_FAILED;
777 IStorage *stg = NULL;
778 STATSTG stat;
780 TRACE("%p %s %d\n", db, debugstr_w(szTransformFile), iErrorCond);
782 r = StgOpenStorage( szTransformFile, NULL,
783 STGM_DIRECT|STGM_READ|STGM_SHARE_DENY_WRITE, NULL, 0, &stg);
784 if ( FAILED(r) )
786 WARN("failed to open transform 0x%08x\n", r);
787 return ret;
790 r = IStorage_Stat( stg, &stat, STATFLAG_NONAME );
791 if ( FAILED( r ) )
792 goto end;
794 if ( !IsEqualGUID( &stat.clsid, &CLSID_MsiTransform ) )
795 goto end;
797 if( TRACE_ON( msi ) )
798 enum_stream_names( stg );
800 ret = msi_table_apply_transform( db, stg );
802 end:
803 IStorage_Release( stg );
805 return ret;
808 UINT WINAPI MsiDatabaseApplyTransformW( MSIHANDLE hdb,
809 LPCWSTR szTransformFile, int iErrorCond)
811 MSIDATABASE *db;
812 UINT r;
814 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
815 if( !db )
817 MSIHANDLE remote;
819 if (!(remote = msi_get_remote(hdb)))
820 return ERROR_INVALID_HANDLE;
822 WARN("MsiDatabaseApplyTransform not allowed during a custom action!\n");
824 return ERROR_SUCCESS;
827 r = MSI_DatabaseApplyTransformW( db, szTransformFile, iErrorCond );
828 msiobj_release( &db->hdr );
829 return r;
832 UINT WINAPI MsiDatabaseApplyTransformA( MSIHANDLE hdb,
833 LPCSTR szTransformFile, int iErrorCond)
835 LPWSTR wstr;
836 UINT ret;
838 TRACE("%d %s %d\n", hdb, debugstr_a(szTransformFile), iErrorCond);
840 wstr = strdupAtoW( szTransformFile );
841 if( szTransformFile && !wstr )
842 return ERROR_NOT_ENOUGH_MEMORY;
844 ret = MsiDatabaseApplyTransformW( hdb, wstr, iErrorCond);
846 msi_free( wstr );
848 return ret;
851 UINT WINAPI MsiDatabaseGenerateTransformA( MSIHANDLE hdb, MSIHANDLE hdbref,
852 LPCSTR szTransformFile, int iReserved1, int iReserved2 )
854 FIXME("%d %d %s %d %d\n", hdb, hdbref,
855 debugstr_a(szTransformFile), iReserved1, iReserved2);
856 return ERROR_CALL_NOT_IMPLEMENTED;
859 UINT WINAPI MsiDatabaseGenerateTransformW( MSIHANDLE hdb, MSIHANDLE hdbref,
860 LPCWSTR szTransformFile, int iReserved1, int iReserved2 )
862 FIXME("%d %d %s %d %d\n", hdb, hdbref,
863 debugstr_w(szTransformFile), iReserved1, iReserved2);
864 return ERROR_CALL_NOT_IMPLEMENTED;
867 UINT WINAPI MsiDatabaseCommit( MSIHANDLE hdb )
869 MSIDATABASE *db;
870 UINT r;
872 TRACE("%d\n", hdb);
874 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
875 if( !db )
877 MSIHANDLE remote;
879 if (!(remote = msi_get_remote(hdb)))
880 return ERROR_INVALID_HANDLE;
882 WARN("not allowed during a custom action!\n");
884 return ERROR_SUCCESS;
887 if (db->mode == MSIDBOPEN_READONLY)
889 msiobj_release( &db->hdr );
890 return ERROR_SUCCESS;
893 /* FIXME: lock the database */
895 r = msi_commit_streams( db );
896 if (r != ERROR_SUCCESS) ERR("Failed to commit streams!\n");
897 else
899 r = MSI_CommitTables( db );
900 if (r != ERROR_SUCCESS) ERR("Failed to commit tables!\n");
903 /* FIXME: unlock the database */
905 msiobj_release( &db->hdr );
907 if (r == ERROR_SUCCESS)
909 msi_free( db->deletefile );
910 db->deletefile = NULL;
913 return r;
916 struct msi_primary_key_record_info
918 DWORD n;
919 MSIRECORD *rec;
922 static UINT msi_primary_key_iterator( MSIRECORD *rec, LPVOID param )
924 struct msi_primary_key_record_info *info = param;
925 LPCWSTR name, table;
926 DWORD type;
928 type = MSI_RecordGetInteger( rec, 4 );
929 if( type & MSITYPE_KEY )
931 info->n++;
932 if( info->rec )
934 if ( info->n == 1 )
936 table = MSI_RecordGetString( rec, 1 );
937 MSI_RecordSetStringW( info->rec, 0, table);
940 name = MSI_RecordGetString( rec, 3 );
941 MSI_RecordSetStringW( info->rec, info->n, name );
945 return ERROR_SUCCESS;
948 UINT MSI_DatabaseGetPrimaryKeys( MSIDATABASE *db,
949 LPCWSTR table, MSIRECORD **prec )
951 static const WCHAR sql[] = {
952 's','e','l','e','c','t',' ','*',' ',
953 'f','r','o','m',' ','`','_','C','o','l','u','m','n','s','`',' ',
954 'w','h','e','r','e',' ',
955 '`','T','a','b','l','e','`',' ','=',' ','\'','%','s','\'',0 };
956 struct msi_primary_key_record_info info;
957 MSIQUERY *query = NULL;
958 UINT r;
960 if (!TABLE_Exists( db, table ))
961 return ERROR_INVALID_TABLE;
963 r = MSI_OpenQuery( db, &query, sql, table );
964 if( r != ERROR_SUCCESS )
965 return r;
967 /* count the number of primary key records */
968 info.n = 0;
969 info.rec = 0;
970 r = MSI_IterateRecords( query, 0, msi_primary_key_iterator, &info );
971 if( r == ERROR_SUCCESS )
973 TRACE("Found %d primary keys\n", info.n );
975 /* allocate a record and fill in the names of the tables */
976 info.rec = MSI_CreateRecord( info.n );
977 info.n = 0;
978 r = MSI_IterateRecords( query, 0, msi_primary_key_iterator, &info );
979 if( r == ERROR_SUCCESS )
980 *prec = info.rec;
981 else
982 msiobj_release( &info.rec->hdr );
984 msiobj_release( &query->hdr );
986 return r;
989 UINT WINAPI MsiDatabaseGetPrimaryKeysW( MSIHANDLE hdb,
990 LPCWSTR table, MSIHANDLE* phRec )
992 MSIRECORD *rec = NULL;
993 MSIDATABASE *db;
994 UINT r;
996 TRACE("%d %s %p\n", hdb, debugstr_w(table), phRec);
998 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
999 if( !db )
1001 struct wire_record *wire_rec = NULL;
1002 MSIHANDLE remote;
1004 if (!(remote = msi_get_remote(hdb)))
1005 return ERROR_INVALID_HANDLE;
1007 r = remote_DatabaseGetPrimaryKeys(remote, table, &wire_rec);
1008 if (!r)
1010 r = unmarshal_record(wire_rec, phRec);
1011 free_remote_record(wire_rec);
1014 return r;
1017 r = MSI_DatabaseGetPrimaryKeys( db, table, &rec );
1018 if( r == ERROR_SUCCESS )
1020 *phRec = alloc_msihandle( &rec->hdr );
1021 if (! *phRec)
1022 r = ERROR_NOT_ENOUGH_MEMORY;
1023 msiobj_release( &rec->hdr );
1025 msiobj_release( &db->hdr );
1027 return r;
1030 UINT WINAPI MsiDatabaseGetPrimaryKeysA(MSIHANDLE hdb,
1031 LPCSTR table, MSIHANDLE* phRec)
1033 LPWSTR szwTable = NULL;
1034 UINT r;
1036 TRACE("%d %s %p\n", hdb, debugstr_a(table), phRec);
1038 if( table )
1040 szwTable = strdupAtoW( table );
1041 if( !szwTable )
1042 return ERROR_OUTOFMEMORY;
1044 r = MsiDatabaseGetPrimaryKeysW( hdb, szwTable, phRec );
1045 msi_free( szwTable );
1047 return r;
1050 MSICONDITION WINAPI MsiDatabaseIsTablePersistentA(
1051 MSIHANDLE hDatabase, LPCSTR szTableName)
1053 LPWSTR szwTableName = NULL;
1054 MSICONDITION r;
1056 TRACE("%x %s\n", hDatabase, debugstr_a(szTableName));
1058 if( szTableName )
1060 szwTableName = strdupAtoW( szTableName );
1061 if( !szwTableName )
1062 return MSICONDITION_ERROR;
1064 r = MsiDatabaseIsTablePersistentW( hDatabase, szwTableName );
1065 msi_free( szwTableName );
1067 return r;
1070 MSICONDITION WINAPI MsiDatabaseIsTablePersistentW(
1071 MSIHANDLE hDatabase, LPCWSTR szTableName)
1073 MSIDATABASE *db;
1074 MSICONDITION r;
1076 TRACE("%x %s\n", hDatabase, debugstr_w(szTableName));
1078 db = msihandle2msiinfo( hDatabase, MSIHANDLETYPE_DATABASE );
1079 if( !db )
1081 MSIHANDLE remote;
1083 if (!(remote = msi_get_remote(hDatabase)))
1084 return MSICONDITION_ERROR;
1086 return remote_DatabaseIsTablePersistent(remote, szTableName);
1089 r = MSI_DatabaseIsTablePersistent( db, szTableName );
1091 msiobj_release( &db->hdr );
1093 return r;
1096 UINT __cdecl remote_ViewClose(MSIHANDLE view)
1098 return MsiViewClose(view);
1101 UINT __cdecl remote_ViewExecute(MSIHANDLE view, struct wire_record *remote_rec)
1103 MSIHANDLE rec = 0;
1104 UINT r;
1106 if ((r = unmarshal_record(remote_rec, &rec)))
1107 return r;
1109 r = MsiViewExecute(view, rec);
1111 MsiCloseHandle(rec);
1112 return r;
1115 UINT __cdecl remote_ViewFetch(MSIHANDLE view, struct wire_record **rec)
1117 MSIHANDLE handle;
1118 UINT r = MsiViewFetch(view, &handle);
1119 *rec = NULL;
1120 if (!r)
1121 *rec = marshal_record(handle);
1122 MsiCloseHandle(handle);
1123 return r;
1126 UINT __cdecl remote_ViewGetColumnInfo(MSIHANDLE view, MSICOLINFO info, struct wire_record **rec)
1128 MSIHANDLE handle;
1129 UINT r = MsiViewGetColumnInfo(view, info, &handle);
1130 *rec = NULL;
1131 if (!r)
1132 *rec = marshal_record(handle);
1133 MsiCloseHandle(handle);
1134 return r;
1137 UINT __cdecl remote_ViewModify(MSIHANDLE view, MSIMODIFY mode,
1138 struct wire_record *remote_rec, struct wire_record **remote_refreshed)
1140 MSIHANDLE handle = 0;
1141 UINT r;
1143 if ((r = unmarshal_record(remote_rec, &handle)))
1144 return r;
1146 r = MsiViewModify(view, mode, handle);
1147 *remote_refreshed = NULL;
1148 if (!r && (mode == MSIMODIFY_REFRESH || mode == MSIMODIFY_SEEK))
1149 *remote_refreshed = marshal_record(handle);
1151 MsiCloseHandle(handle);
1152 return r;