msi: assert.h is not a local header (spotted by winapi_check).
[wine/multimedia.git] / dlls / msi / msiquery.c
blobf91a1236bdc806c7424c52311d787aada94a37cf
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"
39 #include "initguid.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(msi);
43 static void MSI_CloseView( MSIOBJECTHDR *arg )
45 MSIQUERY *query = (MSIQUERY*) arg;
46 struct list *ptr, *t;
48 if( query->view && query->view->ops->delete )
49 query->view->ops->delete( query->view );
50 msiobj_release( &query->db->hdr );
52 LIST_FOR_EACH_SAFE( ptr, t, &query->mem )
54 msi_free( ptr );
58 UINT VIEW_find_column( MSIVIEW *table, LPCWSTR name, UINT *n )
60 LPWSTR col_name;
61 UINT i, count, r;
63 r = table->ops->get_dimensions( table, NULL, &count );
64 if( r != ERROR_SUCCESS )
65 return r;
67 for( i=1; i<=count; i++ )
69 INT x;
71 col_name = NULL;
72 r = table->ops->get_column_info( table, i, &col_name, NULL );
73 if( r != ERROR_SUCCESS )
74 return r;
75 x = lstrcmpW( name, col_name );
76 msi_free( col_name );
77 if( !x )
79 *n = i;
80 return ERROR_SUCCESS;
84 return ERROR_INVALID_PARAMETER;
87 UINT WINAPI MsiDatabaseOpenViewA(MSIHANDLE hdb,
88 LPCSTR szQuery, MSIHANDLE *phView)
90 UINT r;
91 LPWSTR szwQuery;
93 TRACE("%ld %s %p\n", hdb, debugstr_a(szQuery), phView);
95 if( szQuery )
97 szwQuery = strdupAtoW( szQuery );
98 if( !szwQuery )
99 return ERROR_FUNCTION_FAILED;
101 else
102 szwQuery = NULL;
104 r = MsiDatabaseOpenViewW( hdb, szwQuery, phView);
106 msi_free( szwQuery );
107 return r;
110 UINT MSI_DatabaseOpenViewW(MSIDATABASE *db,
111 LPCWSTR szQuery, MSIQUERY **pView)
113 MSIQUERY *query;
114 UINT r;
116 TRACE("%s %p\n", debugstr_w(szQuery), pView);
118 if( !szQuery)
119 return ERROR_INVALID_PARAMETER;
121 /* pre allocate a handle to hold a pointer to the view */
122 query = alloc_msiobject( MSIHANDLETYPE_VIEW, sizeof (MSIQUERY),
123 MSI_CloseView );
124 if( !query )
125 return ERROR_FUNCTION_FAILED;
127 msiobj_addref( &db->hdr );
128 query->row = 0;
129 query->db = db;
130 query->view = NULL;
131 list_init( &query->mem );
133 r = MSI_ParseSQL( db, szQuery, &query->view, &query->mem );
134 if( r == ERROR_SUCCESS )
136 msiobj_addref( &query->hdr );
137 *pView = query;
140 msiobj_release( &query->hdr );
141 return r;
144 UINT MSI_OpenQuery( MSIDATABASE *db, MSIQUERY **view, LPCWSTR fmt, ... )
146 UINT r;
147 int size = 100, res;
148 LPWSTR query;
150 /* construct the string */
151 for (;;)
153 va_list va;
154 query = msi_alloc( size*sizeof(WCHAR) );
155 va_start(va, fmt);
156 res = vsnprintfW(query, size, fmt, va);
157 va_end(va);
158 if (res == -1) size *= 2;
159 else if (res >= size) size = res + 1;
160 else break;
161 msi_free( query );
163 /* perform the query */
164 r = MSI_DatabaseOpenViewW(db, query, view);
165 msi_free(query);
166 return r;
169 UINT MSI_IterateRecords( MSIQUERY *view, DWORD *count,
170 record_func func, LPVOID param )
172 MSIRECORD *rec = NULL;
173 UINT r, n = 0, max = 0;
175 r = MSI_ViewExecute( view, NULL );
176 if( r != ERROR_SUCCESS )
177 return r;
179 if( count )
180 max = *count;
182 /* iterate a query */
183 for( n = 0; (max == 0) || (n < max); n++ )
185 r = MSI_ViewFetch( view, &rec );
186 if( r != ERROR_SUCCESS )
187 break;
188 if (func)
189 r = func( rec, param );
190 msiobj_release( &rec->hdr );
191 if( r != ERROR_SUCCESS )
192 break;
195 MSI_ViewClose( view );
197 if( count )
198 *count = n;
200 if( r == ERROR_NO_MORE_ITEMS )
201 r = ERROR_SUCCESS;
203 return r;
206 /* return a single record from a query */
207 MSIRECORD *MSI_QueryGetRecord( MSIDATABASE *db, LPCWSTR fmt, ... )
209 MSIRECORD *rec = NULL;
210 MSIQUERY *view = NULL;
211 UINT r;
212 int size = 100, res;
213 LPWSTR query;
215 /* construct the string */
216 for (;;)
218 va_list va;
219 query = msi_alloc( size*sizeof(WCHAR) );
220 va_start(va, fmt);
221 res = vsnprintfW(query, size, fmt, va);
222 va_end(va);
223 if (res == -1) size *= 2;
224 else if (res >= size) size = res + 1;
225 else break;
226 msi_free( query );
228 /* perform the query */
229 r = MSI_DatabaseOpenViewW(db, query, &view);
230 msi_free(query);
232 if( r == ERROR_SUCCESS )
234 MSI_ViewExecute( view, NULL );
235 MSI_ViewFetch( view, &rec );
236 MSI_ViewClose( view );
237 msiobj_release( &view->hdr );
239 return rec;
242 UINT WINAPI MsiDatabaseOpenViewW(MSIHANDLE hdb,
243 LPCWSTR szQuery, MSIHANDLE *phView)
245 MSIDATABASE *db;
246 MSIQUERY *query = NULL;
247 UINT ret;
249 TRACE("%s %p\n", debugstr_w(szQuery), phView);
251 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
252 if( !db )
253 return ERROR_INVALID_HANDLE;
255 ret = MSI_DatabaseOpenViewW( db, szQuery, &query );
256 if( ret == ERROR_SUCCESS )
258 *phView = alloc_msihandle( &query->hdr );
259 if (! *phView)
260 ret = ERROR_NOT_ENOUGH_MEMORY;
261 msiobj_release( &query->hdr );
263 msiobj_release( &db->hdr );
265 return ret;
268 UINT MSI_ViewFetch(MSIQUERY *query, MSIRECORD **prec)
270 MSIVIEW *view;
271 MSIRECORD *rec;
272 UINT row_count = 0, col_count = 0, i, ival, ret, type;
274 TRACE("%p %p\n", query, prec );
276 view = query->view;
277 if( !view )
278 return ERROR_FUNCTION_FAILED;
280 ret = view->ops->get_dimensions( view, &row_count, &col_count );
281 if( ret )
282 return ret;
283 if( !col_count )
284 return ERROR_INVALID_PARAMETER;
286 if( query->row >= row_count )
287 return ERROR_NO_MORE_ITEMS;
289 rec = MSI_CreateRecord( col_count );
290 if( !rec )
291 return ERROR_FUNCTION_FAILED;
293 for( i=1; i<=col_count; i++ )
295 ret = view->ops->get_column_info( view, i, NULL, &type );
296 if( ret )
298 ERR("Error getting column type for %d\n", i );
299 continue;
301 if (!MSITYPE_IS_BINARY(type))
303 ret = view->ops->fetch_int( view, query->row, i, &ival );
304 if( ret )
306 ERR("Error fetching data for %d\n", i );
307 continue;
309 if( ! (type & MSITYPE_VALID ) )
310 ERR("Invalid type!\n");
312 /* check if it's nul (0) - if so, don't set anything */
313 if( !ival )
314 continue;
316 if( type & MSITYPE_STRING )
318 LPCWSTR sval;
320 sval = msi_string_lookup_id( query->db->strings, ival );
321 MSI_RecordSetStringW( rec, i, sval );
323 else
325 if( (type & MSI_DATASIZEMASK) == 2 )
326 MSI_RecordSetInteger( rec, i, ival - (1<<15) );
327 else
328 MSI_RecordSetInteger( rec, i, ival - (1<<31) );
331 else
333 IStream *stm = NULL;
335 ret = view->ops->fetch_stream( view, query->row, i, &stm );
336 if( ( ret == ERROR_SUCCESS ) && stm )
338 MSI_RecordSetIStream( rec, i, stm );
339 IStream_Release( stm );
341 else
342 ERR("failed to get stream\n");
345 query->row ++;
347 *prec = rec;
349 return ERROR_SUCCESS;
352 UINT WINAPI MsiViewFetch(MSIHANDLE hView, MSIHANDLE *record)
354 MSIQUERY *query;
355 MSIRECORD *rec = NULL;
356 UINT ret;
358 TRACE("%ld %p\n", hView, record);
360 if( !record )
361 return ERROR_INVALID_PARAMETER;
362 *record = 0;
364 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
365 if( !query )
366 return ERROR_INVALID_HANDLE;
367 ret = MSI_ViewFetch( query, &rec );
368 if( ret == ERROR_SUCCESS )
370 *record = alloc_msihandle( &rec->hdr );
371 if (! *record)
372 ret = ERROR_NOT_ENOUGH_MEMORY;
373 msiobj_release( &rec->hdr );
375 msiobj_release( &query->hdr );
376 return ret;
379 UINT MSI_ViewClose(MSIQUERY *query)
381 MSIVIEW *view;
383 TRACE("%p\n", query );
385 view = query->view;
386 if( !view )
387 return ERROR_FUNCTION_FAILED;
388 if( !view->ops->close )
389 return ERROR_FUNCTION_FAILED;
391 return view->ops->close( view );
394 UINT WINAPI MsiViewClose(MSIHANDLE hView)
396 MSIQUERY *query;
397 UINT ret;
399 TRACE("%ld\n", hView );
401 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
402 if( !query )
403 return ERROR_INVALID_HANDLE;
405 ret = MSI_ViewClose( query );
406 msiobj_release( &query->hdr );
407 return ret;
410 UINT MSI_ViewExecute(MSIQUERY *query, MSIRECORD *rec )
412 MSIVIEW *view;
414 TRACE("%p %p\n", query, rec);
416 view = query->view;
417 if( !view )
418 return ERROR_FUNCTION_FAILED;
419 if( !view->ops->execute )
420 return ERROR_FUNCTION_FAILED;
421 query->row = 0;
423 return view->ops->execute( view, rec );
426 UINT WINAPI MsiViewExecute(MSIHANDLE hView, MSIHANDLE hRec)
428 MSIQUERY *query;
429 MSIRECORD *rec = NULL;
430 UINT ret;
432 TRACE("%ld %ld\n", hView, hRec);
434 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
435 if( !query )
436 return ERROR_INVALID_HANDLE;
438 if( hRec )
440 rec = msihandle2msiinfo( hRec, MSIHANDLETYPE_RECORD );
441 if( !rec )
443 ret = ERROR_INVALID_HANDLE;
444 goto out;
448 msiobj_lock( &rec->hdr );
449 ret = MSI_ViewExecute( query, rec );
450 msiobj_unlock( &rec->hdr );
452 out:
453 msiobj_release( &query->hdr );
454 if( rec )
455 msiobj_release( &rec->hdr );
457 return ret;
460 static UINT msi_set_record_type_string( MSIRECORD *rec, UINT field, UINT type )
462 static const WCHAR fmt[] = { '%','d',0 };
463 WCHAR szType[0x10];
465 if (MSITYPE_IS_BINARY(type))
466 szType[0] = 'v';
467 else if (type & MSITYPE_LOCALIZABLE)
468 szType[0] = 'l';
469 else if (type & MSITYPE_STRING)
470 szType[0] = 's';
471 else
472 szType[0] = 'i';
473 if (type & MSITYPE_NULLABLE)
474 szType[0] &= ~0x20;
476 sprintfW( &szType[1], fmt, (type&0xff) );
478 TRACE("type %04x -> %s\n", type, debugstr_w(szType) );
480 return MSI_RecordSetStringW( rec, field, szType );
483 UINT MSI_ViewGetColumnInfo( MSIQUERY *query, MSICOLINFO info, MSIRECORD **prec )
485 UINT r = ERROR_FUNCTION_FAILED, i, count = 0, type;
486 MSIRECORD *rec;
487 MSIVIEW *view = query->view;
488 LPWSTR name;
490 if( !view )
491 return ERROR_FUNCTION_FAILED;
493 if( !view->ops->get_dimensions )
494 return ERROR_FUNCTION_FAILED;
496 r = view->ops->get_dimensions( view, NULL, &count );
497 if( r != ERROR_SUCCESS )
498 return r;
499 if( !count )
500 return ERROR_INVALID_PARAMETER;
502 rec = MSI_CreateRecord( count );
503 if( !rec )
504 return ERROR_FUNCTION_FAILED;
506 for( i=0; i<count; i++ )
508 name = NULL;
509 r = view->ops->get_column_info( view, i+1, &name, &type );
510 if( r != ERROR_SUCCESS )
511 continue;
512 if (info == MSICOLINFO_NAMES)
513 MSI_RecordSetStringW( rec, i+1, name );
514 else
515 msi_set_record_type_string( rec, i+1, type);
516 msi_free( name );
519 *prec = rec;
520 return ERROR_SUCCESS;
523 UINT WINAPI MsiViewGetColumnInfo(MSIHANDLE hView, MSICOLINFO info, MSIHANDLE *hRec)
525 MSIQUERY *query = NULL;
526 MSIRECORD *rec = NULL;
527 UINT r;
529 TRACE("%ld %d %p\n", hView, info, hRec);
531 if( !hRec )
532 return ERROR_INVALID_PARAMETER;
534 if( info != MSICOLINFO_NAMES && info != MSICOLINFO_TYPES )
535 return ERROR_INVALID_PARAMETER;
537 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
538 if( !query )
539 return ERROR_INVALID_HANDLE;
541 r = MSI_ViewGetColumnInfo( query, info, &rec );
542 if ( r == ERROR_SUCCESS )
544 *hRec = alloc_msihandle( &rec->hdr );
545 if ( !*hRec )
546 r = ERROR_NOT_ENOUGH_MEMORY;
547 msiobj_release( &rec->hdr );
550 msiobj_release( &query->hdr );
552 return r;
555 UINT WINAPI MsiViewModify( MSIHANDLE hView, MSIMODIFY eModifyMode,
556 MSIHANDLE hRecord)
558 MSIVIEW *view = NULL;
559 MSIQUERY *query = NULL;
560 MSIRECORD *rec = NULL;
561 UINT r = ERROR_FUNCTION_FAILED;
563 TRACE("%ld %x %ld\n", hView, eModifyMode, hRecord);
565 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
566 if( !query )
567 return ERROR_INVALID_HANDLE;
569 view = query->view;
570 if( !view )
571 goto out;
573 if( !view->ops->modify )
574 goto out;
576 rec = msihandle2msiinfo( hRecord, MSIHANDLETYPE_RECORD );
577 if( !rec )
579 r = ERROR_INVALID_HANDLE;
580 goto out;
583 r = view->ops->modify( view, eModifyMode, rec );
585 out:
586 msiobj_release( &query->hdr );
587 if( rec )
588 msiobj_release( &rec->hdr );
590 return r;
593 MSIDBERROR WINAPI MsiViewGetErrorW( MSIHANDLE handle, LPWSTR szColumnNameBuffer,
594 DWORD *pcchBuf )
596 MSIQUERY *query = NULL;
597 static const WCHAR szError[] = { 0 };
598 MSIDBERROR r = MSIDBERROR_NOERROR;
599 int len;
601 FIXME("%ld %p %p - returns empty error string\n",
602 handle, szColumnNameBuffer, pcchBuf );
604 if( !pcchBuf )
605 return MSIDBERROR_INVALIDARG;
607 query = msihandle2msiinfo( handle, MSIHANDLETYPE_VIEW );
608 if( !query )
609 return MSIDBERROR_INVALIDARG;
611 len = lstrlenW( szError );
612 if( szColumnNameBuffer )
614 if( *pcchBuf > len )
615 lstrcpyW( szColumnNameBuffer, szError );
616 else
617 r = MSIDBERROR_MOREDATA;
619 *pcchBuf = len;
621 msiobj_release( &query->hdr );
622 return r;
625 MSIDBERROR WINAPI MsiViewGetErrorA( MSIHANDLE handle, LPSTR szColumnNameBuffer,
626 DWORD *pcchBuf )
628 static const CHAR szError[] = { 0 };
629 MSIQUERY *query = NULL;
630 MSIDBERROR r = MSIDBERROR_NOERROR;
631 int len;
633 FIXME("%ld %p %p - returns empty error string\n",
634 handle, szColumnNameBuffer, pcchBuf );
636 if( !pcchBuf )
637 return MSIDBERROR_INVALIDARG;
639 query = msihandle2msiinfo( handle, MSIHANDLETYPE_VIEW );
640 if( !query )
641 return MSIDBERROR_INVALIDARG;
643 len = lstrlenA( szError );
644 if( szColumnNameBuffer )
646 if( *pcchBuf > len )
647 lstrcpyA( szColumnNameBuffer, szError );
648 else
649 r = MSIDBERROR_MOREDATA;
651 *pcchBuf = len;
653 msiobj_release( &query->hdr );
654 return r;
657 MSIHANDLE WINAPI MsiGetLastErrorRecord( void )
659 FIXME("\n");
660 return 0;
663 DEFINE_GUID( CLSID_MsiTransform, 0x000c1082, 0x0000, 0x0000, 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46);
665 UINT MSI_DatabaseApplyTransformW( MSIDATABASE *db,
666 LPCWSTR szTransformFile, int iErrorCond )
668 HRESULT r;
669 UINT ret = ERROR_FUNCTION_FAILED;
670 IStorage *stg = NULL;
671 STATSTG stat;
673 TRACE("%p %s %d\n", db, debugstr_w(szTransformFile), iErrorCond);
675 r = StgOpenStorage( szTransformFile, NULL,
676 STGM_DIRECT|STGM_READ|STGM_SHARE_DENY_WRITE, NULL, 0, &stg);
677 if ( FAILED(r) )
678 return ret;
680 r = IStorage_Stat( stg, &stat, STATFLAG_NONAME );
681 if ( FAILED( r ) )
682 goto end;
684 if ( !IsEqualGUID( &stat.clsid, &CLSID_MsiTransform ) )
685 goto end;
687 if( TRACE_ON( msi ) )
688 enum_stream_names( stg );
690 ret = msi_table_apply_transform( db, stg );
692 end:
693 IStorage_Release( stg );
695 return ret;
698 UINT WINAPI MsiDatabaseApplyTransformW( MSIHANDLE hdb,
699 LPCWSTR szTransformFile, int iErrorCond)
701 MSIDATABASE *db;
702 UINT r;
704 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
705 if( !db )
706 return ERROR_INVALID_HANDLE;
708 r = MSI_DatabaseApplyTransformW( db, szTransformFile, iErrorCond );
709 msiobj_release( &db->hdr );
710 return r;
713 UINT WINAPI MsiDatabaseApplyTransformA( MSIHANDLE hdb,
714 LPCSTR szTransformFile, int iErrorCond)
716 LPWSTR wstr;
717 UINT ret;
719 TRACE("%ld %s %d\n", hdb, debugstr_a(szTransformFile), iErrorCond);
721 wstr = strdupAtoW( szTransformFile );
722 if( szTransformFile && !wstr )
723 return ERROR_NOT_ENOUGH_MEMORY;
725 ret = MsiDatabaseApplyTransformW( hdb, wstr, iErrorCond);
727 msi_free( wstr );
729 return ret;
732 UINT WINAPI MsiDatabaseGenerateTransformA( MSIHANDLE hdb, MSIHANDLE hdbref,
733 LPCSTR szTransformFile, int iReserved1, int iReserved2 )
735 FIXME("%ld %ld %s %d %d\n", hdb, hdbref,
736 debugstr_a(szTransformFile), iReserved1, iReserved2);
737 return ERROR_CALL_NOT_IMPLEMENTED;
740 UINT WINAPI MsiDatabaseGenerateTransformW( MSIHANDLE hdb, MSIHANDLE hdbref,
741 LPCWSTR szTransformFile, int iReserved1, int iReserved2 )
743 FIXME("%ld %ld %s %d %d\n", hdb, hdbref,
744 debugstr_w(szTransformFile), iReserved1, iReserved2);
745 return ERROR_CALL_NOT_IMPLEMENTED;
748 UINT WINAPI MsiDatabaseCommit( MSIHANDLE hdb )
750 MSIDATABASE *db;
751 UINT r;
753 TRACE("%ld\n", hdb);
755 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
756 if( !db )
757 return ERROR_INVALID_HANDLE;
759 /* FIXME: lock the database */
761 r = MSI_CommitTables( db );
763 /* FIXME: unlock the database */
765 msiobj_release( &db->hdr );
767 if (r == ERROR_SUCCESS)
769 msi_free( db->deletefile );
770 db->deletefile = NULL;
773 return r;
776 struct msi_primary_key_record_info
778 DWORD n;
779 MSIRECORD *rec;
782 static UINT msi_primary_key_iterator( MSIRECORD *rec, LPVOID param )
784 struct msi_primary_key_record_info *info = param;
785 LPCWSTR name;
786 DWORD type;
788 type = MSI_RecordGetInteger( rec, 4 );
789 if( type & MSITYPE_KEY )
791 info->n++;
792 if( info->rec )
794 name = MSI_RecordGetString( rec, 3 );
795 MSI_RecordSetStringW( info->rec, info->n, name );
799 return ERROR_SUCCESS;
802 UINT MSI_DatabaseGetPrimaryKeys( MSIDATABASE *db,
803 LPCWSTR table, MSIRECORD **prec )
805 static const WCHAR sql[] = {
806 's','e','l','e','c','t',' ','*',' ',
807 'f','r','o','m',' ','`','_','C','o','l','u','m','n','s','`',' ',
808 'w','h','e','r','e',' ',
809 '`','T','a','b','l','e','`',' ','=',' ','\'','%','s','\'',0 };
810 struct msi_primary_key_record_info info;
811 MSIQUERY *query = NULL;
812 MSIVIEW *view;
813 UINT r;
815 r = MSI_OpenQuery( db, &query, sql, table );
816 if( r != ERROR_SUCCESS )
817 return r;
819 view = query->view;
821 /* count the number of primary key records */
822 info.n = 0;
823 info.rec = 0;
824 r = MSI_IterateRecords( query, 0, msi_primary_key_iterator, &info );
825 if( r == ERROR_SUCCESS )
827 TRACE("Found %d primary keys\n", info.n );
829 /* allocate a record and fill in the names of the tables */
830 info.rec = MSI_CreateRecord( info.n );
831 info.n = 0;
832 r = MSI_IterateRecords( query, 0, msi_primary_key_iterator, &info );
833 if( r == ERROR_SUCCESS )
834 *prec = info.rec;
835 else
836 msiobj_release( &info.rec->hdr );
838 msiobj_release( &query->hdr );
840 return r;
843 UINT WINAPI MsiDatabaseGetPrimaryKeysW( MSIHANDLE hdb,
844 LPCWSTR table, MSIHANDLE* phRec )
846 MSIRECORD *rec = NULL;
847 MSIDATABASE *db;
848 UINT r;
850 TRACE("%ld %s %p\n", hdb, debugstr_w(table), phRec);
852 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
853 if( !db )
854 return ERROR_INVALID_HANDLE;
856 r = MSI_DatabaseGetPrimaryKeys( db, table, &rec );
857 if( r == ERROR_SUCCESS )
859 *phRec = alloc_msihandle( &rec->hdr );
860 if (! *phRec)
861 r = ERROR_NOT_ENOUGH_MEMORY;
862 msiobj_release( &rec->hdr );
864 msiobj_release( &db->hdr );
866 return r;
869 UINT WINAPI MsiDatabaseGetPrimaryKeysA(MSIHANDLE hdb,
870 LPCSTR table, MSIHANDLE* phRec)
872 LPWSTR szwTable = NULL;
873 UINT r;
875 TRACE("%ld %s %p\n", hdb, debugstr_a(table), phRec);
877 if( table )
879 szwTable = strdupAtoW( table );
880 if( !szwTable )
881 return ERROR_OUTOFMEMORY;
883 r = MsiDatabaseGetPrimaryKeysW( hdb, szwTable, phRec );
884 msi_free( szwTable );
886 return r;
889 MSICONDITION WINAPI MsiDatabaseIsTablePersistentA(
890 MSIHANDLE hDatabase, LPCSTR szTableName)
892 LPWSTR szwTableName = NULL;
893 MSICONDITION r;
895 TRACE("%lx %s\n", hDatabase, debugstr_a(szTableName));
897 if( szTableName )
899 szwTableName = strdupAtoW( szTableName );
900 if( !szwTableName )
901 return MSICONDITION_ERROR;
903 r = MsiDatabaseIsTablePersistentW( hDatabase, szwTableName );
904 msi_free( szwTableName );
906 return r;
909 MSICONDITION WINAPI MsiDatabaseIsTablePersistentW(
910 MSIHANDLE hDatabase, LPCWSTR szTableName)
912 MSIDATABASE *db;
913 MSICONDITION r;
915 TRACE("%lx %s\n", hDatabase, debugstr_w(szTableName));
917 db = msihandle2msiinfo( hDatabase, MSIHANDLETYPE_DATABASE );
918 if( !db )
919 return MSICONDITION_ERROR;
921 r = MSI_DatabaseIsTablePersistent( db, szTableName );
923 msiobj_release( &db->hdr );
925 return r;