Release 0.9.39.
[wine/gsoc-2012-control.git] / dlls / msi / msiquery.c
blobabec8d8d38aa03d5bfc70a35cca29b96516b61b9
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 MSI_ViewModify( MSIQUERY *query, MSIMODIFY mode, MSIRECORD *rec )
557 MSIVIEW *view = NULL;
559 if ( !query || !rec )
560 return ERROR_INVALID_HANDLE;
562 view = query->view;
563 if ( !view || !view->ops->modify)
564 return ERROR_FUNCTION_FAILED;
566 return view->ops->modify( view, mode, rec );
569 UINT WINAPI MsiViewModify( MSIHANDLE hView, MSIMODIFY eModifyMode,
570 MSIHANDLE hRecord)
572 MSIQUERY *query = NULL;
573 MSIRECORD *rec = NULL;
574 UINT r = ERROR_FUNCTION_FAILED;
576 TRACE("%ld %x %ld\n", hView, eModifyMode, hRecord);
578 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
579 if( !query )
580 return ERROR_INVALID_HANDLE;
582 rec = msihandle2msiinfo( hRecord, MSIHANDLETYPE_RECORD );
583 r = MSI_ViewModify( query, eModifyMode, rec );
585 msiobj_release( &query->hdr );
586 if( rec )
587 msiobj_release( &rec->hdr );
589 return r;
592 MSIDBERROR WINAPI MsiViewGetErrorW( MSIHANDLE handle, LPWSTR szColumnNameBuffer,
593 DWORD *pcchBuf )
595 MSIQUERY *query = NULL;
596 static const WCHAR szError[] = { 0 };
597 MSIDBERROR r = MSIDBERROR_NOERROR;
598 int len;
600 FIXME("%ld %p %p - returns empty error string\n",
601 handle, szColumnNameBuffer, pcchBuf );
603 if( !pcchBuf )
604 return MSIDBERROR_INVALIDARG;
606 query = msihandle2msiinfo( handle, MSIHANDLETYPE_VIEW );
607 if( !query )
608 return MSIDBERROR_INVALIDARG;
610 len = lstrlenW( szError );
611 if( szColumnNameBuffer )
613 if( *pcchBuf > len )
614 lstrcpyW( szColumnNameBuffer, szError );
615 else
616 r = MSIDBERROR_MOREDATA;
618 *pcchBuf = len;
620 msiobj_release( &query->hdr );
621 return r;
624 MSIDBERROR WINAPI MsiViewGetErrorA( MSIHANDLE handle, LPSTR szColumnNameBuffer,
625 DWORD *pcchBuf )
627 static const CHAR szError[] = { 0 };
628 MSIQUERY *query = NULL;
629 MSIDBERROR r = MSIDBERROR_NOERROR;
630 int len;
632 FIXME("%ld %p %p - returns empty error string\n",
633 handle, szColumnNameBuffer, pcchBuf );
635 if( !pcchBuf )
636 return MSIDBERROR_INVALIDARG;
638 query = msihandle2msiinfo( handle, MSIHANDLETYPE_VIEW );
639 if( !query )
640 return MSIDBERROR_INVALIDARG;
642 len = lstrlenA( szError );
643 if( szColumnNameBuffer )
645 if( *pcchBuf > len )
646 lstrcpyA( szColumnNameBuffer, szError );
647 else
648 r = MSIDBERROR_MOREDATA;
650 *pcchBuf = len;
652 msiobj_release( &query->hdr );
653 return r;
656 MSIHANDLE WINAPI MsiGetLastErrorRecord( void )
658 FIXME("\n");
659 return 0;
662 DEFINE_GUID( CLSID_MsiTransform, 0x000c1082, 0x0000, 0x0000, 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46);
664 UINT MSI_DatabaseApplyTransformW( MSIDATABASE *db,
665 LPCWSTR szTransformFile, int iErrorCond )
667 HRESULT r;
668 UINT ret = ERROR_FUNCTION_FAILED;
669 IStorage *stg = NULL;
670 STATSTG stat;
672 TRACE("%p %s %d\n", db, debugstr_w(szTransformFile), iErrorCond);
674 r = StgOpenStorage( szTransformFile, NULL,
675 STGM_DIRECT|STGM_READ|STGM_SHARE_DENY_WRITE, NULL, 0, &stg);
676 if ( FAILED(r) )
677 return ret;
679 r = IStorage_Stat( stg, &stat, STATFLAG_NONAME );
680 if ( FAILED( r ) )
681 goto end;
683 if ( !IsEqualGUID( &stat.clsid, &CLSID_MsiTransform ) )
684 goto end;
686 if( TRACE_ON( msi ) )
687 enum_stream_names( stg );
689 ret = msi_table_apply_transform( db, stg );
691 end:
692 IStorage_Release( stg );
694 return ret;
697 UINT WINAPI MsiDatabaseApplyTransformW( MSIHANDLE hdb,
698 LPCWSTR szTransformFile, int iErrorCond)
700 MSIDATABASE *db;
701 UINT r;
703 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
704 if( !db )
705 return ERROR_INVALID_HANDLE;
707 r = MSI_DatabaseApplyTransformW( db, szTransformFile, iErrorCond );
708 msiobj_release( &db->hdr );
709 return r;
712 UINT WINAPI MsiDatabaseApplyTransformA( MSIHANDLE hdb,
713 LPCSTR szTransformFile, int iErrorCond)
715 LPWSTR wstr;
716 UINT ret;
718 TRACE("%ld %s %d\n", hdb, debugstr_a(szTransformFile), iErrorCond);
720 wstr = strdupAtoW( szTransformFile );
721 if( szTransformFile && !wstr )
722 return ERROR_NOT_ENOUGH_MEMORY;
724 ret = MsiDatabaseApplyTransformW( hdb, wstr, iErrorCond);
726 msi_free( wstr );
728 return ret;
731 UINT WINAPI MsiDatabaseGenerateTransformA( MSIHANDLE hdb, MSIHANDLE hdbref,
732 LPCSTR szTransformFile, int iReserved1, int iReserved2 )
734 FIXME("%ld %ld %s %d %d\n", hdb, hdbref,
735 debugstr_a(szTransformFile), iReserved1, iReserved2);
736 return ERROR_CALL_NOT_IMPLEMENTED;
739 UINT WINAPI MsiDatabaseGenerateTransformW( MSIHANDLE hdb, MSIHANDLE hdbref,
740 LPCWSTR szTransformFile, int iReserved1, int iReserved2 )
742 FIXME("%ld %ld %s %d %d\n", hdb, hdbref,
743 debugstr_w(szTransformFile), iReserved1, iReserved2);
744 return ERROR_CALL_NOT_IMPLEMENTED;
747 UINT WINAPI MsiDatabaseCommit( MSIHANDLE hdb )
749 MSIDATABASE *db;
750 UINT r;
752 TRACE("%ld\n", hdb);
754 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
755 if( !db )
756 return ERROR_INVALID_HANDLE;
758 /* FIXME: lock the database */
760 r = MSI_CommitTables( db );
762 /* FIXME: unlock the database */
764 msiobj_release( &db->hdr );
766 if (r == ERROR_SUCCESS)
768 msi_free( db->deletefile );
769 db->deletefile = NULL;
772 return r;
775 struct msi_primary_key_record_info
777 DWORD n;
778 MSIRECORD *rec;
781 static UINT msi_primary_key_iterator( MSIRECORD *rec, LPVOID param )
783 struct msi_primary_key_record_info *info = param;
784 LPCWSTR name;
785 DWORD type;
787 type = MSI_RecordGetInteger( rec, 4 );
788 if( type & MSITYPE_KEY )
790 info->n++;
791 if( info->rec )
793 name = MSI_RecordGetString( rec, 3 );
794 MSI_RecordSetStringW( info->rec, info->n, name );
798 return ERROR_SUCCESS;
801 UINT MSI_DatabaseGetPrimaryKeys( MSIDATABASE *db,
802 LPCWSTR table, MSIRECORD **prec )
804 static const WCHAR sql[] = {
805 's','e','l','e','c','t',' ','*',' ',
806 'f','r','o','m',' ','`','_','C','o','l','u','m','n','s','`',' ',
807 'w','h','e','r','e',' ',
808 '`','T','a','b','l','e','`',' ','=',' ','\'','%','s','\'',0 };
809 struct msi_primary_key_record_info info;
810 MSIQUERY *query = NULL;
811 MSIVIEW *view;
812 UINT r;
814 r = MSI_OpenQuery( db, &query, sql, table );
815 if( r != ERROR_SUCCESS )
816 return r;
818 view = query->view;
820 /* count the number of primary key records */
821 info.n = 0;
822 info.rec = 0;
823 r = MSI_IterateRecords( query, 0, msi_primary_key_iterator, &info );
824 if( r == ERROR_SUCCESS )
826 TRACE("Found %d primary keys\n", info.n );
828 /* allocate a record and fill in the names of the tables */
829 info.rec = MSI_CreateRecord( info.n );
830 info.n = 0;
831 r = MSI_IterateRecords( query, 0, msi_primary_key_iterator, &info );
832 if( r == ERROR_SUCCESS )
833 *prec = info.rec;
834 else
835 msiobj_release( &info.rec->hdr );
837 msiobj_release( &query->hdr );
839 return r;
842 UINT WINAPI MsiDatabaseGetPrimaryKeysW( MSIHANDLE hdb,
843 LPCWSTR table, MSIHANDLE* phRec )
845 MSIRECORD *rec = NULL;
846 MSIDATABASE *db;
847 UINT r;
849 TRACE("%ld %s %p\n", hdb, debugstr_w(table), phRec);
851 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
852 if( !db )
853 return ERROR_INVALID_HANDLE;
855 r = MSI_DatabaseGetPrimaryKeys( db, table, &rec );
856 if( r == ERROR_SUCCESS )
858 *phRec = alloc_msihandle( &rec->hdr );
859 if (! *phRec)
860 r = ERROR_NOT_ENOUGH_MEMORY;
861 msiobj_release( &rec->hdr );
863 msiobj_release( &db->hdr );
865 return r;
868 UINT WINAPI MsiDatabaseGetPrimaryKeysA(MSIHANDLE hdb,
869 LPCSTR table, MSIHANDLE* phRec)
871 LPWSTR szwTable = NULL;
872 UINT r;
874 TRACE("%ld %s %p\n", hdb, debugstr_a(table), phRec);
876 if( table )
878 szwTable = strdupAtoW( table );
879 if( !szwTable )
880 return ERROR_OUTOFMEMORY;
882 r = MsiDatabaseGetPrimaryKeysW( hdb, szwTable, phRec );
883 msi_free( szwTable );
885 return r;
888 MSICONDITION WINAPI MsiDatabaseIsTablePersistentA(
889 MSIHANDLE hDatabase, LPCSTR szTableName)
891 LPWSTR szwTableName = NULL;
892 MSICONDITION r;
894 TRACE("%lx %s\n", hDatabase, debugstr_a(szTableName));
896 if( szTableName )
898 szwTableName = strdupAtoW( szTableName );
899 if( !szwTableName )
900 return MSICONDITION_ERROR;
902 r = MsiDatabaseIsTablePersistentW( hDatabase, szwTableName );
903 msi_free( szwTableName );
905 return r;
908 MSICONDITION WINAPI MsiDatabaseIsTablePersistentW(
909 MSIHANDLE hDatabase, LPCWSTR szTableName)
911 MSIDATABASE *db;
912 MSICONDITION r;
914 TRACE("%lx %s\n", hDatabase, debugstr_w(szTableName));
916 db = msihandle2msiinfo( hDatabase, MSIHANDLETYPE_DATABASE );
917 if( !db )
918 return MSICONDITION_ERROR;
920 r = MSI_DatabaseIsTablePersistent( db, szTableName );
922 msiobj_release( &db->hdr );
924 return r;