msi: Make MsiViewGetColumnInfo() RPC-compatible.
[wine.git] / dlls / msi / msiquery.c
blobe73701f9253624bbd4a44c26b9cb40a4746b46f5
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 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
670 if( !query )
671 return ERROR_INVALID_HANDLE;
673 rec = msihandle2msiinfo( hRecord, MSIHANDLETYPE_RECORD );
674 r = MSI_ViewModify( query, eModifyMode, rec );
676 msiobj_release( &query->hdr );
677 if( rec )
678 msiobj_release( &rec->hdr );
680 return r;
683 MSIDBERROR WINAPI MsiViewGetErrorW( MSIHANDLE handle, LPWSTR buffer, LPDWORD buflen )
685 MSIQUERY *query;
686 const WCHAR *column;
687 MSIDBERROR r;
688 DWORD len;
690 TRACE("%u %p %p\n", handle, buffer, buflen);
692 if (!buflen)
693 return MSIDBERROR_INVALIDARG;
695 query = msihandle2msiinfo( handle, MSIHANDLETYPE_VIEW );
696 if( !query )
697 return MSIDBERROR_INVALIDARG;
699 if ((r = query->view->error)) column = query->view->error_column;
700 else column = szEmpty;
702 len = strlenW( column );
703 if (buffer)
705 if (*buflen > len)
706 strcpyW( buffer, column );
707 else
708 r = MSIDBERROR_MOREDATA;
710 *buflen = len;
711 msiobj_release( &query->hdr );
712 return r;
715 MSIDBERROR WINAPI MsiViewGetErrorA( MSIHANDLE handle, LPSTR buffer, LPDWORD buflen )
717 MSIQUERY *query;
718 const WCHAR *column;
719 MSIDBERROR r;
720 DWORD len;
722 TRACE("%u %p %p\n", handle, buffer, buflen);
724 if (!buflen)
725 return MSIDBERROR_INVALIDARG;
727 query = msihandle2msiinfo( handle, MSIHANDLETYPE_VIEW );
728 if (!query)
729 return MSIDBERROR_INVALIDARG;
731 if ((r = query->view->error)) column = query->view->error_column;
732 else column = szEmpty;
734 len = WideCharToMultiByte( CP_ACP, 0, column, -1, NULL, 0, NULL, NULL );
735 if (buffer)
737 if (*buflen >= len)
738 WideCharToMultiByte( CP_ACP, 0, column, -1, buffer, *buflen, NULL, NULL );
739 else
740 r = MSIDBERROR_MOREDATA;
742 *buflen = len - 1;
743 msiobj_release( &query->hdr );
744 return r;
747 MSIHANDLE WINAPI MsiGetLastErrorRecord( void )
749 FIXME("\n");
750 return 0;
753 UINT MSI_DatabaseApplyTransformW( MSIDATABASE *db,
754 LPCWSTR szTransformFile, int iErrorCond )
756 HRESULT r;
757 UINT ret = ERROR_FUNCTION_FAILED;
758 IStorage *stg = NULL;
759 STATSTG stat;
761 TRACE("%p %s %d\n", db, debugstr_w(szTransformFile), iErrorCond);
763 r = StgOpenStorage( szTransformFile, NULL,
764 STGM_DIRECT|STGM_READ|STGM_SHARE_DENY_WRITE, NULL, 0, &stg);
765 if ( FAILED(r) )
767 WARN("failed to open transform 0x%08x\n", r);
768 return ret;
771 r = IStorage_Stat( stg, &stat, STATFLAG_NONAME );
772 if ( FAILED( r ) )
773 goto end;
775 if ( !IsEqualGUID( &stat.clsid, &CLSID_MsiTransform ) )
776 goto end;
778 if( TRACE_ON( msi ) )
779 enum_stream_names( stg );
781 ret = msi_table_apply_transform( db, stg );
783 end:
784 IStorage_Release( stg );
786 return ret;
789 UINT WINAPI MsiDatabaseApplyTransformW( MSIHANDLE hdb,
790 LPCWSTR szTransformFile, int iErrorCond)
792 MSIDATABASE *db;
793 UINT r;
795 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
796 if( !db )
798 MSIHANDLE remote;
800 if (!(remote = msi_get_remote(hdb)))
801 return ERROR_INVALID_HANDLE;
803 WARN("MsiDatabaseApplyTransform not allowed during a custom action!\n");
805 return ERROR_SUCCESS;
808 r = MSI_DatabaseApplyTransformW( db, szTransformFile, iErrorCond );
809 msiobj_release( &db->hdr );
810 return r;
813 UINT WINAPI MsiDatabaseApplyTransformA( MSIHANDLE hdb,
814 LPCSTR szTransformFile, int iErrorCond)
816 LPWSTR wstr;
817 UINT ret;
819 TRACE("%d %s %d\n", hdb, debugstr_a(szTransformFile), iErrorCond);
821 wstr = strdupAtoW( szTransformFile );
822 if( szTransformFile && !wstr )
823 return ERROR_NOT_ENOUGH_MEMORY;
825 ret = MsiDatabaseApplyTransformW( hdb, wstr, iErrorCond);
827 msi_free( wstr );
829 return ret;
832 UINT WINAPI MsiDatabaseGenerateTransformA( MSIHANDLE hdb, MSIHANDLE hdbref,
833 LPCSTR szTransformFile, int iReserved1, int iReserved2 )
835 FIXME("%d %d %s %d %d\n", hdb, hdbref,
836 debugstr_a(szTransformFile), iReserved1, iReserved2);
837 return ERROR_CALL_NOT_IMPLEMENTED;
840 UINT WINAPI MsiDatabaseGenerateTransformW( MSIHANDLE hdb, MSIHANDLE hdbref,
841 LPCWSTR szTransformFile, int iReserved1, int iReserved2 )
843 FIXME("%d %d %s %d %d\n", hdb, hdbref,
844 debugstr_w(szTransformFile), iReserved1, iReserved2);
845 return ERROR_CALL_NOT_IMPLEMENTED;
848 UINT WINAPI MsiDatabaseCommit( MSIHANDLE hdb )
850 MSIDATABASE *db;
851 UINT r;
853 TRACE("%d\n", hdb);
855 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
856 if( !db )
858 MSIHANDLE remote;
860 if (!(remote = msi_get_remote(hdb)))
861 return ERROR_INVALID_HANDLE;
863 WARN("not allowed during a custom action!\n");
865 return ERROR_SUCCESS;
868 if (db->mode == MSIDBOPEN_READONLY)
870 msiobj_release( &db->hdr );
871 return ERROR_SUCCESS;
874 /* FIXME: lock the database */
876 r = msi_commit_streams( db );
877 if (r != ERROR_SUCCESS) ERR("Failed to commit streams!\n");
878 else
880 r = MSI_CommitTables( db );
881 if (r != ERROR_SUCCESS) ERR("Failed to commit tables!\n");
884 /* FIXME: unlock the database */
886 msiobj_release( &db->hdr );
888 if (r == ERROR_SUCCESS)
890 msi_free( db->deletefile );
891 db->deletefile = NULL;
894 return r;
897 struct msi_primary_key_record_info
899 DWORD n;
900 MSIRECORD *rec;
903 static UINT msi_primary_key_iterator( MSIRECORD *rec, LPVOID param )
905 struct msi_primary_key_record_info *info = param;
906 LPCWSTR name, table;
907 DWORD type;
909 type = MSI_RecordGetInteger( rec, 4 );
910 if( type & MSITYPE_KEY )
912 info->n++;
913 if( info->rec )
915 if ( info->n == 1 )
917 table = MSI_RecordGetString( rec, 1 );
918 MSI_RecordSetStringW( info->rec, 0, table);
921 name = MSI_RecordGetString( rec, 3 );
922 MSI_RecordSetStringW( info->rec, info->n, name );
926 return ERROR_SUCCESS;
929 UINT MSI_DatabaseGetPrimaryKeys( MSIDATABASE *db,
930 LPCWSTR table, MSIRECORD **prec )
932 static const WCHAR sql[] = {
933 's','e','l','e','c','t',' ','*',' ',
934 'f','r','o','m',' ','`','_','C','o','l','u','m','n','s','`',' ',
935 'w','h','e','r','e',' ',
936 '`','T','a','b','l','e','`',' ','=',' ','\'','%','s','\'',0 };
937 struct msi_primary_key_record_info info;
938 MSIQUERY *query = NULL;
939 UINT r;
941 if (!TABLE_Exists( db, table ))
942 return ERROR_INVALID_TABLE;
944 r = MSI_OpenQuery( db, &query, sql, table );
945 if( r != ERROR_SUCCESS )
946 return r;
948 /* count the number of primary key records */
949 info.n = 0;
950 info.rec = 0;
951 r = MSI_IterateRecords( query, 0, msi_primary_key_iterator, &info );
952 if( r == ERROR_SUCCESS )
954 TRACE("Found %d primary keys\n", info.n );
956 /* allocate a record and fill in the names of the tables */
957 info.rec = MSI_CreateRecord( info.n );
958 info.n = 0;
959 r = MSI_IterateRecords( query, 0, msi_primary_key_iterator, &info );
960 if( r == ERROR_SUCCESS )
961 *prec = info.rec;
962 else
963 msiobj_release( &info.rec->hdr );
965 msiobj_release( &query->hdr );
967 return r;
970 UINT WINAPI MsiDatabaseGetPrimaryKeysW( MSIHANDLE hdb,
971 LPCWSTR table, MSIHANDLE* phRec )
973 MSIRECORD *rec = NULL;
974 MSIDATABASE *db;
975 UINT r;
977 TRACE("%d %s %p\n", hdb, debugstr_w(table), phRec);
979 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
980 if( !db )
982 MSIHANDLE remote;
983 HRESULT hr;
985 if (!(remote = msi_get_remote(hdb)))
986 return ERROR_INVALID_HANDLE;
988 hr = remote_DatabaseGetPrimaryKeys(remote, table, phRec);
990 if (FAILED(hr))
992 if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
993 return HRESULT_CODE(hr);
995 return ERROR_FUNCTION_FAILED;
998 return ERROR_SUCCESS;
1001 r = MSI_DatabaseGetPrimaryKeys( db, table, &rec );
1002 if( r == ERROR_SUCCESS )
1004 *phRec = alloc_msihandle( &rec->hdr );
1005 if (! *phRec)
1006 r = ERROR_NOT_ENOUGH_MEMORY;
1007 msiobj_release( &rec->hdr );
1009 msiobj_release( &db->hdr );
1011 return r;
1014 UINT WINAPI MsiDatabaseGetPrimaryKeysA(MSIHANDLE hdb,
1015 LPCSTR table, MSIHANDLE* phRec)
1017 LPWSTR szwTable = NULL;
1018 UINT r;
1020 TRACE("%d %s %p\n", hdb, debugstr_a(table), phRec);
1022 if( table )
1024 szwTable = strdupAtoW( table );
1025 if( !szwTable )
1026 return ERROR_OUTOFMEMORY;
1028 r = MsiDatabaseGetPrimaryKeysW( hdb, szwTable, phRec );
1029 msi_free( szwTable );
1031 return r;
1034 MSICONDITION WINAPI MsiDatabaseIsTablePersistentA(
1035 MSIHANDLE hDatabase, LPCSTR szTableName)
1037 LPWSTR szwTableName = NULL;
1038 MSICONDITION r;
1040 TRACE("%x %s\n", hDatabase, debugstr_a(szTableName));
1042 if( szTableName )
1044 szwTableName = strdupAtoW( szTableName );
1045 if( !szwTableName )
1046 return MSICONDITION_ERROR;
1048 r = MsiDatabaseIsTablePersistentW( hDatabase, szwTableName );
1049 msi_free( szwTableName );
1051 return r;
1054 MSICONDITION WINAPI MsiDatabaseIsTablePersistentW(
1055 MSIHANDLE hDatabase, LPCWSTR szTableName)
1057 MSIDATABASE *db;
1058 MSICONDITION r;
1060 TRACE("%x %s\n", hDatabase, debugstr_w(szTableName));
1062 db = msihandle2msiinfo( hDatabase, MSIHANDLETYPE_DATABASE );
1063 if( !db )
1065 MSIHANDLE remote;
1067 if (!(remote = msi_get_remote(hDatabase)))
1068 return MSICONDITION_ERROR;
1070 return remote_DatabaseIsTablePersistent(remote, szTableName);
1073 r = MSI_DatabaseIsTablePersistent( db, szTableName );
1075 msiobj_release( &db->hdr );
1077 return r;
1080 UINT __cdecl remote_ViewClose(MSIHANDLE view)
1082 return MsiViewClose(view);
1085 UINT __cdecl remote_ViewExecute(MSIHANDLE view, struct wire_record *remote_rec)
1087 MSIHANDLE rec = 0;
1088 UINT r;
1090 if ((r = unmarshal_record(remote_rec, &rec)))
1091 return r;
1093 r = MsiViewExecute(view, rec);
1095 MsiCloseHandle(rec);
1096 return r;
1099 UINT __cdecl remote_ViewFetch(MSIHANDLE view, struct wire_record **rec)
1101 MSIHANDLE handle;
1102 UINT r = MsiViewFetch(view, &handle);
1103 *rec = NULL;
1104 if (!r)
1105 *rec = marshal_record(handle);
1106 MsiCloseHandle(handle);
1107 return r;
1110 UINT __cdecl remote_ViewGetColumnInfo(MSIHANDLE view, MSICOLINFO info, struct wire_record **rec)
1112 MSIHANDLE handle;
1113 UINT r = MsiViewGetColumnInfo(view, info, &handle);
1114 *rec = NULL;
1115 if (!r)
1116 *rec = marshal_record(handle);
1117 MsiCloseHandle(handle);
1118 return r;