kernel32: Return error on second attempt to free a module.
[wine] / dlls / msi / database.c
1 /*
2  * Implementation of the Microsoft Installer (msi.dll)
3  *
4  * Copyright 2002,2003,2004,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 #define NONAMELESSUNION
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winreg.h"
29 #include "winnls.h"
30 #include "wine/debug.h"
31 #include "wine/unicode.h"
32 #include "msi.h"
33 #include "msiquery.h"
34 #include "msipriv.h"
35 #include "objidl.h"
36 #include "objbase.h"
37 #include "msiserver.h"
38 #include "query.h"
39
40 #include "initguid.h"
41
42 WINE_DEFAULT_DEBUG_CHANNEL(msi);
43
44 /*
45  *  .MSI  file format
46  *
47  *  An .msi file is a structured storage file.
48  *  It contains a number of streams.
49  *  A stream for each table in the database.
50  *  Two streams for the string table in the database.
51  *  Any binary data in a table is a reference to a stream.
52  */
53
54 typedef struct tagMSITRANSFORM {
55     struct list entry;
56     IStorage *stg;
57 } MSITRANSFORM;
58
59 typedef struct tagMSISTREAM {
60     struct list entry;
61     IStream *stm;
62 } MSISTREAM;
63
64 static UINT find_open_stream( MSIDATABASE *db, LPCWSTR name, IStream **stm )
65 {
66     MSISTREAM *stream;
67
68     LIST_FOR_EACH_ENTRY( stream, &db->streams, MSISTREAM, entry )
69     {
70         HRESULT r;
71         STATSTG stat;
72
73         r = IStream_Stat( stream->stm, &stat, 0 );
74         if( FAILED( r ) )
75         {
76             WARN("failed to stat stream r = %08x!\n", r);
77             continue;
78         }
79
80         if( !lstrcmpW( name, stat.pwcsName ) )
81         {
82             TRACE("found %s\n", debugstr_w(name));
83             *stm = stream->stm;
84             CoTaskMemFree( stat.pwcsName );
85             return ERROR_SUCCESS;
86         }
87
88         CoTaskMemFree( stat.pwcsName );
89     }
90
91     return ERROR_FUNCTION_FAILED;
92 }
93
94 static UINT clone_open_stream( MSIDATABASE *db, LPCWSTR name, IStream **stm )
95 {
96     IStream *stream;
97
98     if (find_open_stream( db, name, &stream ) == ERROR_SUCCESS)
99     {
100         HRESULT r;
101         LARGE_INTEGER pos;
102
103         r = IStream_Clone( stream, stm );
104         if( FAILED( r ) )
105         {
106             WARN("failed to clone stream r = %08x!\n", r);
107             return ERROR_FUNCTION_FAILED;
108         }
109
110         pos.QuadPart = 0;
111         r = IStream_Seek( *stm, pos, STREAM_SEEK_SET, NULL );
112         if( FAILED( r ) )
113         {
114             IStream_Release( *stm );
115             return ERROR_FUNCTION_FAILED;
116         }
117
118         return ERROR_SUCCESS;
119     }
120
121     return ERROR_FUNCTION_FAILED;
122 }
123
124 UINT db_get_raw_stream( MSIDATABASE *db, LPCWSTR stname, IStream **stm )
125 {
126     LPWSTR encname;
127     HRESULT r;
128
129     encname = encode_streamname(FALSE, stname);
130
131     TRACE("%s -> %s\n",debugstr_w(stname),debugstr_w(encname));
132
133     if (clone_open_stream( db, encname, stm ) == ERROR_SUCCESS)
134     {
135         msi_free( encname );
136         return ERROR_SUCCESS;
137     }
138
139     r = IStorage_OpenStream( db->storage, encname, NULL,
140                              STGM_READ | STGM_SHARE_EXCLUSIVE, 0, stm );
141     if( FAILED( r ) )
142     {
143         MSITRANSFORM *transform;
144
145         LIST_FOR_EACH_ENTRY( transform, &db->transforms, MSITRANSFORM, entry )
146         {
147             TRACE("looking for %s in transform storage\n", debugstr_w(stname) );
148             r = IStorage_OpenStream( transform->stg, encname, NULL,
149                                      STGM_READ | STGM_SHARE_EXCLUSIVE, 0, stm );
150             if (SUCCEEDED(r))
151                 break;
152         }
153     }
154
155     msi_free( encname );
156
157     if( SUCCEEDED(r) )
158     {
159         MSISTREAM *stream;
160
161         stream = msi_alloc( sizeof(MSISTREAM) );
162         if( !stream )
163             return ERROR_NOT_ENOUGH_MEMORY;
164
165         stream->stm = *stm;
166         IStream_AddRef( *stm );
167         list_add_tail( &db->streams, &stream->entry );
168     }
169
170     return SUCCEEDED(r) ? ERROR_SUCCESS : ERROR_FUNCTION_FAILED;
171 }
172
173 UINT read_raw_stream_data( MSIDATABASE *db, LPCWSTR stname,
174                               USHORT **pdata, UINT *psz )
175 {
176     HRESULT r;
177     UINT ret = ERROR_FUNCTION_FAILED;
178     VOID *data;
179     ULONG sz, count;
180     IStream *stm = NULL;
181     STATSTG stat;
182
183     r = db_get_raw_stream( db, stname, &stm );
184     if( r != ERROR_SUCCESS)
185         return ret;
186     r = IStream_Stat(stm, &stat, STATFLAG_NONAME );
187     if( FAILED( r ) )
188     {
189         WARN("open stream failed r = %08x!\n", r);
190         goto end;
191     }
192
193     if( stat.cbSize.QuadPart >> 32 )
194     {
195         WARN("Too big!\n");
196         goto end;
197     }
198
199     sz = stat.cbSize.QuadPart;
200     data = msi_alloc( sz );
201     if( !data )
202     {
203         WARN("couldn't allocate memory r=%08x!\n", r);
204         ret = ERROR_NOT_ENOUGH_MEMORY;
205         goto end;
206     }
207
208     r = IStream_Read(stm, data, sz, &count );
209     if( FAILED( r ) || ( count != sz ) )
210     {
211         msi_free( data );
212         WARN("read stream failed r = %08x!\n", r);
213         goto end;
214     }
215
216     *pdata = data;
217     *psz = sz;
218     ret = ERROR_SUCCESS;
219
220 end:
221     IStream_Release( stm );
222
223     return ret;
224 }
225
226 void append_storage_to_db( MSIDATABASE *db, IStorage *stg )
227 {
228     MSITRANSFORM *t;
229
230     t = msi_alloc( sizeof *t );
231     t->stg = stg;
232     IStorage_AddRef( stg );
233     list_add_tail( &db->transforms, &t->entry );
234 }
235
236 static void free_transforms( MSIDATABASE *db )
237 {
238     while( !list_empty( &db->transforms ) )
239     {
240         MSITRANSFORM *t = LIST_ENTRY( list_head( &db->transforms ),
241                                       MSITRANSFORM, entry );
242         list_remove( &t->entry );
243         IStorage_Release( t->stg );
244         msi_free( t );
245     }
246 }
247
248 static void free_streams( MSIDATABASE *db )
249 {
250     while( !list_empty( &db->streams ) )
251     {
252         MSISTREAM *s = LIST_ENTRY( list_head( &db->streams ),
253                                    MSISTREAM, entry );
254         list_remove( &s->entry );
255         IStream_Release( s->stm );
256         msi_free( s );
257     }
258 }
259
260 static VOID MSI_CloseDatabase( MSIOBJECTHDR *arg )
261 {
262     MSIDATABASE *db = (MSIDATABASE *) arg;
263
264     msi_free(db->path);
265     free_cached_tables( db );
266     free_streams( db );
267     free_transforms( db );
268     msi_destroy_stringtable( db->strings );
269     IStorage_Release( db->storage );
270     if (db->deletefile)
271     {
272         DeleteFileW( db->deletefile );
273         msi_free( db->deletefile );
274     }
275     if (db->localfile)
276     {
277         DeleteFileW( db->localfile );
278         msi_free( db->localfile );
279     }
280 }
281
282 UINT MSI_OpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIDATABASE **pdb)
283 {
284     IStorage *stg = NULL;
285     HRESULT r;
286     MSIDATABASE *db = NULL;
287     UINT ret = ERROR_FUNCTION_FAILED;
288     LPCWSTR szMode, save_path;
289     STATSTG stat;
290     BOOL created = FALSE;
291     WCHAR path[MAX_PATH];
292
293     static const WCHAR szTables[]  = { '_','T','a','b','l','e','s',0 };
294
295     TRACE("%s %s\n",debugstr_w(szDBPath),debugstr_w(szPersist) );
296
297     if( !pdb )
298         return ERROR_INVALID_PARAMETER;
299
300     if (szPersist - MSIDBOPEN_PATCHFILE >= MSIDBOPEN_READONLY &&
301         szPersist - MSIDBOPEN_PATCHFILE <= MSIDBOPEN_CREATEDIRECT)
302     {
303         TRACE("Database is a patch\n");
304         szPersist -= MSIDBOPEN_PATCHFILE;
305     }
306
307     save_path = szDBPath;
308     szMode = szPersist;
309     if( HIWORD( szPersist ) )
310     {
311         if (!CopyFileW( szDBPath, szPersist, FALSE ))
312             return ERROR_OPEN_FAILED;
313
314         szDBPath = szPersist;
315         szPersist = MSIDBOPEN_TRANSACT;
316         created = TRUE;
317     }
318
319     if( szPersist == MSIDBOPEN_READONLY )
320     {
321         r = StgOpenStorage( szDBPath, NULL,
322               STGM_DIRECT|STGM_READ|STGM_SHARE_DENY_WRITE, NULL, 0, &stg);
323     }
324     else if( szPersist == MSIDBOPEN_CREATE || szPersist == MSIDBOPEN_CREATEDIRECT )
325     {
326         /* FIXME: MSIDBOPEN_CREATE should case STGM_TRANSACTED flag to be
327          * used here: */
328         r = StgCreateDocfile( szDBPath,
329               STGM_CREATE|STGM_DIRECT|STGM_READWRITE|STGM_SHARE_EXCLUSIVE, 0, &stg);
330         if( r == ERROR_SUCCESS )
331         {
332             IStorage_SetClass( stg, &CLSID_MsiDatabase );
333             /* create the _Tables stream */
334             r = write_stream_data(stg, szTables, NULL, 0, TRUE);
335             if (SUCCEEDED(r))
336                 r = msi_init_string_table( stg );
337         }
338         created = TRUE;
339     }
340     else if( szPersist == MSIDBOPEN_TRANSACT )
341     {
342         /* FIXME: MSIDBOPEN_TRANSACT should case STGM_TRANSACTED flag to be
343          * used here: */
344         r = StgOpenStorage( szDBPath, NULL,
345               STGM_DIRECT|STGM_READWRITE|STGM_SHARE_EXCLUSIVE, NULL, 0, &stg);
346     }
347     else if( szPersist == MSIDBOPEN_DIRECT )
348     {
349         r = StgOpenStorage( szDBPath, NULL,
350               STGM_DIRECT|STGM_READWRITE|STGM_SHARE_EXCLUSIVE, NULL, 0, &stg);
351     }
352     else
353     {
354         ERR("unknown flag %p\n",szPersist);
355         return ERROR_INVALID_PARAMETER;
356     }
357
358     if( FAILED( r ) || !stg )
359     {
360         FIXME("open failed r = %08x for %s\n", r, debugstr_w(szDBPath));
361         return ERROR_FUNCTION_FAILED;
362     }
363
364     r = IStorage_Stat( stg, &stat, STATFLAG_NONAME );
365     if( FAILED( r ) )
366     {
367         FIXME("Failed to stat storage\n");
368         goto end;
369     }
370
371     if ( !IsEqualGUID( &stat.clsid, &CLSID_MsiDatabase ) &&
372          !IsEqualGUID( &stat.clsid, &CLSID_MsiPatch ) &&
373          !IsEqualGUID( &stat.clsid, &CLSID_MsiTransform ) )
374     {
375         ERR("storage GUID is not a MSI database GUID %s\n",
376              debugstr_guid(&stat.clsid) );
377         goto end;
378     }
379
380     db = alloc_msiobject( MSIHANDLETYPE_DATABASE, sizeof (MSIDATABASE),
381                               MSI_CloseDatabase );
382     if( !db )
383     {
384         FIXME("Failed to allocate a handle\n");
385         goto end;
386     }
387
388     if (!strchrW( save_path, '\\' ))
389     {
390         GetCurrentDirectoryW( MAX_PATH, path );
391         lstrcatW( path, szBackSlash );
392         lstrcatW( path, save_path );
393     }
394     else
395         lstrcpyW( path, save_path );
396
397     db->path = strdupW( path );
398
399     if( TRACE_ON( msi ) )
400         enum_stream_names( stg );
401
402     db->storage = stg;
403     db->mode = szMode;
404     if (created)
405         db->deletefile = strdupW( szDBPath );
406     list_init( &db->tables );
407     list_init( &db->transforms );
408     list_init( &db->streams );
409
410     db->strings = msi_load_string_table( stg, &db->bytes_per_strref );
411     if( !db->strings )
412         goto end;
413
414     ret = ERROR_SUCCESS;
415
416     msiobj_addref( &db->hdr );
417     IStorage_AddRef( stg );
418     *pdb = db;
419
420 end:
421     if( db )
422         msiobj_release( &db->hdr );
423     if( stg )
424         IStorage_Release( stg );
425
426     return ret;
427 }
428
429 UINT WINAPI MsiOpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIHANDLE *phDB)
430 {
431     MSIDATABASE *db;
432     UINT ret;
433
434     TRACE("%s %s %p\n",debugstr_w(szDBPath),debugstr_w(szPersist), phDB);
435
436     ret = MSI_OpenDatabaseW( szDBPath, szPersist, &db );
437     if( ret == ERROR_SUCCESS )
438     {
439         *phDB = alloc_msihandle( &db->hdr );
440         if (! *phDB)
441             ret = ERROR_NOT_ENOUGH_MEMORY;
442         msiobj_release( &db->hdr );
443     }
444
445     return ret;
446 }
447
448 UINT WINAPI MsiOpenDatabaseA(LPCSTR szDBPath, LPCSTR szPersist, MSIHANDLE *phDB)
449 {
450     HRESULT r = ERROR_FUNCTION_FAILED;
451     LPWSTR szwDBPath = NULL, szwPersist = NULL;
452
453     TRACE("%s %s %p\n", debugstr_a(szDBPath), debugstr_a(szPersist), phDB);
454
455     if( szDBPath )
456     {
457         szwDBPath = strdupAtoW( szDBPath );
458         if( !szwDBPath )
459             goto end;
460     }
461
462     if( HIWORD(szPersist) )
463     {
464         szwPersist = strdupAtoW( szPersist );
465         if( !szwPersist )
466             goto end;
467     }
468     else
469         szwPersist = (LPWSTR)(DWORD_PTR)szPersist;
470
471     r = MsiOpenDatabaseW( szwDBPath, szwPersist, phDB );
472
473 end:
474     if( HIWORD(szPersist) )
475         msi_free( szwPersist );
476     msi_free( szwDBPath );
477
478     return r;
479 }
480
481 static LPWSTR msi_read_text_archive(LPCWSTR path)
482 {
483     HANDLE file;
484     LPSTR data = NULL;
485     LPWSTR wdata = NULL;
486     DWORD read, size = 0;
487
488     file = CreateFileW( path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
489     if (file == INVALID_HANDLE_VALUE)
490         return NULL;
491
492     size = GetFileSize( file, NULL );
493     data = msi_alloc( size + 1 );
494     if (!data)
495         goto done;
496
497     if (!ReadFile( file, data, size, &read, NULL ))
498         goto done;
499
500     data[size] = '\0';
501     wdata = strdupAtoW( data );
502
503 done:
504     CloseHandle( file );
505     msi_free( data );
506     return wdata;
507 }
508
509 static void msi_parse_line(LPWSTR *line, LPWSTR **entries, DWORD *num_entries)
510 {
511     LPWSTR ptr = *line, save;
512     DWORD i, count = 1;
513
514     *entries = NULL;
515
516     /* stay on this line */
517     while (*ptr && *ptr != '\n')
518     {
519         /* entries are separated by tabs */
520         if (*ptr == '\t')
521             count++;
522
523         ptr++;
524     }
525
526     *entries = msi_alloc(count * sizeof(LPWSTR));
527     if (!*entries)
528         return;
529
530     /* store pointers into the data */
531     for (i = 0, ptr = *line; i < count; i++)
532     {
533         while (*ptr && *ptr == '\r') ptr++;
534         save = ptr;
535
536         while (*ptr && *ptr != '\t' && *ptr != '\n' && *ptr != '\r') ptr++;
537
538         /* NULL-separate the data */
539         if (*ptr == '\n' || *ptr == '\r')
540         {
541             while (*ptr == '\n' || *ptr == '\r')
542                 *(ptr++) = '\0';
543         }
544         else if (*ptr)
545             *ptr++ = '\0';
546
547         (*entries)[i] = save;
548     }
549
550     /* move to the next line if there's more, else EOF */
551     *line = ptr;
552
553     if (num_entries)
554         *num_entries = count;
555 }
556
557 static LPWSTR msi_build_createsql_prelude(LPWSTR table)
558 {
559     LPWSTR prelude;
560     DWORD size;
561
562     static const WCHAR create_fmt[] = {'C','R','E','A','T','E',' ','T','A','B','L','E',' ','`','%','s','`',' ','(',' ',0};
563
564     size = sizeof(create_fmt)/sizeof(create_fmt[0]) + lstrlenW(table) - 2;
565     prelude = msi_alloc(size * sizeof(WCHAR));
566     if (!prelude)
567         return NULL;
568
569     sprintfW(prelude, create_fmt, table);
570     return prelude;
571 }
572
573 static LPWSTR msi_build_createsql_columns(LPWSTR *columns_data, LPWSTR *types, DWORD num_columns)
574 {
575     LPWSTR columns, p;
576     LPCWSTR type;
577     DWORD sql_size = 1, i, len;
578     WCHAR expanded[128], *ptr;
579     WCHAR size[10], comma[2], extra[30];
580
581     static const WCHAR column_fmt[] = {'`','%','s','`',' ','%','s','%','s','%','s','%','s',' ',0};
582     static const WCHAR size_fmt[] = {'(','%','s',')',0};
583     static const WCHAR type_char[] = {'C','H','A','R',0};
584     static const WCHAR type_int[] = {'I','N','T',0};
585     static const WCHAR type_long[] = {'L','O','N','G',0};
586     static const WCHAR type_object[] = {'O','B','J','E','C','T',0};
587     static const WCHAR type_notnull[] = {' ','N','O','T',' ','N','U','L','L',0};
588     static const WCHAR localizable[] = {' ','L','O','C','A','L','I','Z','A','B','L','E',0};
589
590     columns = msi_alloc_zero(sql_size * sizeof(WCHAR));
591     if (!columns)
592         return NULL;
593
594     for (i = 0; i < num_columns; i++)
595     {
596         type = NULL;
597         comma[1] = size[0] = extra[0] = '\0';
598
599         if (i == num_columns - 1)
600             comma[0] = '\0';
601         else
602             comma[0] = ',';
603
604         ptr = &types[i][1];
605         len = atolW(ptr);
606         extra[0] = '\0';
607
608         switch (types[i][0])
609         {
610             case 'l':
611                 lstrcpyW(extra, type_notnull);
612             case 'L':
613                 lstrcatW(extra, localizable);
614                 type = type_char;
615                 sprintfW(size, size_fmt, ptr);
616                 break;
617             case 's':
618                 lstrcpyW(extra, type_notnull);
619             case 'S':
620                 type = type_char;
621                 sprintfW(size, size_fmt, ptr);
622                 break;
623             case 'i':
624                 lstrcpyW(extra, type_notnull);
625             case 'I':
626                 if (len <= 2)
627                     type = type_int;
628                 else if (len == 4)
629                     type = type_long;
630                 else
631                 {
632                     WARN("invalid int width %u\n", len);
633                     msi_free(columns);
634                     return NULL;
635                 }
636                 break;
637             case 'v':
638                 lstrcpyW(extra, type_notnull);
639             case 'V':
640                 type = type_object;
641                 break;
642             default:
643                 ERR("Unknown type: %c\n", types[i][0]);
644                 msi_free(columns);
645                 return NULL;
646         }
647
648         sprintfW(expanded, column_fmt, columns_data[i], type, size, extra, comma);
649         sql_size += lstrlenW(expanded);
650
651         p = msi_realloc(columns, sql_size * sizeof(WCHAR));
652         if (!p)
653         {
654             msi_free(columns);
655             return NULL;
656         }
657         columns = p;
658
659         lstrcatW(columns, expanded);
660     }
661
662     return columns;
663 }
664
665 static LPWSTR msi_build_createsql_postlude(LPWSTR *primary_keys, DWORD num_keys)
666 {
667     LPWSTR postlude, keys, ptr;
668     DWORD size, key_size, i;
669
670     static const WCHAR key_fmt[] = {'`','%','s','`',',',' ',0};
671     static const WCHAR postlude_fmt[] = {'P','R','I','M','A','R','Y',' ','K','E','Y',' ','%','s',')',0};
672
673     for (i = 0, size = 1; i < num_keys; i++)
674         size += lstrlenW(key_fmt) + lstrlenW(primary_keys[i]) - 2;
675
676     keys = msi_alloc(size * sizeof(WCHAR));
677     if (!keys)
678         return NULL;
679
680     for (i = 0, ptr = keys; i < num_keys; i++)
681     {
682         key_size = lstrlenW(key_fmt) + lstrlenW(primary_keys[i]) -2;
683         sprintfW(ptr, key_fmt, primary_keys[i]);
684         ptr += key_size;
685     }
686
687     /* remove final ', ' */
688     *(ptr - 2) = '\0';
689
690     size = lstrlenW(postlude_fmt) + size - 1;
691     postlude = msi_alloc(size * sizeof(WCHAR));
692     if (!postlude)
693         goto done;
694
695     sprintfW(postlude, postlude_fmt, keys);
696
697 done:
698     msi_free(keys);
699     return postlude;
700 }
701
702 static UINT msi_add_table_to_db(MSIDATABASE *db, LPWSTR *columns, LPWSTR *types, LPWSTR *labels, DWORD num_labels, DWORD num_columns)
703 {
704     UINT r = ERROR_OUTOFMEMORY;
705     DWORD size;
706     MSIQUERY *view;
707     LPWSTR create_sql = NULL;
708     LPWSTR prelude, columns_sql, postlude;
709
710     prelude = msi_build_createsql_prelude(labels[0]);
711     columns_sql = msi_build_createsql_columns(columns, types, num_columns);
712     postlude = msi_build_createsql_postlude(labels + 1, num_labels - 1); /* skip over table name */
713
714     if (!prelude || !columns_sql || !postlude)
715         goto done;
716
717     size = lstrlenW(prelude) + lstrlenW(columns_sql) + lstrlenW(postlude) + 1;
718     create_sql = msi_alloc(size * sizeof(WCHAR));
719     if (!create_sql)
720         goto done;
721
722     lstrcpyW(create_sql, prelude);
723     lstrcatW(create_sql, columns_sql);
724     lstrcatW(create_sql, postlude);
725
726     r = MSI_DatabaseOpenViewW( db, create_sql, &view );
727     if (r != ERROR_SUCCESS)
728         goto done;
729
730     r = MSI_ViewExecute(view, NULL);
731     MSI_ViewClose(view);
732     msiobj_release(&view->hdr);
733
734 done:
735     msi_free(prelude);
736     msi_free(columns_sql);
737     msi_free(postlude);
738     msi_free(create_sql);
739     return r;
740 }
741
742 static LPWSTR msi_import_stream_filename(LPCWSTR path, LPCWSTR name)
743 {
744     DWORD len;
745     LPWSTR fullname, ptr;
746
747     len = lstrlenW(path) + lstrlenW(name) + 1;
748     fullname = msi_alloc(len*sizeof(WCHAR));
749     if (!fullname)
750        return NULL;
751
752     lstrcpyW( fullname, path );
753
754     /* chop off extension from path */
755     ptr = strrchrW(fullname, '.');
756     if (!ptr)
757     {
758         msi_free (fullname);
759         return NULL;
760     }
761     *ptr++ = '\\';
762     lstrcpyW( ptr, name );
763     return fullname;
764 }
765
766 static UINT construct_record(DWORD num_columns, LPWSTR *types,
767                              LPWSTR *data, LPWSTR path, MSIRECORD **rec)
768 {
769     UINT i;
770
771     *rec = MSI_CreateRecord(num_columns);
772     if (!*rec)
773         return ERROR_OUTOFMEMORY;
774
775     for (i = 0; i < num_columns; i++)
776     {
777         switch (types[i][0])
778         {
779             case 'L': case 'l': case 'S': case 's':
780                 MSI_RecordSetStringW(*rec, i + 1, data[i]);
781                 break;
782             case 'I': case 'i':
783                 if (*data[i])
784                     MSI_RecordSetInteger(*rec, i + 1, atoiW(data[i]));
785                 break;
786             case 'V': case 'v':
787                 if (*data[i])
788                 {
789                     UINT r;
790                     LPWSTR file = msi_import_stream_filename(path, data[i]);
791                     if (!file)
792                         return ERROR_FUNCTION_FAILED;
793
794                     r = MSI_RecordSetStreamFromFileW(*rec, i + 1, file);
795                     msi_free (file);
796                     if (r != ERROR_SUCCESS)
797                         return ERROR_FUNCTION_FAILED;
798                 }
799                 break;
800             default:
801                 ERR("Unhandled column type: %c\n", types[i][0]);
802                 msiobj_release(&(*rec)->hdr);
803                 return ERROR_FUNCTION_FAILED;
804         }
805     }
806
807     return ERROR_SUCCESS;
808 }
809
810 static UINT msi_add_records_to_table(MSIDATABASE *db, LPWSTR *columns, LPWSTR *types,
811                                      LPWSTR *labels, LPWSTR **records,
812                                      int num_columns, int num_records,
813                                      LPWSTR path)
814 {
815     UINT r;
816     int i;
817     MSIQUERY *view;
818     MSIRECORD *rec;
819
820     static const WCHAR select[] = {
821         'S','E','L','E','C','T',' ','*',' ',
822         'F','R','O','M',' ','`','%','s','`',0
823     };
824
825     r = MSI_OpenQuery(db, &view, select, labels[0]);
826     if (r != ERROR_SUCCESS)
827         return r;
828
829     while (MSI_ViewFetch(view, &rec) != ERROR_NO_MORE_ITEMS)
830     {
831         r = MSI_ViewModify(view, MSIMODIFY_DELETE, rec);
832         msiobj_release(&rec->hdr);
833         if (r != ERROR_SUCCESS)
834             goto done;
835     }
836
837     for (i = 0; i < num_records; i++)
838     {
839         r = construct_record(num_columns, types, records[i], path, &rec);
840         if (r != ERROR_SUCCESS)
841             goto done;
842
843         r = MSI_ViewModify(view, MSIMODIFY_INSERT, rec);
844         if (r != ERROR_SUCCESS)
845         {
846             msiobj_release(&rec->hdr);
847             goto done;
848         }
849
850         msiobj_release(&rec->hdr);
851     }
852
853 done:
854     msiobj_release(&view->hdr);
855     return r;
856 }
857
858 static UINT MSI_DatabaseImport(MSIDATABASE *db, LPCWSTR folder, LPCWSTR file)
859 {
860     UINT r;
861     DWORD len, i;
862     DWORD num_labels, num_types;
863     DWORD num_columns, num_records = 0;
864     LPWSTR *columns, *types, *labels;
865     LPWSTR path, ptr, data;
866     LPWSTR **records = NULL;
867     LPWSTR **temp_records;
868
869     static const WCHAR suminfo[] =
870         {'_','S','u','m','m','a','r','y','I','n','f','o','r','m','a','t','i','o','n',0};
871
872     TRACE("%p %s %s\n", db, debugstr_w(folder), debugstr_w(file) );
873
874     if( folder == NULL || file == NULL )
875         return ERROR_INVALID_PARAMETER;
876
877     len = lstrlenW(folder) + lstrlenW(szBackSlash) + lstrlenW(file) + 1;
878     path = msi_alloc( len * sizeof(WCHAR) );
879     if (!path)
880         return ERROR_OUTOFMEMORY;
881
882     lstrcpyW( path, folder );
883     lstrcatW( path, szBackSlash );
884     lstrcatW( path, file );
885
886     data = msi_read_text_archive( path );
887
888     ptr = data;
889     msi_parse_line( &ptr, &columns, &num_columns );
890     msi_parse_line( &ptr, &types, &num_types );
891     msi_parse_line( &ptr, &labels, &num_labels );
892
893     if (num_columns != num_types)
894     {
895         r = ERROR_FUNCTION_FAILED;
896         goto done;
897     }
898
899     records = msi_alloc(sizeof(LPWSTR *));
900     if (!records)
901     {
902         r = ERROR_OUTOFMEMORY;
903         goto done;
904     }
905
906     /* read in the table records */
907     while (*ptr)
908     {
909         msi_parse_line( &ptr, &records[num_records], NULL );
910
911         num_records++;
912         temp_records = msi_realloc(records, (num_records + 1) * sizeof(LPWSTR *));
913         if (!temp_records)
914         {
915             r = ERROR_OUTOFMEMORY;
916             goto done;
917         }
918         records = temp_records;
919     }
920
921     if (!strcmpW(labels[0], suminfo))
922     {
923         r = msi_add_suminfo( db, records, num_records, num_columns );
924         if (r != ERROR_SUCCESS)
925         {
926             r = ERROR_FUNCTION_FAILED;
927             goto done;
928         }
929     }
930     else
931     {
932         if (!TABLE_Exists(db, labels[0]))
933         {
934             r = msi_add_table_to_db( db, columns, types, labels, num_labels, num_columns );
935             if (r != ERROR_SUCCESS)
936             {
937                 r = ERROR_FUNCTION_FAILED;
938                 goto done;
939             }
940         }
941
942         r = msi_add_records_to_table( db, columns, types, labels, records, num_columns, num_records, path );
943     }
944
945 done:
946     msi_free(path);
947     msi_free(data);
948     msi_free(columns);
949     msi_free(types);
950     msi_free(labels);
951
952     for (i = 0; i < num_records; i++)
953         msi_free(records[i]);
954
955     msi_free(records);
956
957     return r;
958 }
959
960 UINT WINAPI MsiDatabaseImportW(MSIHANDLE handle, LPCWSTR szFolder, LPCWSTR szFilename)
961 {
962     MSIDATABASE *db;
963     UINT r;
964
965     TRACE("%x %s %s\n",handle,debugstr_w(szFolder), debugstr_w(szFilename));
966
967     db = msihandle2msiinfo( handle, MSIHANDLETYPE_DATABASE );
968     if( !db )
969     {
970         IWineMsiRemoteDatabase *remote_database;
971
972         remote_database = (IWineMsiRemoteDatabase *)msi_get_remote( handle );
973         if ( !remote_database )
974             return ERROR_INVALID_HANDLE;
975
976         IWineMsiRemoteDatabase_Release( remote_database );
977         WARN("MsiDatabaseImport not allowed during a custom action!\n");
978
979         return ERROR_SUCCESS;
980     }
981
982     r = MSI_DatabaseImport( db, szFolder, szFilename );
983     msiobj_release( &db->hdr );
984     return r;
985 }
986
987 UINT WINAPI MsiDatabaseImportA( MSIHANDLE handle,
988                LPCSTR szFolder, LPCSTR szFilename )
989 {
990     LPWSTR path = NULL, file = NULL;
991     UINT r = ERROR_OUTOFMEMORY;
992
993     TRACE("%x %s %s\n", handle, debugstr_a(szFolder), debugstr_a(szFilename));
994
995     if( szFolder )
996     {
997         path = strdupAtoW( szFolder );
998         if( !path )
999             goto end;
1000     }
1001
1002     if( szFilename )
1003     {
1004         file = strdupAtoW( szFilename );
1005         if( !file )
1006             goto end;
1007     }
1008
1009     r = MsiDatabaseImportW( handle, path, file );
1010
1011 end:
1012     msi_free( path );
1013     msi_free( file );
1014
1015     return r;
1016 }
1017
1018 static UINT msi_export_record( HANDLE handle, MSIRECORD *row, UINT start )
1019 {
1020     UINT i, count, len, r = ERROR_SUCCESS;
1021     const char *sep;
1022     char *buffer;
1023     DWORD sz;
1024
1025     len = 0x100;
1026     buffer = msi_alloc( len );
1027     if ( !buffer )
1028         return ERROR_OUTOFMEMORY;
1029
1030     count = MSI_RecordGetFieldCount( row );
1031     for ( i=start; i<=count; i++ )
1032     {
1033         sz = len;
1034         r = MSI_RecordGetStringA( row, i, buffer, &sz );
1035         if (r == ERROR_MORE_DATA)
1036         {
1037             char *p = msi_realloc( buffer, sz + 1 );
1038             if (!p)
1039                 break;
1040             len = sz + 1;
1041             buffer = p;
1042         }
1043         sz = len;
1044         r = MSI_RecordGetStringA( row, i, buffer, &sz );
1045         if (r != ERROR_SUCCESS)
1046             break;
1047
1048         if (!WriteFile( handle, buffer, sz, &sz, NULL ))
1049         {
1050             r = ERROR_FUNCTION_FAILED;
1051             break;
1052         }
1053
1054         sep = (i < count) ? "\t" : "\r\n";
1055         if (!WriteFile( handle, sep, strlen(sep), &sz, NULL ))
1056         {
1057             r = ERROR_FUNCTION_FAILED;
1058             break;
1059         }
1060     }
1061     msi_free( buffer );
1062     return r;
1063 }
1064
1065 static UINT msi_export_row( MSIRECORD *row, void *arg )
1066 {
1067     return msi_export_record( arg, row, 1 );
1068 }
1069
1070 static UINT msi_export_forcecodepage( HANDLE handle )
1071 {
1072     DWORD sz;
1073
1074     static const char data[] = "\r\n\r\n0\t_ForceCodepage\r\n";
1075
1076     FIXME("Read the codepage from the strings table!\n");
1077
1078     sz = lstrlenA(data) + 1;
1079     if (!WriteFile(handle, data, sz, &sz, NULL))
1080         return ERROR_FUNCTION_FAILED;
1081
1082     return ERROR_SUCCESS;
1083 }
1084
1085 static UINT MSI_DatabaseExport( MSIDATABASE *db, LPCWSTR table,
1086                LPCWSTR folder, LPCWSTR file )
1087 {
1088     static const WCHAR query[] = {
1089         's','e','l','e','c','t',' ','*',' ','f','r','o','m',' ','%','s',0 };
1090     static const WCHAR forcecodepage[] = {
1091         '_','F','o','r','c','e','C','o','d','e','p','a','g','e',0 };
1092     MSIRECORD *rec = NULL;
1093     MSIQUERY *view = NULL;
1094     LPWSTR filename;
1095     HANDLE handle;
1096     UINT len, r;
1097
1098     TRACE("%p %s %s %s\n", db, debugstr_w(table),
1099           debugstr_w(folder), debugstr_w(file) );
1100
1101     if( folder == NULL || file == NULL )
1102         return ERROR_INVALID_PARAMETER;
1103
1104     len = lstrlenW(folder) + lstrlenW(file) + 2;
1105     filename = msi_alloc(len * sizeof (WCHAR));
1106     if (!filename)
1107         return ERROR_OUTOFMEMORY;
1108
1109     lstrcpyW( filename, folder );
1110     lstrcatW( filename, szBackSlash );
1111     lstrcatW( filename, file );
1112
1113     handle = CreateFileW( filename, GENERIC_READ | GENERIC_WRITE, 0,
1114                           NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
1115     msi_free( filename );
1116     if (handle == INVALID_HANDLE_VALUE)
1117         return ERROR_FUNCTION_FAILED;
1118
1119     if (!lstrcmpW( table, forcecodepage ))
1120     {
1121         r = msi_export_forcecodepage( handle );
1122         goto done;
1123     }
1124
1125     r = MSI_OpenQuery( db, &view, query, table );
1126     if (r == ERROR_SUCCESS)
1127     {
1128         /* write out row 1, the column names */
1129         r = MSI_ViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec);
1130         if (r == ERROR_SUCCESS)
1131         {
1132             msi_export_record( handle, rec, 1 );
1133             msiobj_release( &rec->hdr );
1134         }
1135
1136         /* write out row 2, the column types */
1137         r = MSI_ViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
1138         if (r == ERROR_SUCCESS)
1139         {
1140             msi_export_record( handle, rec, 1 );
1141             msiobj_release( &rec->hdr );
1142         }
1143
1144         /* write out row 3, the table name + keys */
1145         r = MSI_DatabaseGetPrimaryKeys( db, table, &rec );
1146         if (r == ERROR_SUCCESS)
1147         {
1148             MSI_RecordSetStringW( rec, 0, table );
1149             msi_export_record( handle, rec, 0 );
1150             msiobj_release( &rec->hdr );
1151         }
1152
1153         /* write out row 4 onwards, the data */
1154         r = MSI_IterateRecords( view, 0, msi_export_row, handle );
1155         msiobj_release( &view->hdr );
1156     }
1157
1158 done:
1159     CloseHandle( handle );
1160     return r;
1161 }
1162
1163 /***********************************************************************
1164  * MsiExportDatabaseW        [MSI.@]
1165  *
1166  * Writes a file containing the table data as tab separated ASCII.
1167  *
1168  * The format is as follows:
1169  *
1170  * row1 : colname1 <tab> colname2 <tab> .... colnameN <cr> <lf>
1171  * row2 : coltype1 <tab> coltype2 <tab> .... coltypeN <cr> <lf>
1172  * row3 : tablename <tab> key1 <tab> key2 <tab> ... keyM <cr> <lf>
1173  *
1174  * Followed by the data, starting at row 1 with one row per line
1175  *
1176  * row4 : data <tab> data <tab> data <tab> ... data <cr> <lf>
1177  */
1178 UINT WINAPI MsiDatabaseExportW( MSIHANDLE handle, LPCWSTR szTable,
1179                LPCWSTR szFolder, LPCWSTR szFilename )
1180 {
1181     MSIDATABASE *db;
1182     UINT r;
1183
1184     TRACE("%x %s %s %s\n", handle, debugstr_w(szTable),
1185           debugstr_w(szFolder), debugstr_w(szFilename));
1186
1187     db = msihandle2msiinfo( handle, MSIHANDLETYPE_DATABASE );
1188     if( !db )
1189     {
1190         IWineMsiRemoteDatabase *remote_database;
1191
1192         remote_database = (IWineMsiRemoteDatabase *)msi_get_remote( handle );
1193         if ( !remote_database )
1194             return ERROR_INVALID_HANDLE;
1195
1196         IWineMsiRemoteDatabase_Release( remote_database );
1197         WARN("MsiDatabaseExport not allowed during a custom action!\n");
1198
1199         return ERROR_SUCCESS;
1200     }
1201
1202     r = MSI_DatabaseExport( db, szTable, szFolder, szFilename );
1203     msiobj_release( &db->hdr );
1204     return r;
1205 }
1206
1207 UINT WINAPI MsiDatabaseExportA( MSIHANDLE handle, LPCSTR szTable,
1208                LPCSTR szFolder, LPCSTR szFilename )
1209 {
1210     LPWSTR path = NULL, file = NULL, table = NULL;
1211     UINT r = ERROR_OUTOFMEMORY;
1212
1213     TRACE("%x %s %s %s\n", handle, debugstr_a(szTable),
1214           debugstr_a(szFolder), debugstr_a(szFilename));
1215
1216     if( szTable )
1217     {
1218         table = strdupAtoW( szTable );
1219         if( !table )
1220             goto end;
1221     }
1222
1223     if( szFolder )
1224     {
1225         path = strdupAtoW( szFolder );
1226         if( !path )
1227             goto end;
1228     }
1229
1230     if( szFilename )
1231     {
1232         file = strdupAtoW( szFilename );
1233         if( !file )
1234             goto end;
1235     }
1236
1237     r = MsiDatabaseExportW( handle, table, path, file );
1238
1239 end:
1240     msi_free( table );
1241     msi_free( path );
1242     msi_free( file );
1243
1244     return r;
1245 }
1246
1247 UINT WINAPI MsiDatabaseMergeA(MSIHANDLE hDatabase, MSIHANDLE hDatabaseMerge,
1248                               LPCSTR szTableName)
1249 {
1250     UINT r;
1251     LPWSTR table;
1252
1253     TRACE("(%d, %d, %s)\n", hDatabase, hDatabaseMerge,
1254           debugstr_a(szTableName));
1255
1256     table = strdupAtoW(szTableName);
1257     r = MsiDatabaseMergeW(hDatabase, hDatabaseMerge, table);
1258
1259     msi_free(table);
1260     return r;
1261 }
1262
1263 typedef struct _tagMERGETABLE
1264 {
1265     struct list entry;
1266     struct list rows;
1267     LPWSTR name;
1268     DWORD numconflicts;
1269     LPWSTR *columns;
1270     DWORD numcolumns;
1271     LPWSTR *types;
1272     DWORD numtypes;
1273     LPWSTR *labels;
1274     DWORD numlabels;
1275 } MERGETABLE;
1276
1277 typedef struct _tagMERGEROW
1278 {
1279     struct list entry;
1280     MSIRECORD *data;
1281 } MERGEROW;
1282
1283 typedef struct _tagMERGEDATA
1284 {
1285     MSIDATABASE *db;
1286     MSIDATABASE *merge;
1287     MERGETABLE *curtable;
1288     MSIQUERY *curview;
1289     struct list *tabledata;
1290 } MERGEDATA;
1291
1292 static BOOL merge_type_match(LPCWSTR type1, LPCWSTR type2)
1293 {
1294     if (((type1[0] == 'l') || (type1[0] == 's')) &&
1295         ((type2[0] == 'l') || (type2[0] == 's')))
1296         return TRUE;
1297
1298     if (((type1[0] == 'L') || (type1[0] == 'S')) &&
1299         ((type2[0] == 'L') || (type2[0] == 'S')))
1300         return TRUE;
1301
1302     return !lstrcmpW(type1, type2);
1303 }
1304
1305 static UINT merge_verify_colnames(MSIQUERY *dbview, MSIQUERY *mergeview)
1306 {
1307     MSIRECORD *dbrec, *mergerec;
1308     UINT r, i, count;
1309
1310     r = MSI_ViewGetColumnInfo(dbview, MSICOLINFO_NAMES, &dbrec);
1311     if (r != ERROR_SUCCESS)
1312         return r;
1313
1314     r = MSI_ViewGetColumnInfo(mergeview, MSICOLINFO_NAMES, &mergerec);
1315     if (r != ERROR_SUCCESS)
1316         return r;
1317
1318     count = MSI_RecordGetFieldCount(dbrec);
1319     for (i = 1; i <= count; i++)
1320     {
1321         if (!MSI_RecordGetString(mergerec, i))
1322             break;
1323
1324         if (lstrcmpW(MSI_RecordGetString(dbrec, i),
1325                      MSI_RecordGetString(mergerec, i)))
1326         {
1327             r = ERROR_DATATYPE_MISMATCH;
1328             goto done;
1329         }
1330     }
1331
1332     msiobj_release(&dbrec->hdr);
1333     msiobj_release(&mergerec->hdr);
1334     dbrec = mergerec = NULL;
1335
1336     r = MSI_ViewGetColumnInfo(dbview, MSICOLINFO_TYPES, &dbrec);
1337     if (r != ERROR_SUCCESS)
1338         return r;
1339
1340     r = MSI_ViewGetColumnInfo(mergeview, MSICOLINFO_TYPES, &mergerec);
1341     if (r != ERROR_SUCCESS)
1342         return r;
1343
1344     count = MSI_RecordGetFieldCount(dbrec);
1345     for (i = 1; i <= count; i++)
1346     {
1347         if (!MSI_RecordGetString(mergerec, i))
1348             break;
1349
1350         if (!merge_type_match(MSI_RecordGetString(dbrec, i),
1351                      MSI_RecordGetString(mergerec, i)))
1352         {
1353             r = ERROR_DATATYPE_MISMATCH;
1354             break;
1355         }
1356     }
1357
1358 done:
1359     msiobj_release(&dbrec->hdr);
1360     msiobj_release(&mergerec->hdr);
1361
1362     return r;
1363 }
1364
1365 static UINT merge_verify_primary_keys(MSIDATABASE *db, MSIDATABASE *mergedb,
1366                                       LPCWSTR table)
1367 {
1368     MSIRECORD *dbrec, *mergerec = NULL;
1369     UINT r, i, count;
1370
1371     r = MSI_DatabaseGetPrimaryKeys(db, table, &dbrec);
1372     if (r != ERROR_SUCCESS)
1373         return r;
1374
1375     r = MSI_DatabaseGetPrimaryKeys(mergedb, table, &mergerec);
1376     if (r != ERROR_SUCCESS)
1377         goto done;
1378
1379     count = MSI_RecordGetFieldCount(dbrec);
1380     if (count != MSI_RecordGetFieldCount(mergerec))
1381     {
1382         r = ERROR_DATATYPE_MISMATCH;
1383         goto done;
1384     }
1385
1386     for (i = 1; i <= count; i++)
1387     {
1388         if (lstrcmpW(MSI_RecordGetString(dbrec, i),
1389                      MSI_RecordGetString(mergerec, i)))
1390         {
1391             r = ERROR_DATATYPE_MISMATCH;
1392             goto done;
1393         }
1394     }
1395
1396 done:
1397     msiobj_release(&dbrec->hdr);
1398     msiobj_release(&mergerec->hdr);
1399
1400     return r;
1401 }
1402
1403 static LPWSTR get_key_value(MSIQUERY *view, LPCWSTR key, MSIRECORD *rec)
1404 {
1405     MSIRECORD *colnames;
1406     LPWSTR str, val;
1407     UINT r, i = 0, sz = 0;
1408     int cmp;
1409
1410     r = MSI_ViewGetColumnInfo(view, MSICOLINFO_NAMES, &colnames);
1411     if (r != ERROR_SUCCESS)
1412         return NULL;
1413
1414     do
1415     {
1416         str = msi_dup_record_field(colnames, ++i);
1417         cmp = lstrcmpW(key, str);
1418         msi_free(str);
1419     } while (cmp);
1420
1421     msiobj_release(&colnames->hdr);
1422
1423     r = MSI_RecordGetStringW(rec, i, NULL, &sz);
1424     if (r != ERROR_SUCCESS)
1425         return NULL;
1426     sz++;
1427
1428     if (MSI_RecordGetString(rec, i))  /* check record field is a string */
1429     {
1430         /* quote string record fields */
1431         const WCHAR szQuote[] = {'\'', 0};
1432         sz += 2;
1433         val = msi_alloc(sz*sizeof(WCHAR));
1434         if (!val)
1435             return NULL;
1436
1437         lstrcpyW(val, szQuote);
1438         r = MSI_RecordGetStringW(rec, i, val+1, &sz);
1439         lstrcpyW(val+1+sz, szQuote);
1440     }
1441     else
1442     {
1443         /* do not quote integer record fields */
1444         val = msi_alloc(sz*sizeof(WCHAR));
1445         if (!val)
1446             return NULL;
1447
1448         r = MSI_RecordGetStringW(rec, i, val, &sz);
1449     }
1450
1451     if (r != ERROR_SUCCESS)
1452     {
1453         ERR("failed to get string!\n");
1454         msi_free(val);
1455         return NULL;
1456     }
1457
1458     return val;
1459 }
1460
1461 static LPWSTR create_diff_row_query(MSIDATABASE *merge, MSIQUERY *view,
1462                                     LPWSTR table, MSIRECORD *rec)
1463 {
1464     LPWSTR query = NULL, clause = NULL;
1465     LPWSTR ptr = NULL, val;
1466     LPCWSTR setptr;
1467     DWORD size = 1, oldsize;
1468     LPCWSTR key;
1469     MSIRECORD *keys;
1470     UINT r, i, count;
1471
1472     static const WCHAR keyset[] = {
1473         '`','%','s','`',' ','=',' ','%','s',' ','A','N','D',' ',0};
1474     static const WCHAR lastkeyset[] = {
1475         '`','%','s','`',' ','=',' ','%','s',' ',0};
1476     static const WCHAR fmt[] = {'S','E','L','E','C','T',' ','*',' ',
1477         'F','R','O','M',' ','`','%','s','`',' ',
1478         'W','H','E','R','E',' ','%','s',0};
1479
1480     r = MSI_DatabaseGetPrimaryKeys(merge, table, &keys);
1481     if (r != ERROR_SUCCESS)
1482         return NULL;
1483
1484     clause = msi_alloc_zero(size * sizeof(WCHAR));
1485     if (!clause)
1486         goto done;
1487
1488     ptr = clause;
1489     count = MSI_RecordGetFieldCount(keys);
1490     for (i = 1; i <= count; i++)
1491     {
1492         key = MSI_RecordGetString(keys, i);
1493         val = get_key_value(view, key, rec);
1494
1495         if (i == count)
1496             setptr = lastkeyset;
1497         else
1498             setptr = keyset;
1499
1500         oldsize = size;
1501         size += lstrlenW(setptr) + lstrlenW(key) + lstrlenW(val) - 4;
1502         clause = msi_realloc(clause, size * sizeof (WCHAR));
1503         if (!clause)
1504         {
1505             msi_free(val);
1506             goto done;
1507         }
1508
1509         ptr = clause + oldsize - 1;
1510         sprintfW(ptr, setptr, key, val);
1511         msi_free(val);
1512     }
1513
1514     size = lstrlenW(fmt) + lstrlenW(table) + lstrlenW(clause) + 1;
1515     query = msi_alloc(size * sizeof(WCHAR));
1516     if (!query)
1517         goto done;
1518
1519     sprintfW(query, fmt, table, clause);
1520
1521 done:
1522     msi_free(clause);
1523     msiobj_release(&keys->hdr);
1524     return query;
1525 }
1526
1527 static UINT merge_diff_row(MSIRECORD *rec, LPVOID param)
1528 {
1529     MERGEDATA *data = param;
1530     MERGETABLE *table = data->curtable;
1531     MERGEROW *mergerow;
1532     MSIQUERY *dbview = NULL;
1533     MSIRECORD *row = NULL;
1534     LPWSTR query = NULL;
1535     UINT r = ERROR_SUCCESS;
1536
1537     if (TABLE_Exists(data->db, table->name))
1538     {
1539         query = create_diff_row_query(data->merge, data->curview, table->name, rec);
1540         if (!query)
1541             return ERROR_OUTOFMEMORY;
1542
1543         r = MSI_DatabaseOpenViewW(data->db, query, &dbview);
1544         if (r != ERROR_SUCCESS)
1545             goto done;
1546
1547         r = MSI_ViewExecute(dbview, NULL);
1548         if (r != ERROR_SUCCESS)
1549             goto done;
1550
1551         r = MSI_ViewFetch(dbview, &row);
1552         if (r == ERROR_SUCCESS && !MSI_RecordsAreEqual(rec, row))
1553         {
1554             table->numconflicts++;
1555             goto done;
1556         }
1557         else if (r != ERROR_NO_MORE_ITEMS)
1558             goto done;
1559
1560         r = ERROR_SUCCESS;
1561     }
1562
1563     mergerow = msi_alloc(sizeof(MERGEROW));
1564     if (!mergerow)
1565     {
1566         r = ERROR_OUTOFMEMORY;
1567         goto done;
1568     }
1569
1570     mergerow->data = MSI_CloneRecord(rec);
1571     if (!mergerow->data)
1572     {
1573         r = ERROR_OUTOFMEMORY;
1574         msi_free(mergerow);
1575         goto done;
1576     }
1577
1578     list_add_tail(&table->rows, &mergerow->entry);
1579
1580 done:
1581     msi_free(query);
1582     msiobj_release(&row->hdr);
1583     msiobj_release(&dbview->hdr);
1584     return r;
1585 }
1586
1587 static UINT msi_get_table_labels(MSIDATABASE *db, LPCWSTR table, LPWSTR **labels, DWORD *numlabels)
1588 {
1589     UINT r, i, count;
1590     MSIRECORD *prec = NULL;
1591
1592     r = MSI_DatabaseGetPrimaryKeys(db, table, &prec);
1593     if (r != ERROR_SUCCESS)
1594         return r;
1595
1596     count = MSI_RecordGetFieldCount(prec);
1597     *numlabels = count + 1;
1598     *labels = msi_alloc((*numlabels)*sizeof(LPWSTR));
1599     if (!*labels)
1600     {
1601         r = ERROR_OUTOFMEMORY;
1602         goto end;
1603     }
1604
1605     (*labels)[0] = strdupW(table);
1606     for (i=1; i<=count; i++ )
1607     {
1608         (*labels)[i] = strdupW(MSI_RecordGetString(prec, i));
1609     }
1610
1611 end:
1612     msiobj_release( &prec->hdr );
1613     return r;
1614 }
1615
1616 static UINT msi_get_query_columns(MSIQUERY *query, LPWSTR **columns, DWORD *numcolumns)
1617 {
1618     UINT r, i, count;
1619     MSIRECORD *prec = NULL;
1620
1621     r = MSI_ViewGetColumnInfo(query, MSICOLINFO_NAMES, &prec);
1622     if (r != ERROR_SUCCESS)
1623         return r;
1624
1625     count = MSI_RecordGetFieldCount(prec);
1626     *columns = msi_alloc(count*sizeof(LPWSTR));
1627     if (!*columns)
1628     {
1629         r = ERROR_OUTOFMEMORY;
1630         goto end;
1631     }
1632
1633     for (i=1; i<=count; i++ )
1634     {
1635         (*columns)[i-1] = strdupW(MSI_RecordGetString(prec, i));
1636     }
1637
1638     *numcolumns = count;
1639
1640 end:
1641     msiobj_release( &prec->hdr );
1642     return r;
1643 }
1644
1645 static UINT msi_get_query_types(MSIQUERY *query, LPWSTR **types, DWORD *numtypes)
1646 {
1647     UINT r, i, count;
1648     MSIRECORD *prec = NULL;
1649
1650     r = MSI_ViewGetColumnInfo(query, MSICOLINFO_TYPES, &prec);
1651     if (r != ERROR_SUCCESS)
1652         return r;
1653
1654     count = MSI_RecordGetFieldCount(prec);
1655     *types = msi_alloc(count*sizeof(LPWSTR));
1656     if (!*types)
1657     {
1658         r = ERROR_OUTOFMEMORY;
1659         goto end;
1660     }
1661
1662     *numtypes = count;
1663     for (i=1; i<=count; i++ )
1664     {
1665         (*types)[i-1] = strdupW(MSI_RecordGetString(prec, i));
1666     }
1667
1668 end:
1669     msiobj_release( &prec->hdr );
1670     return r;
1671 }
1672
1673 static void merge_free_rows(MERGETABLE *table)
1674 {
1675     struct list *item, *cursor;
1676
1677     LIST_FOR_EACH_SAFE(item, cursor, &table->rows)
1678     {
1679         MERGEROW *row = LIST_ENTRY(item, MERGEROW, entry);
1680
1681         list_remove(&row->entry);
1682         msiobj_release(&row->data->hdr);
1683         msi_free(row);
1684     }
1685 }
1686
1687 static void free_merge_table(MERGETABLE *table)
1688 {
1689     UINT i;
1690
1691     if (table->labels != NULL)
1692     {
1693         for (i = 0; i < table->numlabels; i++)
1694             msi_free(table->labels[i]);
1695
1696         msi_free(table->labels);
1697     }
1698
1699     if (table->columns != NULL)
1700     {
1701         for (i = 0; i < table->numcolumns; i++)
1702             msi_free(table->columns[i]);
1703
1704         msi_free(table->columns);
1705     }
1706
1707     if (table->types != NULL)
1708     {
1709         for (i = 0; i < table->numtypes; i++)
1710             msi_free(table->types[i]);
1711
1712         msi_free(table->types);
1713     }
1714
1715     msi_free(table->name);
1716     merge_free_rows(table);
1717
1718     msi_free(table);
1719 }
1720
1721 static UINT msi_get_merge_table (MSIDATABASE *db, LPCWSTR name, MERGETABLE **ptable)
1722 {
1723     UINT r;
1724     MERGETABLE *table;
1725     MSIQUERY *mergeview = NULL;
1726
1727     static const WCHAR query[] = {'S','E','L','E','C','T',' ','*',' ',
1728         'F','R','O','M',' ','`','%','s','`',0};
1729
1730     table = msi_alloc_zero(sizeof(MERGETABLE));
1731     if (!table)
1732     {
1733        *ptable = NULL;
1734        return ERROR_OUTOFMEMORY;
1735     }
1736
1737     r = msi_get_table_labels(db, name, &table->labels, &table->numlabels);
1738     if (r != ERROR_SUCCESS)
1739         goto err;
1740
1741     r = MSI_OpenQuery(db, &mergeview, query, name);
1742     if (r != ERROR_SUCCESS)
1743         goto err;
1744
1745     r = msi_get_query_columns(mergeview, &table->columns, &table->numcolumns);
1746     if (r != ERROR_SUCCESS)
1747         goto err;
1748
1749     r = msi_get_query_types(mergeview, &table->types, &table->numtypes);
1750     if (r != ERROR_SUCCESS)
1751         goto err;
1752
1753     list_init(&table->rows);
1754
1755     table->name = strdupW(name);
1756     table->numconflicts = 0;
1757
1758     msiobj_release(&mergeview->hdr);
1759     *ptable = table;
1760     return ERROR_SUCCESS;
1761
1762 err:
1763     msiobj_release(&mergeview->hdr);
1764     free_merge_table(table);
1765     *ptable = NULL;
1766     return r;
1767 }
1768
1769 static UINT merge_diff_tables(MSIRECORD *rec, LPVOID param)
1770 {
1771     MERGEDATA *data = param;
1772     MERGETABLE *table;
1773     MSIQUERY *dbview = NULL;
1774     MSIQUERY *mergeview = NULL;
1775     LPCWSTR name;
1776     UINT r;
1777
1778     static const WCHAR query[] = {'S','E','L','E','C','T',' ','*',' ',
1779         'F','R','O','M',' ','`','%','s','`',0};
1780
1781     name = MSI_RecordGetString(rec, 1);
1782
1783     r = MSI_OpenQuery(data->merge, &mergeview, query, name);
1784     if (r != ERROR_SUCCESS)
1785         goto done;
1786
1787     if (TABLE_Exists(data->db, name))
1788     {
1789         r = MSI_OpenQuery(data->db, &dbview, query, name);
1790         if (r != ERROR_SUCCESS)
1791             goto done;
1792
1793         r = merge_verify_colnames(dbview, mergeview);
1794         if (r != ERROR_SUCCESS)
1795             goto done;
1796
1797         r = merge_verify_primary_keys(data->db, data->merge, name);
1798         if (r != ERROR_SUCCESS)
1799             goto done;
1800     }
1801
1802     r = msi_get_merge_table(data->merge, name, &table);
1803     if (r != ERROR_SUCCESS)
1804         goto done;
1805
1806     data->curtable = table;
1807     data->curview = mergeview;
1808     r = MSI_IterateRecords(mergeview, NULL, merge_diff_row, data);
1809     if (r != ERROR_SUCCESS)
1810     {
1811         free_merge_table(table);
1812         goto done;
1813     }
1814
1815     list_add_tail(data->tabledata, &table->entry);
1816
1817 done:
1818     msiobj_release(&dbview->hdr);
1819     msiobj_release(&mergeview->hdr);
1820     return r;
1821 }
1822
1823 static UINT gather_merge_data(MSIDATABASE *db, MSIDATABASE *merge,
1824                               struct list *tabledata)
1825 {
1826     UINT r;
1827     MSIQUERY *view;
1828     MERGEDATA data;
1829
1830     static const WCHAR query[] = {'S','E','L','E','C','T',' ','*',' ',
1831         'F','R','O','M',' ','`','_','T','a','b','l','e','s','`',0};
1832
1833     r = MSI_DatabaseOpenViewW(merge, query, &view);
1834     if (r != ERROR_SUCCESS)
1835         return r;
1836
1837     data.db = db;
1838     data.merge = merge;
1839     data.tabledata = tabledata;
1840     r = MSI_IterateRecords(view, NULL, merge_diff_tables, &data);
1841
1842     msiobj_release(&view->hdr);
1843     return r;
1844 }
1845
1846 static UINT merge_table(MSIDATABASE *db, MERGETABLE *table)
1847 {
1848     UINT r;
1849     MERGEROW *row;
1850     MSIVIEW *tv;
1851
1852     if (!TABLE_Exists(db, table->name))
1853     {
1854         r = msi_add_table_to_db(db, table->columns, table->types,
1855                table->labels, table->numlabels, table->numcolumns);
1856         if (r != ERROR_SUCCESS)
1857            return ERROR_FUNCTION_FAILED;
1858     }
1859
1860     LIST_FOR_EACH_ENTRY(row, &table->rows, MERGEROW, entry)
1861     {
1862         r = TABLE_CreateView(db, table->name, &tv);
1863         if (r != ERROR_SUCCESS)
1864             return r;
1865
1866         r = tv->ops->insert_row(tv, row->data, -1, FALSE);
1867         tv->ops->delete(tv);
1868
1869         if (r != ERROR_SUCCESS)
1870             return r;
1871     }
1872
1873     return ERROR_SUCCESS;
1874 }
1875
1876 static UINT update_merge_errors(MSIDATABASE *db, LPCWSTR error,
1877                                 LPWSTR table, DWORD numconflicts)
1878 {
1879     UINT r;
1880     MSIQUERY *view;
1881
1882     static const WCHAR create[] = {
1883         'C','R','E','A','T','E',' ','T','A','B','L','E',' ',
1884         '`','%','s','`',' ','(','`','T','a','b','l','e','`',' ',
1885         'C','H','A','R','(','2','5','5',')',' ','N','O','T',' ',
1886         'N','U','L','L',',',' ','`','N','u','m','R','o','w','M','e','r','g','e',
1887         'C','o','n','f','l','i','c','t','s','`',' ','S','H','O','R','T',' ',
1888         'N','O','T',' ','N','U','L','L',' ','P','R','I','M','A','R','Y',' ',
1889         'K','E','Y',' ','`','T','a','b','l','e','`',')',0};
1890     static const WCHAR insert[] = {
1891         'I','N','S','E','R','T',' ','I','N','T','O',' ',
1892         '`','%','s','`',' ','(','`','T','a','b','l','e','`',',',' ',
1893         '`','N','u','m','R','o','w','M','e','r','g','e',
1894         'C','o','n','f','l','i','c','t','s','`',')',' ','V','A','L','U','E','S',
1895         ' ','(','\'','%','s','\'',',',' ','%','d',')',0};
1896
1897     if (!TABLE_Exists(db, error))
1898     {
1899         r = MSI_OpenQuery(db, &view, create, error);
1900         if (r != ERROR_SUCCESS)
1901             return r;
1902
1903         r = MSI_ViewExecute(view, NULL);
1904         msiobj_release(&view->hdr);
1905         if (r != ERROR_SUCCESS)
1906             return r;
1907     }
1908
1909     r = MSI_OpenQuery(db, &view, insert, error, table, numconflicts);
1910     if (r != ERROR_SUCCESS)
1911         return r;
1912
1913     r = MSI_ViewExecute(view, NULL);
1914     msiobj_release(&view->hdr);
1915     return r;
1916 }
1917
1918 UINT WINAPI MsiDatabaseMergeW(MSIHANDLE hDatabase, MSIHANDLE hDatabaseMerge,
1919                               LPCWSTR szTableName)
1920 {
1921     struct list tabledata = LIST_INIT(tabledata);
1922     struct list *item, *cursor;
1923     MSIDATABASE *db, *merge;
1924     MERGETABLE *table;
1925     BOOL conflicts;
1926     UINT r;
1927
1928     TRACE("(%d, %d, %s)\n", hDatabase, hDatabaseMerge,
1929           debugstr_w(szTableName));
1930
1931     if (szTableName && !*szTableName)
1932         return ERROR_INVALID_TABLE;
1933
1934     db = msihandle2msiinfo(hDatabase, MSIHANDLETYPE_DATABASE);
1935     merge = msihandle2msiinfo(hDatabaseMerge, MSIHANDLETYPE_DATABASE);
1936     if (!db || !merge)
1937     {
1938         r = ERROR_INVALID_HANDLE;
1939         goto done;
1940     }
1941
1942     r = gather_merge_data(db, merge, &tabledata);
1943     if (r != ERROR_SUCCESS)
1944         goto done;
1945
1946     conflicts = FALSE;
1947     LIST_FOR_EACH_ENTRY(table, &tabledata, MERGETABLE, entry)
1948     {
1949         if (table->numconflicts)
1950         {
1951             conflicts = TRUE;
1952
1953             r = update_merge_errors(db, szTableName, table->name,
1954                                     table->numconflicts);
1955             if (r != ERROR_SUCCESS)
1956                 break;
1957         }
1958         else
1959         {
1960             r = merge_table(db, table);
1961             if (r != ERROR_SUCCESS)
1962                 break;
1963         }
1964     }
1965
1966     LIST_FOR_EACH_SAFE(item, cursor, &tabledata)
1967     {
1968         MERGETABLE *table = LIST_ENTRY(item, MERGETABLE, entry);
1969         list_remove(&table->entry);
1970         free_merge_table(table);
1971     }
1972
1973     if (conflicts)
1974         r = ERROR_FUNCTION_FAILED;
1975
1976 done:
1977     msiobj_release(&db->hdr);
1978     msiobj_release(&merge->hdr);
1979     return r;
1980 }
1981
1982 MSIDBSTATE WINAPI MsiGetDatabaseState( MSIHANDLE handle )
1983 {
1984     MSIDBSTATE ret = MSIDBSTATE_READ;
1985     MSIDATABASE *db;
1986
1987     TRACE("%d\n", handle);
1988
1989     db = msihandle2msiinfo( handle, MSIHANDLETYPE_DATABASE );
1990     if( !db )
1991     {
1992         IWineMsiRemoteDatabase *remote_database;
1993
1994         remote_database = (IWineMsiRemoteDatabase *)msi_get_remote( handle );
1995         if ( !remote_database )
1996             return MSIDBSTATE_ERROR;
1997
1998         IWineMsiRemoteDatabase_Release( remote_database );
1999         WARN("MsiGetDatabaseState not allowed during a custom action!\n");
2000
2001         return MSIDBSTATE_READ;
2002     }
2003
2004     if (db->mode != MSIDBOPEN_READONLY )
2005         ret = MSIDBSTATE_WRITE;
2006     msiobj_release( &db->hdr );
2007
2008     return ret;
2009 }
2010
2011 typedef struct _msi_remote_database_impl {
2012     const IWineMsiRemoteDatabaseVtbl *lpVtbl;
2013     MSIHANDLE database;
2014     LONG refs;
2015 } msi_remote_database_impl;
2016
2017 static inline msi_remote_database_impl* mrd_from_IWineMsiRemoteDatabase( IWineMsiRemoteDatabase* iface )
2018 {
2019     return (msi_remote_database_impl *)iface;
2020 }
2021
2022 static HRESULT WINAPI mrd_QueryInterface( IWineMsiRemoteDatabase *iface,
2023                                           REFIID riid,LPVOID *ppobj)
2024 {
2025     if( IsEqualCLSID( riid, &IID_IUnknown ) ||
2026         IsEqualCLSID( riid, &IID_IWineMsiRemoteDatabase ) )
2027     {
2028         IUnknown_AddRef( iface );
2029         *ppobj = iface;
2030         return S_OK;
2031     }
2032
2033     return E_NOINTERFACE;
2034 }
2035
2036 static ULONG WINAPI mrd_AddRef( IWineMsiRemoteDatabase *iface )
2037 {
2038     msi_remote_database_impl* This = mrd_from_IWineMsiRemoteDatabase( iface );
2039
2040     return InterlockedIncrement( &This->refs );
2041 }
2042
2043 static ULONG WINAPI mrd_Release( IWineMsiRemoteDatabase *iface )
2044 {
2045     msi_remote_database_impl* This = mrd_from_IWineMsiRemoteDatabase( iface );
2046     ULONG r;
2047
2048     r = InterlockedDecrement( &This->refs );
2049     if (r == 0)
2050     {
2051         MsiCloseHandle( This->database );
2052         msi_free( This );
2053     }
2054     return r;
2055 }
2056
2057 static HRESULT WINAPI mrd_IsTablePersistent( IWineMsiRemoteDatabase *iface,
2058                                              BSTR table, MSICONDITION *persistent )
2059 {
2060     msi_remote_database_impl *This = mrd_from_IWineMsiRemoteDatabase( iface );
2061     *persistent = MsiDatabaseIsTablePersistentW(This->database, table);
2062     return S_OK;
2063 }
2064
2065 static HRESULT WINAPI mrd_GetPrimaryKeys( IWineMsiRemoteDatabase *iface,
2066                                           BSTR table, MSIHANDLE *keys )
2067 {
2068     msi_remote_database_impl *This = mrd_from_IWineMsiRemoteDatabase( iface );
2069     UINT r = MsiDatabaseGetPrimaryKeysW(This->database, table, keys);
2070     return HRESULT_FROM_WIN32(r);
2071 }
2072
2073 static HRESULT WINAPI mrd_GetSummaryInformation( IWineMsiRemoteDatabase *iface,
2074                                                 UINT updatecount, MSIHANDLE *suminfo )
2075 {
2076     msi_remote_database_impl *This = mrd_from_IWineMsiRemoteDatabase( iface );
2077     UINT r = MsiGetSummaryInformationW(This->database, NULL, updatecount, suminfo);
2078     return HRESULT_FROM_WIN32(r);
2079 }
2080
2081 static HRESULT WINAPI mrd_OpenView( IWineMsiRemoteDatabase *iface,
2082                                     BSTR query, MSIHANDLE *view )
2083 {
2084     msi_remote_database_impl *This = mrd_from_IWineMsiRemoteDatabase( iface );
2085     UINT r = MsiDatabaseOpenViewW(This->database, query, view);
2086     return HRESULT_FROM_WIN32(r);
2087 }
2088
2089 static HRESULT WINAPI mrd_SetMsiHandle( IWineMsiRemoteDatabase *iface, MSIHANDLE handle )
2090 {
2091     msi_remote_database_impl* This = mrd_from_IWineMsiRemoteDatabase( iface );
2092     This->database = handle;
2093     return S_OK;
2094 }
2095
2096 static const IWineMsiRemoteDatabaseVtbl msi_remote_database_vtbl =
2097 {
2098     mrd_QueryInterface,
2099     mrd_AddRef,
2100     mrd_Release,
2101     mrd_IsTablePersistent,
2102     mrd_GetPrimaryKeys,
2103     mrd_GetSummaryInformation,
2104     mrd_OpenView,
2105     mrd_SetMsiHandle,
2106 };
2107
2108 HRESULT create_msi_remote_database( IUnknown *pOuter, LPVOID *ppObj )
2109 {
2110     msi_remote_database_impl *This;
2111
2112     This = msi_alloc( sizeof *This );
2113     if (!This)
2114         return E_OUTOFMEMORY;
2115
2116     This->lpVtbl = &msi_remote_database_vtbl;
2117     This->database = 0;
2118     This->refs = 1;
2119
2120     *ppObj = This;
2121
2122     return S_OK;
2123 }