msi: Make MsiDatabaseOpenView() RPC-compatible.
[wine.git] / dlls / msi / msiquery.c
blob9518c5958aeaa22a834df1d5b410bf434bdce128
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 )
393 return ERROR_INVALID_HANDLE;
394 ret = MSI_ViewFetch( query, &rec );
395 if( ret == ERROR_SUCCESS )
397 *record = alloc_msihandle( &rec->hdr );
398 if (! *record)
399 ret = ERROR_NOT_ENOUGH_MEMORY;
400 msiobj_release( &rec->hdr );
402 msiobj_release( &query->hdr );
403 return ret;
406 UINT MSI_ViewClose(MSIQUERY *query)
408 MSIVIEW *view;
410 TRACE("%p\n", query );
412 view = query->view;
413 if( !view )
414 return ERROR_FUNCTION_FAILED;
415 if( !view->ops->close )
416 return ERROR_FUNCTION_FAILED;
418 return view->ops->close( view );
421 UINT WINAPI MsiViewClose(MSIHANDLE hView)
423 MSIQUERY *query;
424 UINT ret;
426 TRACE("%d\n", hView );
428 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
429 if( !query )
430 return ERROR_INVALID_HANDLE;
432 ret = MSI_ViewClose( query );
433 msiobj_release( &query->hdr );
434 return ret;
437 UINT MSI_ViewExecute(MSIQUERY *query, MSIRECORD *rec )
439 MSIVIEW *view;
441 TRACE("%p %p\n", query, rec);
443 view = query->view;
444 if( !view )
445 return ERROR_FUNCTION_FAILED;
446 if( !view->ops->execute )
447 return ERROR_FUNCTION_FAILED;
448 query->row = 0;
450 return view->ops->execute( view, rec );
453 UINT WINAPI MsiViewExecute(MSIHANDLE hView, MSIHANDLE hRec)
455 MSIQUERY *query;
456 MSIRECORD *rec = NULL;
457 UINT ret;
459 TRACE("%d %d\n", hView, hRec);
461 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
462 if( !query )
463 return ERROR_INVALID_HANDLE;
465 if( hRec )
467 rec = msihandle2msiinfo( hRec, MSIHANDLETYPE_RECORD );
468 if( !rec )
470 ret = ERROR_INVALID_HANDLE;
471 goto out;
475 msiobj_lock( &rec->hdr );
476 ret = MSI_ViewExecute( query, rec );
477 msiobj_unlock( &rec->hdr );
479 out:
480 msiobj_release( &query->hdr );
481 if( rec )
482 msiobj_release( &rec->hdr );
484 return ret;
487 static UINT msi_set_record_type_string( MSIRECORD *rec, UINT field,
488 UINT type, BOOL temporary )
490 static const WCHAR fmt[] = { '%','d',0 };
491 WCHAR szType[0x10];
493 if (MSITYPE_IS_BINARY(type))
494 szType[0] = 'v';
495 else if (type & MSITYPE_LOCALIZABLE)
496 szType[0] = 'l';
497 else if (type & MSITYPE_UNKNOWN)
498 szType[0] = 'f';
499 else if (type & MSITYPE_STRING)
501 if (temporary)
502 szType[0] = 'g';
503 else
504 szType[0] = 's';
506 else
508 if (temporary)
509 szType[0] = 'j';
510 else
511 szType[0] = 'i';
514 if (type & MSITYPE_NULLABLE)
515 szType[0] &= ~0x20;
517 sprintfW( &szType[1], fmt, (type&0xff) );
519 TRACE("type %04x -> %s\n", type, debugstr_w(szType) );
521 return MSI_RecordSetStringW( rec, field, szType );
524 UINT MSI_ViewGetColumnInfo( MSIQUERY *query, MSICOLINFO info, MSIRECORD **prec )
526 UINT r = ERROR_FUNCTION_FAILED, i, count = 0, type;
527 MSIRECORD *rec;
528 MSIVIEW *view = query->view;
529 LPCWSTR name;
530 BOOL temporary;
532 if( !view )
533 return ERROR_FUNCTION_FAILED;
535 if( !view->ops->get_dimensions )
536 return ERROR_FUNCTION_FAILED;
538 r = view->ops->get_dimensions( view, NULL, &count );
539 if( r != ERROR_SUCCESS )
540 return r;
541 if( !count )
542 return ERROR_INVALID_PARAMETER;
544 rec = MSI_CreateRecord( count );
545 if( !rec )
546 return ERROR_FUNCTION_FAILED;
548 for( i=0; i<count; i++ )
550 name = NULL;
551 r = view->ops->get_column_info( view, i+1, &name, &type, &temporary, NULL );
552 if( r != ERROR_SUCCESS )
553 continue;
554 if (info == MSICOLINFO_NAMES)
555 MSI_RecordSetStringW( rec, i+1, name );
556 else
557 msi_set_record_type_string( rec, i+1, type, temporary );
559 *prec = rec;
560 return ERROR_SUCCESS;
563 UINT WINAPI MsiViewGetColumnInfo(MSIHANDLE hView, MSICOLINFO info, MSIHANDLE *hRec)
565 MSIQUERY *query = NULL;
566 MSIRECORD *rec = NULL;
567 UINT r;
569 TRACE("%d %d %p\n", hView, info, hRec);
571 if( !hRec )
572 return ERROR_INVALID_PARAMETER;
574 if( info != MSICOLINFO_NAMES && info != MSICOLINFO_TYPES )
575 return ERROR_INVALID_PARAMETER;
577 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
578 if( !query )
579 return ERROR_INVALID_HANDLE;
581 r = MSI_ViewGetColumnInfo( query, info, &rec );
582 if ( r == ERROR_SUCCESS )
584 *hRec = alloc_msihandle( &rec->hdr );
585 if ( !*hRec )
586 r = ERROR_NOT_ENOUGH_MEMORY;
587 msiobj_release( &rec->hdr );
590 msiobj_release( &query->hdr );
592 return r;
595 UINT MSI_ViewModify( MSIQUERY *query, MSIMODIFY mode, MSIRECORD *rec )
597 MSIVIEW *view = NULL;
598 UINT r;
600 if ( !query || !rec )
601 return ERROR_INVALID_HANDLE;
603 view = query->view;
604 if ( !view || !view->ops->modify)
605 return ERROR_FUNCTION_FAILED;
607 if ( mode == MSIMODIFY_UPDATE && rec->query != query )
608 return ERROR_FUNCTION_FAILED;
610 r = view->ops->modify( view, mode, rec, query->row );
611 if (mode == MSIMODIFY_DELETE && r == ERROR_SUCCESS)
612 query->row--;
614 return r;
617 UINT WINAPI MsiViewModify( MSIHANDLE hView, MSIMODIFY eModifyMode,
618 MSIHANDLE hRecord)
620 MSIQUERY *query = NULL;
621 MSIRECORD *rec = NULL;
622 UINT r = ERROR_FUNCTION_FAILED;
624 TRACE("%d %x %d\n", hView, eModifyMode, hRecord);
626 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
627 if( !query )
628 return ERROR_INVALID_HANDLE;
630 rec = msihandle2msiinfo( hRecord, MSIHANDLETYPE_RECORD );
631 r = MSI_ViewModify( query, eModifyMode, rec );
633 msiobj_release( &query->hdr );
634 if( rec )
635 msiobj_release( &rec->hdr );
637 return r;
640 MSIDBERROR WINAPI MsiViewGetErrorW( MSIHANDLE handle, LPWSTR buffer, LPDWORD buflen )
642 MSIQUERY *query;
643 const WCHAR *column;
644 MSIDBERROR r;
645 DWORD len;
647 TRACE("%u %p %p\n", handle, buffer, buflen);
649 if (!buflen)
650 return MSIDBERROR_INVALIDARG;
652 query = msihandle2msiinfo( handle, MSIHANDLETYPE_VIEW );
653 if( !query )
654 return MSIDBERROR_INVALIDARG;
656 if ((r = query->view->error)) column = query->view->error_column;
657 else column = szEmpty;
659 len = strlenW( column );
660 if (buffer)
662 if (*buflen > len)
663 strcpyW( buffer, column );
664 else
665 r = MSIDBERROR_MOREDATA;
667 *buflen = len;
668 msiobj_release( &query->hdr );
669 return r;
672 MSIDBERROR WINAPI MsiViewGetErrorA( MSIHANDLE handle, LPSTR buffer, LPDWORD buflen )
674 MSIQUERY *query;
675 const WCHAR *column;
676 MSIDBERROR r;
677 DWORD len;
679 TRACE("%u %p %p\n", handle, buffer, buflen);
681 if (!buflen)
682 return MSIDBERROR_INVALIDARG;
684 query = msihandle2msiinfo( handle, MSIHANDLETYPE_VIEW );
685 if (!query)
686 return MSIDBERROR_INVALIDARG;
688 if ((r = query->view->error)) column = query->view->error_column;
689 else column = szEmpty;
691 len = WideCharToMultiByte( CP_ACP, 0, column, -1, NULL, 0, NULL, NULL );
692 if (buffer)
694 if (*buflen >= len)
695 WideCharToMultiByte( CP_ACP, 0, column, -1, buffer, *buflen, NULL, NULL );
696 else
697 r = MSIDBERROR_MOREDATA;
699 *buflen = len - 1;
700 msiobj_release( &query->hdr );
701 return r;
704 MSIHANDLE WINAPI MsiGetLastErrorRecord( void )
706 FIXME("\n");
707 return 0;
710 UINT MSI_DatabaseApplyTransformW( MSIDATABASE *db,
711 LPCWSTR szTransformFile, int iErrorCond )
713 HRESULT r;
714 UINT ret = ERROR_FUNCTION_FAILED;
715 IStorage *stg = NULL;
716 STATSTG stat;
718 TRACE("%p %s %d\n", db, debugstr_w(szTransformFile), iErrorCond);
720 r = StgOpenStorage( szTransformFile, NULL,
721 STGM_DIRECT|STGM_READ|STGM_SHARE_DENY_WRITE, NULL, 0, &stg);
722 if ( FAILED(r) )
724 WARN("failed to open transform 0x%08x\n", r);
725 return ret;
728 r = IStorage_Stat( stg, &stat, STATFLAG_NONAME );
729 if ( FAILED( r ) )
730 goto end;
732 if ( !IsEqualGUID( &stat.clsid, &CLSID_MsiTransform ) )
733 goto end;
735 if( TRACE_ON( msi ) )
736 enum_stream_names( stg );
738 ret = msi_table_apply_transform( db, stg );
740 end:
741 IStorage_Release( stg );
743 return ret;
746 UINT WINAPI MsiDatabaseApplyTransformW( MSIHANDLE hdb,
747 LPCWSTR szTransformFile, int iErrorCond)
749 MSIDATABASE *db;
750 UINT r;
752 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
753 if( !db )
755 MSIHANDLE remote;
757 if (!(remote = msi_get_remote(hdb)))
758 return ERROR_INVALID_HANDLE;
760 WARN("MsiDatabaseApplyTransform not allowed during a custom action!\n");
762 return ERROR_SUCCESS;
765 r = MSI_DatabaseApplyTransformW( db, szTransformFile, iErrorCond );
766 msiobj_release( &db->hdr );
767 return r;
770 UINT WINAPI MsiDatabaseApplyTransformA( MSIHANDLE hdb,
771 LPCSTR szTransformFile, int iErrorCond)
773 LPWSTR wstr;
774 UINT ret;
776 TRACE("%d %s %d\n", hdb, debugstr_a(szTransformFile), iErrorCond);
778 wstr = strdupAtoW( szTransformFile );
779 if( szTransformFile && !wstr )
780 return ERROR_NOT_ENOUGH_MEMORY;
782 ret = MsiDatabaseApplyTransformW( hdb, wstr, iErrorCond);
784 msi_free( wstr );
786 return ret;
789 UINT WINAPI MsiDatabaseGenerateTransformA( MSIHANDLE hdb, MSIHANDLE hdbref,
790 LPCSTR szTransformFile, int iReserved1, int iReserved2 )
792 FIXME("%d %d %s %d %d\n", hdb, hdbref,
793 debugstr_a(szTransformFile), iReserved1, iReserved2);
794 return ERROR_CALL_NOT_IMPLEMENTED;
797 UINT WINAPI MsiDatabaseGenerateTransformW( MSIHANDLE hdb, MSIHANDLE hdbref,
798 LPCWSTR szTransformFile, int iReserved1, int iReserved2 )
800 FIXME("%d %d %s %d %d\n", hdb, hdbref,
801 debugstr_w(szTransformFile), iReserved1, iReserved2);
802 return ERROR_CALL_NOT_IMPLEMENTED;
805 UINT WINAPI MsiDatabaseCommit( MSIHANDLE hdb )
807 MSIDATABASE *db;
808 UINT r;
810 TRACE("%d\n", hdb);
812 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
813 if( !db )
815 MSIHANDLE remote;
817 if (!(remote = msi_get_remote(hdb)))
818 return ERROR_INVALID_HANDLE;
820 WARN("not allowed during a custom action!\n");
822 return ERROR_SUCCESS;
825 if (db->mode == MSIDBOPEN_READONLY)
827 msiobj_release( &db->hdr );
828 return ERROR_SUCCESS;
831 /* FIXME: lock the database */
833 r = msi_commit_streams( db );
834 if (r != ERROR_SUCCESS) ERR("Failed to commit streams!\n");
835 else
837 r = MSI_CommitTables( db );
838 if (r != ERROR_SUCCESS) ERR("Failed to commit tables!\n");
841 /* FIXME: unlock the database */
843 msiobj_release( &db->hdr );
845 if (r == ERROR_SUCCESS)
847 msi_free( db->deletefile );
848 db->deletefile = NULL;
851 return r;
854 struct msi_primary_key_record_info
856 DWORD n;
857 MSIRECORD *rec;
860 static UINT msi_primary_key_iterator( MSIRECORD *rec, LPVOID param )
862 struct msi_primary_key_record_info *info = param;
863 LPCWSTR name, table;
864 DWORD type;
866 type = MSI_RecordGetInteger( rec, 4 );
867 if( type & MSITYPE_KEY )
869 info->n++;
870 if( info->rec )
872 if ( info->n == 1 )
874 table = MSI_RecordGetString( rec, 1 );
875 MSI_RecordSetStringW( info->rec, 0, table);
878 name = MSI_RecordGetString( rec, 3 );
879 MSI_RecordSetStringW( info->rec, info->n, name );
883 return ERROR_SUCCESS;
886 UINT MSI_DatabaseGetPrimaryKeys( MSIDATABASE *db,
887 LPCWSTR table, MSIRECORD **prec )
889 static const WCHAR sql[] = {
890 's','e','l','e','c','t',' ','*',' ',
891 'f','r','o','m',' ','`','_','C','o','l','u','m','n','s','`',' ',
892 'w','h','e','r','e',' ',
893 '`','T','a','b','l','e','`',' ','=',' ','\'','%','s','\'',0 };
894 struct msi_primary_key_record_info info;
895 MSIQUERY *query = NULL;
896 UINT r;
898 if (!TABLE_Exists( db, table ))
899 return ERROR_INVALID_TABLE;
901 r = MSI_OpenQuery( db, &query, sql, table );
902 if( r != ERROR_SUCCESS )
903 return r;
905 /* count the number of primary key records */
906 info.n = 0;
907 info.rec = 0;
908 r = MSI_IterateRecords( query, 0, msi_primary_key_iterator, &info );
909 if( r == ERROR_SUCCESS )
911 TRACE("Found %d primary keys\n", info.n );
913 /* allocate a record and fill in the names of the tables */
914 info.rec = MSI_CreateRecord( info.n );
915 info.n = 0;
916 r = MSI_IterateRecords( query, 0, msi_primary_key_iterator, &info );
917 if( r == ERROR_SUCCESS )
918 *prec = info.rec;
919 else
920 msiobj_release( &info.rec->hdr );
922 msiobj_release( &query->hdr );
924 return r;
927 UINT WINAPI MsiDatabaseGetPrimaryKeysW( MSIHANDLE hdb,
928 LPCWSTR table, MSIHANDLE* phRec )
930 MSIRECORD *rec = NULL;
931 MSIDATABASE *db;
932 UINT r;
934 TRACE("%d %s %p\n", hdb, debugstr_w(table), phRec);
936 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
937 if( !db )
939 MSIHANDLE remote;
940 HRESULT hr;
942 if (!(remote = msi_get_remote(hdb)))
943 return ERROR_INVALID_HANDLE;
945 hr = remote_DatabaseGetPrimaryKeys(remote, table, phRec);
947 if (FAILED(hr))
949 if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
950 return HRESULT_CODE(hr);
952 return ERROR_FUNCTION_FAILED;
955 return ERROR_SUCCESS;
958 r = MSI_DatabaseGetPrimaryKeys( db, table, &rec );
959 if( r == ERROR_SUCCESS )
961 *phRec = alloc_msihandle( &rec->hdr );
962 if (! *phRec)
963 r = ERROR_NOT_ENOUGH_MEMORY;
964 msiobj_release( &rec->hdr );
966 msiobj_release( &db->hdr );
968 return r;
971 UINT WINAPI MsiDatabaseGetPrimaryKeysA(MSIHANDLE hdb,
972 LPCSTR table, MSIHANDLE* phRec)
974 LPWSTR szwTable = NULL;
975 UINT r;
977 TRACE("%d %s %p\n", hdb, debugstr_a(table), phRec);
979 if( table )
981 szwTable = strdupAtoW( table );
982 if( !szwTable )
983 return ERROR_OUTOFMEMORY;
985 r = MsiDatabaseGetPrimaryKeysW( hdb, szwTable, phRec );
986 msi_free( szwTable );
988 return r;
991 MSICONDITION WINAPI MsiDatabaseIsTablePersistentA(
992 MSIHANDLE hDatabase, LPCSTR szTableName)
994 LPWSTR szwTableName = NULL;
995 MSICONDITION r;
997 TRACE("%x %s\n", hDatabase, debugstr_a(szTableName));
999 if( szTableName )
1001 szwTableName = strdupAtoW( szTableName );
1002 if( !szwTableName )
1003 return MSICONDITION_ERROR;
1005 r = MsiDatabaseIsTablePersistentW( hDatabase, szwTableName );
1006 msi_free( szwTableName );
1008 return r;
1011 MSICONDITION WINAPI MsiDatabaseIsTablePersistentW(
1012 MSIHANDLE hDatabase, LPCWSTR szTableName)
1014 MSIDATABASE *db;
1015 MSICONDITION r;
1017 TRACE("%x %s\n", hDatabase, debugstr_w(szTableName));
1019 db = msihandle2msiinfo( hDatabase, MSIHANDLETYPE_DATABASE );
1020 if( !db )
1022 MSIHANDLE remote;
1024 if (!(remote = msi_get_remote(hDatabase)))
1025 return MSICONDITION_ERROR;
1027 return remote_DatabaseIsTablePersistent(remote, szTableName);
1030 r = MSI_DatabaseIsTablePersistent( db, szTableName );
1032 msiobj_release( &db->hdr );
1034 return r;