xref: /reactos/dll/win32/msi/msiquery.c (revision f4be6dc3)
1 /*
2  * Implementation of the Microsoft Installer (msi.dll)
3  *
4  * Copyright 2002-2005 Mike McCormack for CodeWeavers
5  *
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.
10  *
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.
15  *
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
19  */
20 
21 #include <stdarg.h>
22 
23 #define COBJMACROS
24 
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winerror.h"
28 #include "wine/debug.h"
29 #include "wine/exception.h"
30 #include "msi.h"
31 #include "msiquery.h"
32 #include "objbase.h"
33 #include "objidl.h"
34 #include "winnls.h"
35 
36 #include "msipriv.h"
37 #include "query.h"
38 #include "winemsi_s.h"
39 
40 #include "initguid.h"
41 
42 WINE_DEFAULT_DEBUG_CHANNEL(msi);
43 
MSI_CloseView(MSIOBJECTHDR * arg)44 static void MSI_CloseView( MSIOBJECTHDR *arg )
45 {
46     MSIQUERY *query = (MSIQUERY*) arg;
47     struct list *ptr, *t;
48 
49     if( query->view && query->view->ops->delete )
50         query->view->ops->delete( query->view );
51     msiobj_release( &query->db->hdr );
52 
53     LIST_FOR_EACH_SAFE( ptr, t, &query->mem )
54     {
55         free( ptr );
56     }
57 }
58 
VIEW_find_column(MSIVIEW * table,LPCWSTR name,LPCWSTR table_name,UINT * n)59 UINT VIEW_find_column( MSIVIEW *table, LPCWSTR name, LPCWSTR table_name, UINT *n )
60 {
61     LPCWSTR col_name, haystack_table_name;
62     UINT i, count, r;
63 
64     r = table->ops->get_dimensions( table, NULL, &count );
65     if( r != ERROR_SUCCESS )
66         return r;
67 
68     for( i=1; i<=count; i++ )
69     {
70         INT x;
71 
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 = wcscmp( name, col_name );
77         if( table_name )
78             x |= wcscmp( table_name, haystack_table_name );
79         if( !x )
80         {
81             *n = i;
82             return ERROR_SUCCESS;
83         }
84     }
85     return ERROR_INVALID_PARAMETER;
86 }
87 
MsiDatabaseOpenViewA(MSIHANDLE hdb,const char * szQuery,MSIHANDLE * phView)88 UINT WINAPI MsiDatabaseOpenViewA( MSIHANDLE hdb, const char *szQuery, MSIHANDLE *phView )
89 {
90     UINT r;
91     WCHAR *szwQuery;
92 
93     TRACE( "%lu, %s, %p\n", hdb, debugstr_a(szQuery), phView );
94 
95     if( szQuery )
96     {
97         szwQuery = strdupAtoW( szQuery );
98         if( !szwQuery )
99             return ERROR_FUNCTION_FAILED;
100     }
101     else
102         szwQuery = NULL;
103 
104     r = MsiDatabaseOpenViewW( hdb, szwQuery, phView);
105 
106     free( szwQuery );
107     return r;
108 }
109 
MSI_DatabaseOpenViewW(MSIDATABASE * db,const WCHAR * szQuery,MSIQUERY ** pView)110 UINT MSI_DatabaseOpenViewW( MSIDATABASE *db, const WCHAR *szQuery, MSIQUERY **pView )
111 {
112     MSIQUERY *query;
113     UINT r;
114 
115     TRACE( "%s, %p\n", debugstr_w(szQuery), pView );
116 
117     /* pre allocate a handle to hold a pointer to the view */
118     query = alloc_msiobject( MSIHANDLETYPE_VIEW, sizeof (MSIQUERY),
119                               MSI_CloseView );
120     if( !query )
121         return ERROR_FUNCTION_FAILED;
122 
123     msiobj_addref( &db->hdr );
124     query->db = db;
125     list_init( &query->mem );
126 
127     r = MSI_ParseSQL( db, szQuery, &query->view, &query->mem );
128     if( r == ERROR_SUCCESS )
129     {
130         msiobj_addref( &query->hdr );
131         *pView = query;
132     }
133 
134     msiobj_release( &query->hdr );
135     return r;
136 }
137 
MSI_OpenQuery(MSIDATABASE * db,MSIQUERY ** view,LPCWSTR fmt,...)138 UINT WINAPIV MSI_OpenQuery( MSIDATABASE *db, MSIQUERY **view, LPCWSTR fmt, ... )
139 {
140     UINT r;
141     int size = 100, res;
142     LPWSTR query;
143 
144     /* construct the string */
145     for (;;)
146     {
147         va_list va;
148         query = malloc(size * sizeof(WCHAR));
149         va_start(va, fmt);
150         res = vswprintf(query, size, fmt, va);
151         va_end(va);
152         if (res == -1) size *= 2;
153         else if (res >= size) size = res + 1;
154         else break;
155         free(query);
156     }
157     /* perform the query */
158     r = MSI_DatabaseOpenViewW(db, query, view);
159     free(query);
160     return r;
161 }
162 
MSI_IterateRecords(MSIQUERY * view,LPDWORD count,record_func func,LPVOID param)163 UINT MSI_IterateRecords( MSIQUERY *view, LPDWORD count,
164                          record_func func, LPVOID param )
165 {
166     MSIRECORD *rec = NULL;
167     UINT r, n = 0, max = 0;
168 
169     r = MSI_ViewExecute( view, NULL );
170     if( r != ERROR_SUCCESS )
171         return r;
172 
173     if( count )
174         max = *count;
175 
176     /* iterate a query */
177     for( n = 0; (max == 0) || (n < max); n++ )
178     {
179         r = MSI_ViewFetch( view, &rec );
180         if( r != ERROR_SUCCESS )
181             break;
182         if (func)
183             r = func( rec, param );
184         msiobj_release( &rec->hdr );
185         if( r != ERROR_SUCCESS )
186             break;
187     }
188 
189     MSI_ViewClose( view );
190 
191     if( count )
192         *count = n;
193 
194     if( r == ERROR_NO_MORE_ITEMS )
195         r = ERROR_SUCCESS;
196 
197     return r;
198 }
199 
200 /* return a single record from a query */
MSI_QueryGetRecord(MSIDATABASE * db,LPCWSTR fmt,...)201 MSIRECORD * WINAPIV MSI_QueryGetRecord( MSIDATABASE *db, LPCWSTR fmt, ... )
202 {
203     MSIRECORD *rec = NULL;
204     MSIQUERY *view = NULL;
205     UINT r;
206     int size = 100, res;
207     LPWSTR query;
208 
209     /* construct the string */
210     for (;;)
211     {
212         va_list va;
213         query = malloc(size * sizeof(WCHAR));
214         va_start(va, fmt);
215         res = vswprintf(query, size, fmt, va);
216         va_end(va);
217         if (res == -1) size *= 2;
218         else if (res >= size) size = res + 1;
219         else break;
220         free(query);
221     }
222     /* perform the query */
223     r = MSI_DatabaseOpenViewW(db, query, &view);
224     free(query);
225 
226     if( r == ERROR_SUCCESS )
227     {
228         MSI_ViewExecute( view, NULL );
229         MSI_ViewFetch( view, &rec );
230         MSI_ViewClose( view );
231         msiobj_release( &view->hdr );
232     }
233     return rec;
234 }
235 
MsiDatabaseOpenViewW(MSIHANDLE hdb,LPCWSTR szQuery,MSIHANDLE * phView)236 UINT WINAPI MsiDatabaseOpenViewW(MSIHANDLE hdb,
237               LPCWSTR szQuery, MSIHANDLE *phView)
238 {
239     MSIDATABASE *db;
240     MSIQUERY *query = NULL;
241     UINT ret;
242 
243     TRACE("%s %p\n", debugstr_w(szQuery), phView);
244 
245     if (!phView)
246         return ERROR_INVALID_PARAMETER;
247 
248     if (!szQuery)
249         return ERROR_BAD_QUERY_SYNTAX;
250 
251     db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
252     if( !db )
253     {
254         MSIHANDLE remote, remote_view;
255 
256         if (!(remote = msi_get_remote(hdb)))
257             return ERROR_INVALID_HANDLE;
258 
259         __TRY
260         {
261             ret = remote_DatabaseOpenView(remote, szQuery, &remote_view);
262         }
263         __EXCEPT(rpc_filter)
264         {
265             ret = GetExceptionCode();
266         }
267         __ENDTRY
268 
269         if (!ret)
270             *phView = alloc_msi_remote_handle(remote_view);
271         return ret;
272     }
273 
274     ret = MSI_DatabaseOpenViewW( db, szQuery, &query );
275     if( ret == ERROR_SUCCESS )
276     {
277         *phView = alloc_msihandle( &query->hdr );
278         if (! *phView)
279            ret = ERROR_NOT_ENOUGH_MEMORY;
280         msiobj_release( &query->hdr );
281     }
282     msiobj_release( &db->hdr );
283 
284     return ret;
285 }
286 
msi_view_refresh_row(MSIDATABASE * db,MSIVIEW * view,UINT row,MSIRECORD * rec)287 UINT msi_view_refresh_row(MSIDATABASE *db, MSIVIEW *view, UINT row, MSIRECORD *rec)
288 {
289     UINT row_count = 0, col_count = 0, i, ival, ret, type;
290 
291     TRACE("%p %p %d %p\n", db, view, row, rec);
292 
293     ret = view->ops->get_dimensions(view, &row_count, &col_count);
294     if (ret)
295         return ret;
296 
297     if (!col_count)
298         return ERROR_INVALID_PARAMETER;
299 
300     for (i = 1; i <= col_count; i++)
301     {
302         ret = view->ops->get_column_info(view, i, NULL, &type, NULL, NULL);
303         if (ret)
304         {
305             ERR("Error getting column type for %d\n", i);
306             continue;
307         }
308 
309         if (MSITYPE_IS_BINARY(type))
310         {
311             IStream *stm = NULL;
312 
313             ret = view->ops->fetch_stream(view, row, i, &stm);
314             if ((ret == ERROR_SUCCESS) && stm)
315             {
316                 MSI_RecordSetIStream(rec, i, stm);
317                 IStream_Release(stm);
318             }
319             else
320                 WARN("failed to get stream\n");
321 
322             continue;
323         }
324 
325         ret = view->ops->fetch_int(view, row, i, &ival);
326         if (ret)
327         {
328             ERR("Error fetching data for %d\n", i);
329             continue;
330         }
331 
332         if (! (type & MSITYPE_VALID))
333             ERR("Invalid type!\n");
334 
335         if (type & MSITYPE_STRING)
336         {
337             int len;
338             const WCHAR *sval = msi_string_lookup(db->strings, ival, &len);
339             msi_record_set_string(rec, i, sval, len);
340         }
341         else
342         {
343             if ((type & MSI_DATASIZEMASK) == 2)
344                 MSI_RecordSetInteger(rec, i, ival ? ival - (1<<15) : MSI_NULL_INTEGER);
345             else
346                 MSI_RecordSetInteger(rec, i, ival - (1u<<31));
347         }
348     }
349 
350     return ERROR_SUCCESS;
351 }
352 
msi_view_get_row(MSIDATABASE * db,MSIVIEW * view,UINT row,MSIRECORD ** rec)353 UINT msi_view_get_row(MSIDATABASE *db, MSIVIEW *view, UINT row, MSIRECORD **rec)
354 {
355     UINT row_count = 0, col_count = 0, r;
356     MSIRECORD *object;
357 
358     TRACE("view %p, row %u, rec %p.\n", view, row, rec);
359 
360     if ((r = view->ops->get_dimensions(view, &row_count, &col_count)))
361         return r;
362 
363     if (row >= row_count)
364         return ERROR_NO_MORE_ITEMS;
365 
366     if (!(object = MSI_CreateRecord( col_count )))
367         return ERROR_OUTOFMEMORY;
368 
369     if ((r = msi_view_refresh_row(db, view, row, object)))
370         msiobj_release( &object->hdr );
371     else
372         *rec = object;
373 
374     return r;
375 }
376 
MSI_ViewFetch(MSIQUERY * query,MSIRECORD ** prec)377 UINT MSI_ViewFetch(MSIQUERY *query, MSIRECORD **prec)
378 {
379     MSIVIEW *view;
380     UINT r;
381 
382     TRACE("%p %p\n", query, prec );
383 
384     view = query->view;
385     if( !view )
386         return ERROR_FUNCTION_FAILED;
387 
388     r = msi_view_get_row(query->db, view, query->row, prec);
389     if (r == ERROR_SUCCESS)
390     {
391         query->row ++;
392         (*prec)->cookie = (UINT64)(ULONG_PTR)query;
393         MSI_RecordSetInteger(*prec, 0, 1);
394     }
395     else if (r == ERROR_NO_MORE_ITEMS)
396     {
397         /* end of view; reset cursor to first row */
398         query->row = 0;
399     }
400 
401     return r;
402 }
403 
MsiViewFetch(MSIHANDLE hView,MSIHANDLE * record)404 UINT WINAPI MsiViewFetch( MSIHANDLE hView, MSIHANDLE *record )
405 {
406     MSIQUERY *query;
407     MSIRECORD *rec = NULL;
408     UINT ret;
409 
410     TRACE( "%lu, %p\n", hView, record );
411 
412     if( !record )
413         return ERROR_INVALID_PARAMETER;
414     *record = 0;
415 
416     query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
417     if (!query)
418     {
419         struct wire_record *wire_rec = NULL;
420         MSIHANDLE remote;
421 
422         if (!(remote = msi_get_remote(hView)))
423             return ERROR_INVALID_HANDLE;
424 
425         __TRY
426         {
427             ret = remote_ViewFetch(remote, &wire_rec);
428         }
429         __EXCEPT(rpc_filter)
430         {
431             ret = GetExceptionCode();
432         }
433         __ENDTRY
434 
435         if (!ret)
436         {
437             ret = unmarshal_record(wire_rec, record);
438             free_remote_record(wire_rec);
439         }
440         return ret;
441     }
442     ret = MSI_ViewFetch( query, &rec );
443     if( ret == ERROR_SUCCESS )
444     {
445         *record = alloc_msihandle( &rec->hdr );
446         if (! *record)
447            ret = ERROR_NOT_ENOUGH_MEMORY;
448         msiobj_release( &rec->hdr );
449     }
450     msiobj_release( &query->hdr );
451     return ret;
452 }
453 
MSI_ViewClose(MSIQUERY * query)454 UINT MSI_ViewClose(MSIQUERY *query)
455 {
456     MSIVIEW *view;
457 
458     TRACE("%p\n", query );
459 
460     view = query->view;
461     if( !view )
462         return ERROR_FUNCTION_FAILED;
463     if( !view->ops->close )
464         return ERROR_FUNCTION_FAILED;
465 
466     return view->ops->close( view );
467 }
468 
MsiViewClose(MSIHANDLE hView)469 UINT WINAPI MsiViewClose( MSIHANDLE hView )
470 {
471     MSIQUERY *query;
472     UINT ret;
473 
474     TRACE( "%lu\n", hView );
475 
476     query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
477     if (!query)
478     {
479         MSIHANDLE remote;
480 
481         if (!(remote = msi_get_remote(hView)))
482             return ERROR_INVALID_HANDLE;
483 
484         __TRY
485         {
486             ret = remote_ViewClose(remote);
487         }
488         __EXCEPT(rpc_filter)
489         {
490             ret = GetExceptionCode();
491         }
492         __ENDTRY
493 
494         return ret;
495     }
496 
497     ret = MSI_ViewClose( query );
498     msiobj_release( &query->hdr );
499     return ret;
500 }
501 
MSI_ViewExecute(MSIQUERY * query,MSIRECORD * rec)502 UINT MSI_ViewExecute(MSIQUERY *query, MSIRECORD *rec )
503 {
504     MSIVIEW *view;
505 
506     TRACE("%p %p\n", query, rec);
507 
508     view = query->view;
509     if( !view )
510         return ERROR_FUNCTION_FAILED;
511     if( !view->ops->execute )
512         return ERROR_FUNCTION_FAILED;
513     query->row = 0;
514 
515     return view->ops->execute( view, rec );
516 }
517 
MsiViewExecute(MSIHANDLE hView,MSIHANDLE hRec)518 UINT WINAPI MsiViewExecute( MSIHANDLE hView, MSIHANDLE hRec )
519 {
520     MSIQUERY *query;
521     MSIRECORD *rec = NULL;
522     UINT ret;
523 
524     TRACE( "%lu, %lu\n", hView, hRec );
525 
526     if( hRec )
527     {
528         rec = msihandle2msiinfo( hRec, MSIHANDLETYPE_RECORD );
529         if( !rec )
530             return ERROR_INVALID_HANDLE;
531     }
532 
533     query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
534     if( !query )
535     {
536         MSIHANDLE remote;
537 
538         if (!(remote = msi_get_remote(hView)))
539             return ERROR_INVALID_HANDLE;
540 
541         __TRY
542         {
543             ret = remote_ViewExecute(remote, rec ? (struct wire_record *)&rec->count : NULL);
544         }
545         __EXCEPT(rpc_filter)
546         {
547             ret = GetExceptionCode();
548         }
549         __ENDTRY
550 
551         if (rec)
552             msiobj_release(&rec->hdr);
553         return ret;
554     }
555 
556     msiobj_lock( &rec->hdr );
557     ret = MSI_ViewExecute( query, rec );
558     msiobj_unlock( &rec->hdr );
559 
560     msiobj_release( &query->hdr );
561     if( rec )
562         msiobj_release( &rec->hdr );
563 
564     return ret;
565 }
566 
set_record_type_string(MSIRECORD * rec,UINT field,UINT type,BOOL temporary)567 static UINT set_record_type_string( MSIRECORD *rec, UINT field, UINT type, BOOL temporary )
568 {
569     WCHAR szType[0x10];
570 
571     if (MSITYPE_IS_BINARY(type))
572         szType[0] = 'v';
573     else if (type & MSITYPE_LOCALIZABLE)
574         szType[0] = 'l';
575     else if (type & MSITYPE_UNKNOWN)
576         szType[0] = 'f';
577     else if (type & MSITYPE_STRING)
578     {
579         if (temporary)
580             szType[0] = 'g';
581         else
582           szType[0] = 's';
583     }
584     else
585     {
586         if (temporary)
587             szType[0] = 'j';
588         else
589             szType[0] = 'i';
590     }
591 
592     if (type & MSITYPE_NULLABLE)
593         szType[0] &= ~0x20;
594 
595     swprintf( &szType[1], ARRAY_SIZE(szType) - 1, L"%d", (type&0xff) );
596 
597     TRACE("type %04x -> %s\n", type, debugstr_w(szType) );
598 
599     return MSI_RecordSetStringW( rec, field, szType );
600 }
601 
MSI_ViewGetColumnInfo(MSIQUERY * query,MSICOLINFO info,MSIRECORD ** prec)602 UINT MSI_ViewGetColumnInfo( MSIQUERY *query, MSICOLINFO info, MSIRECORD **prec )
603 {
604     UINT r = ERROR_FUNCTION_FAILED, i, count = 0, type;
605     MSIRECORD *rec;
606     MSIVIEW *view = query->view;
607     LPCWSTR name;
608     BOOL temporary;
609 
610     if( !view )
611         return ERROR_FUNCTION_FAILED;
612 
613     if( !view->ops->get_dimensions )
614         return ERROR_FUNCTION_FAILED;
615 
616     r = view->ops->get_dimensions( view, NULL, &count );
617     if( r != ERROR_SUCCESS )
618         return r;
619     if( !count )
620         return ERROR_INVALID_PARAMETER;
621 
622     rec = MSI_CreateRecord( count );
623     if( !rec )
624         return ERROR_FUNCTION_FAILED;
625 
626     for( i=0; i<count; i++ )
627     {
628         name = NULL;
629         r = view->ops->get_column_info( view, i+1, &name, &type, &temporary, NULL );
630         if( r != ERROR_SUCCESS )
631             continue;
632         if (info == MSICOLINFO_NAMES)
633             MSI_RecordSetStringW( rec, i+1, name );
634         else
635             set_record_type_string( rec, i+1, type, temporary );
636     }
637     *prec = rec;
638     return ERROR_SUCCESS;
639 }
640 
MsiViewGetColumnInfo(MSIHANDLE hView,MSICOLINFO info,MSIHANDLE * hRec)641 UINT WINAPI MsiViewGetColumnInfo( MSIHANDLE hView, MSICOLINFO info, MSIHANDLE *hRec )
642 {
643     MSIQUERY *query = NULL;
644     MSIRECORD *rec = NULL;
645     UINT r;
646 
647     TRACE( "%lu, %d, %p\n", hView, info, hRec );
648 
649     if( !hRec )
650         return ERROR_INVALID_PARAMETER;
651 
652     if( info != MSICOLINFO_NAMES && info != MSICOLINFO_TYPES )
653         return ERROR_INVALID_PARAMETER;
654 
655     query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
656     if (!query)
657     {
658         struct wire_record *wire_rec = NULL;
659         MSIHANDLE remote;
660 
661         if (!(remote = msi_get_remote(hView)))
662             return ERROR_INVALID_HANDLE;
663 
664         __TRY
665         {
666             r = remote_ViewGetColumnInfo(remote, info, &wire_rec);
667         }
668         __EXCEPT(rpc_filter)
669         {
670             r = GetExceptionCode();
671         }
672         __ENDTRY
673 
674         if (!r)
675         {
676             r = unmarshal_record(wire_rec, hRec);
677             free_remote_record(wire_rec);
678         }
679 
680         return r;
681     }
682 
683     r = MSI_ViewGetColumnInfo( query, info, &rec );
684     if ( r == ERROR_SUCCESS )
685     {
686         *hRec = alloc_msihandle( &rec->hdr );
687         if ( !*hRec )
688             r = ERROR_NOT_ENOUGH_MEMORY;
689         msiobj_release( &rec->hdr );
690     }
691 
692     msiobj_release( &query->hdr );
693 
694     return r;
695 }
696 
MSI_ViewModify(MSIQUERY * query,MSIMODIFY mode,MSIRECORD * rec)697 UINT MSI_ViewModify( MSIQUERY *query, MSIMODIFY mode, MSIRECORD *rec )
698 {
699     MSIVIEW *view = NULL;
700     UINT r;
701 
702     if ( !query || !rec )
703         return ERROR_INVALID_HANDLE;
704 
705     view = query->view;
706     if ( !view  || !view->ops->modify)
707         return ERROR_FUNCTION_FAILED;
708 
709     if ( mode == MSIMODIFY_UPDATE && rec->cookie != (UINT64)(ULONG_PTR)query )
710         return ERROR_FUNCTION_FAILED;
711 
712     r = view->ops->modify( view, mode, rec, query->row - 1 );
713     if (mode == MSIMODIFY_DELETE && r == ERROR_SUCCESS)
714         query->row--;
715 
716     return r;
717 }
718 
MsiViewModify(MSIHANDLE hView,MSIMODIFY eModifyMode,MSIHANDLE hRecord)719 UINT WINAPI MsiViewModify( MSIHANDLE hView, MSIMODIFY eModifyMode, MSIHANDLE hRecord )
720 {
721     MSIQUERY *query = NULL;
722     MSIRECORD *rec = NULL;
723     UINT r = ERROR_FUNCTION_FAILED;
724 
725     TRACE( "%lu, %#x, %lu\n", hView, eModifyMode, hRecord );
726 
727     rec = msihandle2msiinfo( hRecord, MSIHANDLETYPE_RECORD );
728 
729     if (!rec)
730         return ERROR_INVALID_HANDLE;
731 
732     query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
733     if (!query)
734     {
735         struct wire_record *wire_refreshed = NULL;
736         MSIHANDLE remote;
737 
738         if (!(remote = msi_get_remote(hView)))
739             return ERROR_INVALID_HANDLE;
740 
741         __TRY
742         {
743             r = remote_ViewModify(remote, eModifyMode,
744                 (struct wire_record *)&rec->count, &wire_refreshed);
745         }
746         __EXCEPT(rpc_filter)
747         {
748             r = GetExceptionCode();
749         }
750         __ENDTRY
751 
752         if (!r && (eModifyMode == MSIMODIFY_REFRESH || eModifyMode == MSIMODIFY_SEEK))
753         {
754             r = copy_remote_record(wire_refreshed, hRecord);
755             free_remote_record(wire_refreshed);
756         }
757 
758         msiobj_release(&rec->hdr);
759         return r;
760     }
761 
762     r = MSI_ViewModify( query, eModifyMode, rec );
763 
764     msiobj_release( &query->hdr );
765     msiobj_release(&rec->hdr);
766     return r;
767 }
768 
MsiViewGetErrorW(MSIHANDLE handle,WCHAR * buffer,DWORD * buflen)769 MSIDBERROR WINAPI MsiViewGetErrorW( MSIHANDLE handle, WCHAR *buffer, DWORD *buflen )
770 {
771     MSIQUERY *query;
772     const WCHAR *column;
773     MSIDBERROR r;
774 
775     TRACE( "%lu, %p, %p\n", handle, buffer, buflen );
776 
777     if (!buflen)
778         return MSIDBERROR_INVALIDARG;
779 
780     if (!(query = msihandle2msiinfo(handle, MSIHANDLETYPE_VIEW)))
781     {
782         WCHAR *remote_column = NULL;
783         MSIHANDLE remote;
784 
785         if (!(remote = msi_get_remote(handle)))
786             return MSIDBERROR_INVALIDARG;
787 
788         if (!*buflen)
789             return MSIDBERROR_FUNCTIONERROR;
790 
791         __TRY
792         {
793             r = remote_ViewGetError(remote, &remote_column);
794         }
795         __EXCEPT(rpc_filter)
796         {
797             r = GetExceptionCode();
798         }
799         __ENDTRY;
800 
801         if (msi_strncpyW(remote_column ? remote_column : L"", -1, buffer, buflen) == ERROR_MORE_DATA)
802             r = MSIDBERROR_MOREDATA;
803 
804         if (remote_column)
805             midl_user_free(remote_column);
806 
807         return r;
808     }
809 
810     if ((r = query->view->error)) column = query->view->error_column;
811     else column = L"";
812 
813     if (msi_strncpyW(column, -1, buffer, buflen) == ERROR_MORE_DATA)
814         r = MSIDBERROR_MOREDATA;
815 
816     msiobj_release( &query->hdr );
817     return r;
818 }
819 
MsiViewGetErrorA(MSIHANDLE handle,char * buffer,DWORD * buflen)820 MSIDBERROR WINAPI MsiViewGetErrorA( MSIHANDLE handle, char *buffer, DWORD *buflen )
821 {
822     MSIQUERY *query;
823     const WCHAR *column;
824     MSIDBERROR r;
825 
826     TRACE( "%lu, %p, %p\n", handle, buffer, buflen );
827 
828     if (!buflen)
829         return MSIDBERROR_INVALIDARG;
830 
831     if (!(query = msihandle2msiinfo(handle, MSIHANDLETYPE_VIEW)))
832     {
833         WCHAR *remote_column = NULL;
834         MSIHANDLE remote;
835 
836         if (!(remote = msi_get_remote(handle)))
837             return MSIDBERROR_INVALIDARG;
838 
839         if (!*buflen)
840             return MSIDBERROR_FUNCTIONERROR;
841 
842         __TRY
843         {
844             r = remote_ViewGetError(remote, &remote_column);
845         }
846         __EXCEPT(rpc_filter)
847         {
848             r = GetExceptionCode();
849         }
850         __ENDTRY;
851 
852         if (msi_strncpyWtoA(remote_column ? remote_column : L"", -1, buffer, buflen, FALSE) == ERROR_MORE_DATA)
853             r = MSIDBERROR_MOREDATA;
854 
855         if (remote_column)
856             midl_user_free(remote_column);
857 
858         return r;
859     }
860 
861     if ((r = query->view->error)) column = query->view->error_column;
862     else column = L"";
863 
864     if (msi_strncpyWtoA(column, -1, buffer, buflen, FALSE) == ERROR_MORE_DATA)
865         r = MSIDBERROR_MOREDATA;
866 
867     msiobj_release( &query->hdr );
868     return r;
869 }
870 
MsiGetLastErrorRecord(void)871 MSIHANDLE WINAPI MsiGetLastErrorRecord( void )
872 {
873     FIXME("\n");
874     return 0;
875 }
876 
MSI_DatabaseApplyTransformW(MSIDATABASE * db,const WCHAR * transform,int error_cond)877 UINT MSI_DatabaseApplyTransformW( MSIDATABASE *db, const WCHAR *transform, int error_cond )
878 {
879     HRESULT hr;
880     UINT ret = ERROR_FUNCTION_FAILED;
881     IStorage *stg;
882     STATSTG stat;
883 
884     TRACE( "%p %s %08x\n", db, debugstr_w(transform), error_cond );
885 
886     if (*transform == ':')
887     {
888         hr = IStorage_OpenStorage( db->storage, transform + 1, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
889         if (FAILED( hr ))
890         {
891             WARN( "failed to open substorage transform %#lx\n", hr );
892             return ERROR_FUNCTION_FAILED;
893         }
894     }
895     else
896     {
897         hr = StgOpenStorage( transform, NULL, STGM_DIRECT|STGM_READ|STGM_SHARE_DENY_WRITE, NULL, 0, &stg );
898         if (FAILED( hr ))
899         {
900             WARN( "failed to open file transform %#lx\n", hr );
901             return ERROR_FUNCTION_FAILED;
902         }
903     }
904 
905     hr = IStorage_Stat( stg, &stat, STATFLAG_NONAME );
906     if (FAILED( hr )) goto end;
907     if (!IsEqualGUID( &stat.clsid, &CLSID_MsiTransform )) goto end;
908     if (TRACE_ON( msi )) enum_stream_names( stg );
909 
910     ret = msi_table_apply_transform( db, stg, error_cond );
911 
912 end:
913     IStorage_Release( stg );
914     return ret;
915 }
916 
MsiDatabaseApplyTransformW(MSIHANDLE hdb,const WCHAR * transform,int error_cond)917 UINT WINAPI MsiDatabaseApplyTransformW( MSIHANDLE hdb, const WCHAR *transform, int error_cond )
918 {
919     MSIDATABASE *db;
920     UINT r;
921 
922     if (error_cond & ~MSITRANSFORM_ERROR_VIEWTRANSFORM) FIXME( "ignoring error conditions\n" );
923 
924     if (!(db = msihandle2msiinfo(hdb, MSIHANDLETYPE_DATABASE)))
925         return ERROR_INVALID_HANDLE;
926 
927     r = MSI_DatabaseApplyTransformW( db, transform, error_cond );
928     msiobj_release( &db->hdr );
929     return r;
930 }
931 
MsiDatabaseApplyTransformA(MSIHANDLE hdb,const char * transform,int error_cond)932 UINT WINAPI MsiDatabaseApplyTransformA( MSIHANDLE hdb, const char *transform, int error_cond )
933 {
934     WCHAR *wstr;
935     UINT ret;
936 
937     TRACE( "%lu, %s, %#x\n", hdb, debugstr_a(transform), error_cond );
938 
939     wstr = strdupAtoW( transform );
940     if (transform && !wstr)
941         return ERROR_NOT_ENOUGH_MEMORY;
942 
943     ret = MsiDatabaseApplyTransformW( hdb, wstr, error_cond );
944     free( wstr );
945     return ret;
946 }
947 
MsiDatabaseGenerateTransformA(MSIHANDLE hdb,MSIHANDLE hdbref,const char * szTransformFile,int iReserved1,int iReserved2)948 UINT WINAPI MsiDatabaseGenerateTransformA( MSIHANDLE hdb, MSIHANDLE hdbref, const char *szTransformFile,
949                                            int iReserved1, int iReserved2 )
950 {
951     FIXME( "%lu, %lu, %s, %d, %d\n", hdb, hdbref, debugstr_a(szTransformFile), iReserved1, iReserved2 );
952     return ERROR_CALL_NOT_IMPLEMENTED;
953 }
954 
MsiDatabaseGenerateTransformW(MSIHANDLE hdb,MSIHANDLE hdbref,const WCHAR * szTransformFile,int iReserved1,int iReserved2)955 UINT WINAPI MsiDatabaseGenerateTransformW( MSIHANDLE hdb, MSIHANDLE hdbref, const WCHAR *szTransformFile,
956                                            int iReserved1, int iReserved2 )
957 {
958     FIXME( "%lu, %lu, %s, %d, %d\n", hdb, hdbref, debugstr_w(szTransformFile), iReserved1, iReserved2 );
959     return ERROR_CALL_NOT_IMPLEMENTED;
960 }
961 
MsiDatabaseCommit(MSIHANDLE hdb)962 UINT WINAPI MsiDatabaseCommit( MSIHANDLE hdb )
963 {
964     MSIDATABASE *db;
965     UINT r;
966 
967     TRACE( "%lu\n", hdb );
968 
969     db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
970     if( !db )
971     {
972         MSIHANDLE remote;
973 
974         if (!(remote = msi_get_remote(hdb)))
975             return ERROR_INVALID_HANDLE;
976 
977         WARN("not allowed during a custom action!\n");
978 
979         return ERROR_SUCCESS;
980     }
981 
982     if (db->mode == MSI_OPEN_READONLY)
983     {
984         msiobj_release( &db->hdr );
985         return ERROR_SUCCESS;
986     }
987 
988     /* FIXME: lock the database */
989 
990     r = msi_commit_streams( db );
991     if (r != ERROR_SUCCESS) ERR("Failed to commit streams!\n");
992     else
993     {
994         r = MSI_CommitTables( db );
995         if (r != ERROR_SUCCESS) ERR("Failed to commit tables!\n");
996     }
997 
998     /* FIXME: unlock the database */
999 
1000     msiobj_release( &db->hdr );
1001 
1002     if (r == ERROR_SUCCESS)
1003     {
1004         free( db->deletefile );
1005         db->deletefile = NULL;
1006     }
1007 
1008     return r;
1009 }
1010 
1011 struct primary_key_record_info
1012 {
1013     DWORD n;
1014     MSIRECORD *rec;
1015 };
1016 
primary_key_iterator(MSIRECORD * rec,void * param)1017 static UINT primary_key_iterator( MSIRECORD *rec, void *param )
1018 {
1019     struct primary_key_record_info *info = param;
1020     LPCWSTR name, table;
1021     DWORD type;
1022 
1023     type = MSI_RecordGetInteger( rec, 4 );
1024     if( type & MSITYPE_KEY )
1025     {
1026         info->n++;
1027         if( info->rec )
1028         {
1029             if ( info->n == 1 )
1030             {
1031                 table = MSI_RecordGetString( rec, 1 );
1032                 MSI_RecordSetStringW( info->rec, 0, table);
1033             }
1034 
1035             name = MSI_RecordGetString( rec, 3 );
1036             MSI_RecordSetStringW( info->rec, info->n, name );
1037         }
1038     }
1039 
1040     return ERROR_SUCCESS;
1041 }
1042 
MSI_DatabaseGetPrimaryKeys(MSIDATABASE * db,const WCHAR * table,MSIRECORD ** prec)1043 UINT MSI_DatabaseGetPrimaryKeys( MSIDATABASE *db, const WCHAR *table, MSIRECORD **prec )
1044 {
1045     struct primary_key_record_info info;
1046     MSIQUERY *query = NULL;
1047     UINT r;
1048 
1049     if (!TABLE_Exists( db, table ))
1050         return ERROR_INVALID_TABLE;
1051 
1052     r = MSI_OpenQuery( db, &query, L"SELECT * FROM `_Columns` WHERE `Table` = '%s'", table );
1053     if( r != ERROR_SUCCESS )
1054         return r;
1055 
1056     /* count the number of primary key records */
1057     info.n = 0;
1058     info.rec = 0;
1059     r = MSI_IterateRecords( query, 0, primary_key_iterator, &info );
1060     if( r == ERROR_SUCCESS )
1061     {
1062         TRACE( "found %lu primary keys\n", info.n );
1063 
1064         /* allocate a record and fill in the names of the tables */
1065         info.rec = MSI_CreateRecord( info.n );
1066         info.n = 0;
1067         r = MSI_IterateRecords( query, 0, primary_key_iterator, &info );
1068         if( r == ERROR_SUCCESS )
1069             *prec = info.rec;
1070         else
1071             msiobj_release( &info.rec->hdr );
1072     }
1073     msiobj_release( &query->hdr );
1074 
1075     return r;
1076 }
1077 
MsiDatabaseGetPrimaryKeysW(MSIHANDLE hdb,const WCHAR * table,MSIHANDLE * phRec)1078 UINT WINAPI MsiDatabaseGetPrimaryKeysW( MSIHANDLE hdb, const WCHAR *table, MSIHANDLE *phRec )
1079 {
1080     MSIRECORD *rec = NULL;
1081     MSIDATABASE *db;
1082     UINT r;
1083 
1084     TRACE( "%lu, %s, %p\n", hdb, debugstr_w(table), phRec );
1085 
1086     db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
1087     if( !db )
1088     {
1089         struct wire_record *wire_rec = NULL;
1090         MSIHANDLE remote;
1091 
1092         if (!(remote = msi_get_remote(hdb)))
1093             return ERROR_INVALID_HANDLE;
1094 
1095         __TRY
1096         {
1097             r = remote_DatabaseGetPrimaryKeys(remote, table, &wire_rec);
1098         }
1099         __EXCEPT(rpc_filter)
1100         {
1101             r = GetExceptionCode();
1102         }
1103         __ENDTRY
1104 
1105         if (!r)
1106         {
1107             r = unmarshal_record(wire_rec, phRec);
1108             free_remote_record(wire_rec);
1109         }
1110 
1111         return r;
1112     }
1113 
1114     r = MSI_DatabaseGetPrimaryKeys( db, table, &rec );
1115     if( r == ERROR_SUCCESS )
1116     {
1117         *phRec = alloc_msihandle( &rec->hdr );
1118         if (! *phRec)
1119            r = ERROR_NOT_ENOUGH_MEMORY;
1120         msiobj_release( &rec->hdr );
1121     }
1122     msiobj_release( &db->hdr );
1123 
1124     return r;
1125 }
1126 
MsiDatabaseGetPrimaryKeysA(MSIHANDLE hdb,const char * table,MSIHANDLE * phRec)1127 UINT WINAPI MsiDatabaseGetPrimaryKeysA( MSIHANDLE hdb, const char *table, MSIHANDLE *phRec )
1128 {
1129     WCHAR *szwTable = NULL;
1130     UINT r;
1131 
1132     TRACE( "%lu, %s, %p\n", hdb, debugstr_a(table), phRec );
1133 
1134     if( table )
1135     {
1136         szwTable = strdupAtoW( table );
1137         if( !szwTable )
1138             return ERROR_OUTOFMEMORY;
1139     }
1140     r = MsiDatabaseGetPrimaryKeysW( hdb, szwTable, phRec );
1141     free( szwTable );
1142 
1143     return r;
1144 }
1145 
MsiDatabaseIsTablePersistentA(MSIHANDLE hDatabase,const char * szTableName)1146 MSICONDITION WINAPI MsiDatabaseIsTablePersistentA( MSIHANDLE hDatabase, const char *szTableName )
1147 {
1148     WCHAR *szwTableName = NULL;
1149     MSICONDITION r;
1150 
1151     TRACE( "%lu, %s\n", hDatabase, debugstr_a(szTableName) );
1152 
1153     if( szTableName )
1154     {
1155         szwTableName = strdupAtoW( szTableName );
1156         if( !szwTableName )
1157             return MSICONDITION_ERROR;
1158     }
1159     r = MsiDatabaseIsTablePersistentW( hDatabase, szwTableName );
1160     free( szwTableName );
1161 
1162     return r;
1163 }
1164 
MsiDatabaseIsTablePersistentW(MSIHANDLE hDatabase,const WCHAR * szTableName)1165 MSICONDITION WINAPI MsiDatabaseIsTablePersistentW( MSIHANDLE hDatabase, const WCHAR *szTableName )
1166 {
1167     MSIDATABASE *db;
1168     MSICONDITION r;
1169 
1170     TRACE( "%lu, %s\n", hDatabase, debugstr_w(szTableName) );
1171 
1172     db = msihandle2msiinfo( hDatabase, MSIHANDLETYPE_DATABASE );
1173     if( !db )
1174     {
1175         MSIHANDLE remote;
1176 
1177         if (!(remote = msi_get_remote(hDatabase)))
1178             return MSICONDITION_ERROR;
1179 
1180         __TRY
1181         {
1182             r = remote_DatabaseIsTablePersistent(remote, szTableName);
1183         }
1184         __EXCEPT(rpc_filter)
1185         {
1186             r = MSICONDITION_ERROR;
1187         }
1188         __ENDTRY
1189 
1190         return r;
1191     }
1192 
1193     r = MSI_DatabaseIsTablePersistent( db, szTableName );
1194 
1195     msiobj_release( &db->hdr );
1196 
1197     return r;
1198 }
1199 
s_remote_ViewClose(MSIHANDLE view)1200 UINT __cdecl s_remote_ViewClose(MSIHANDLE view)
1201 {
1202     return MsiViewClose(view);
1203 }
1204 
s_remote_ViewExecute(MSIHANDLE view,struct wire_record * remote_rec)1205 UINT __cdecl s_remote_ViewExecute(MSIHANDLE view, struct wire_record *remote_rec)
1206 {
1207     MSIHANDLE rec = 0;
1208     UINT r;
1209 
1210     if ((r = unmarshal_record(remote_rec, &rec)))
1211         return r;
1212 
1213     r = MsiViewExecute(view, rec);
1214 
1215     MsiCloseHandle(rec);
1216     return r;
1217 }
1218 
s_remote_ViewFetch(MSIHANDLE view,struct wire_record ** rec)1219 UINT __cdecl s_remote_ViewFetch(MSIHANDLE view, struct wire_record **rec)
1220 {
1221     MSIHANDLE handle;
1222     UINT r = MsiViewFetch(view, &handle);
1223     *rec = NULL;
1224     if (!r)
1225         *rec = marshal_record(handle);
1226     MsiCloseHandle(handle);
1227     return r;
1228 }
1229 
s_remote_ViewGetColumnInfo(MSIHANDLE view,MSICOLINFO info,struct wire_record ** rec)1230 UINT __cdecl s_remote_ViewGetColumnInfo(MSIHANDLE view, MSICOLINFO info, struct wire_record **rec)
1231 {
1232     MSIHANDLE handle;
1233     UINT r = MsiViewGetColumnInfo(view, info, &handle);
1234     *rec = NULL;
1235     if (!r)
1236         *rec = marshal_record(handle);
1237     MsiCloseHandle(handle);
1238     return r;
1239 }
1240 
s_remote_ViewGetError(MSIHANDLE view,LPWSTR * column)1241 MSIDBERROR __cdecl s_remote_ViewGetError(MSIHANDLE view, LPWSTR *column)
1242 {
1243     WCHAR empty[1];
1244     DWORD size = 1;
1245     UINT r;
1246 
1247     r = MsiViewGetErrorW(view, empty, &size);
1248     if (r == MSIDBERROR_MOREDATA)
1249     {
1250         if (!(*column = midl_user_allocate(++size * sizeof(WCHAR))))
1251             return MSIDBERROR_FUNCTIONERROR;
1252         r = MsiViewGetErrorW(view, *column, &size);
1253     }
1254     return r;
1255 }
1256 
s_remote_ViewModify(MSIHANDLE view,MSIMODIFY mode,struct wire_record * remote_rec,struct wire_record ** remote_refreshed)1257 UINT __cdecl s_remote_ViewModify(MSIHANDLE view, MSIMODIFY mode,
1258     struct wire_record *remote_rec, struct wire_record **remote_refreshed)
1259 {
1260     MSIHANDLE handle = 0;
1261     UINT r;
1262 
1263     if ((r = unmarshal_record(remote_rec, &handle)))
1264         return r;
1265 
1266     r = MsiViewModify(view, mode, handle);
1267     *remote_refreshed = NULL;
1268     if (!r && (mode == MSIMODIFY_REFRESH || mode == MSIMODIFY_SEEK))
1269         *remote_refreshed = marshal_record(handle);
1270 
1271     MsiCloseHandle(handle);
1272     return r;
1273 }
1274