msi: Handle adding columns in transforms.
[wine] / dlls / msi / table.c
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 #include <assert.h>
23
24 #define COBJMACROS
25 #define NONAMELESSUNION
26 #define NONAMELESSSTRUCT
27
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winerror.h"
31 #include "msi.h"
32 #include "msiquery.h"
33 #include "objbase.h"
34 #include "objidl.h"
35 #include "winnls.h"
36 #include "msipriv.h"
37 #include "query.h"
38
39 #include "wine/debug.h"
40 #include "wine/unicode.h"
41
42 WINE_DEFAULT_DEBUG_CHANNEL(msidb);
43
44 #define MSITABLE_HASH_TABLE_SIZE 37
45 #define LONG_STR_BYTES 3
46
47 typedef struct tagMSICOLUMNHASHENTRY
48 {
49     struct tagMSICOLUMNHASHENTRY *next;
50     UINT value;
51     UINT row;
52 } MSICOLUMNHASHENTRY;
53
54 typedef struct tagMSICOLUMNINFO
55 {
56     LPCWSTR tablename;
57     UINT   number;
58     LPCWSTR colname;
59     UINT   type;
60     UINT   offset;
61     MSICOLUMNHASHENTRY **hash_table;
62 } MSICOLUMNINFO;
63
64 struct tagMSITABLE
65 {
66     BYTE **data;
67     UINT row_count;
68     BYTE **nonpersistent_data;
69     UINT nonpersistent_row_count;
70     struct list entry;
71     MSICOLUMNINFO *colinfo;
72     UINT col_count;
73     BOOL persistent;
74     WCHAR name[1];
75 };
76
77 typedef struct tagMSITRANSFORM {
78     struct list entry;
79     IStorage *stg;
80 } MSITRANSFORM;
81
82 static const WCHAR szStringData[] = {
83     '_','S','t','r','i','n','g','D','a','t','a',0 };
84 static const WCHAR szStringPool[] = {
85     '_','S','t','r','i','n','g','P','o','o','l',0 };
86
87 /* information for default tables */
88 static const WCHAR szTables[]  = { '_','T','a','b','l','e','s',0 };
89 static const WCHAR szTable[]  = { 'T','a','b','l','e',0 };
90 static const WCHAR szName[]    = { 'N','a','m','e',0 };
91 static const WCHAR szColumns[] = { '_','C','o','l','u','m','n','s',0 };
92 static const WCHAR szNumber[]  = { 'N','u','m','b','e','r',0 };
93 static const WCHAR szType[]    = { 'T','y','p','e',0 };
94
95 /* These tables are written into (the .hash_table part).
96  * Do not mark them const.
97  */
98 static MSICOLUMNINFO _Columns_cols[4] = {
99     { szColumns, 1, szTable,  MSITYPE_VALID | MSITYPE_STRING | 64, 0 },
100     { szColumns, 2, szNumber, MSITYPE_VALID | 2,                   2 },
101     { szColumns, 3, szName,   MSITYPE_VALID | MSITYPE_STRING | 64, 4 },
102     { szColumns, 4, szType,   MSITYPE_VALID | 2,                   6 },
103 };
104 static MSICOLUMNINFO _Tables_cols[1] = {
105     { szTables,  1, szName,   MSITYPE_VALID | MSITYPE_STRING | 64, 0 },
106 };
107
108 #define MAX_STREAM_NAME 0x1f
109
110 static UINT table_get_column_info( MSIDATABASE *db, LPCWSTR name,
111        MSICOLUMNINFO **pcols, UINT *pcount );
112 static void table_calc_column_offsets( MSICOLUMNINFO *colinfo, DWORD count );
113 static UINT get_tablecolumns( MSIDATABASE *db,
114        LPCWSTR szTableName, MSICOLUMNINFO *colinfo, UINT *sz);
115 static void msi_free_colinfo( MSICOLUMNINFO *colinfo, UINT count );
116
117
118 void msi_table_set_strref(UINT bytes_per_strref)
119 {
120     _Columns_cols[0].offset = 0;
121     _Columns_cols[1].offset = bytes_per_strref;
122     _Columns_cols[2].offset = _Columns_cols[1].offset + sizeof(USHORT);
123     _Columns_cols[3].offset = _Columns_cols[2].offset + bytes_per_strref;
124 }
125
126 static inline UINT bytes_per_column( const MSICOLUMNINFO *col )
127 {
128     if( MSITYPE_IS_BINARY(col->type) )
129         return 2;
130     if( col->type & MSITYPE_STRING )
131         return _Columns_cols[1].offset;
132     if( (col->type & 0xff) > 4 )
133         ERR("Invalid column size!\n");
134     return col->type & 0xff;
135 }
136
137 static int utf2mime(int x)
138 {
139     if( (x>='0') && (x<='9') )
140         return x-'0';
141     if( (x>='A') && (x<='Z') )
142         return x-'A'+10;
143     if( (x>='a') && (x<='z') )
144         return x-'a'+10+26;
145     if( x=='.' )
146         return 10+26+26;
147     if( x=='_' )
148         return 10+26+26+1;
149     return -1;
150 }
151
152 LPWSTR encode_streamname(BOOL bTable, LPCWSTR in)
153 {
154     DWORD count = MAX_STREAM_NAME;
155     DWORD ch, next;
156     LPWSTR out, p;
157
158     if( !bTable )
159         count = lstrlenW( in )+2;
160     out = msi_alloc( count*sizeof(WCHAR) );
161     p = out;
162
163     if( bTable )
164     {
165          *p++ = 0x4840;
166          count --;
167     }
168     while( count -- ) 
169     {
170         ch = *in++;
171         if( !ch )
172         {
173             *p = ch;
174             return out;
175         }
176         if( ( ch < 0x80 ) && ( utf2mime(ch) >= 0 ) )
177         {
178             ch = utf2mime(ch) + 0x4800;
179             next = *in;
180             if( next && (next<0x80) )
181             {
182                 next = utf2mime(next);
183                 if( next >= 0  )
184                 {
185                      next += 0x3ffffc0;
186                      ch += (next<<6);
187                      in++;
188                 }
189             }
190         }
191         *p++ = ch;
192     }
193     ERR("Failed to encode stream name (%s)\n",debugstr_w(in));
194     msi_free( out );
195     return NULL;
196 }
197
198 static int mime2utf(int x)
199 {
200     if( x<10 )
201         return x + '0';
202     if( x<(10+26))
203         return x - 10 + 'A';
204     if( x<(10+26+26))
205         return x - 10 - 26 + 'a';
206     if( x == (10+26+26) )
207         return '.';
208     return '_';
209 }
210
211 BOOL decode_streamname(LPCWSTR in, LPWSTR out)
212 {
213     WCHAR ch;
214     DWORD count = 0;
215
216     while ( (ch = *in++) )
217     {
218         if( (ch >= 0x3800 ) && (ch < 0x4840 ) )
219         {
220             if( ch >= 0x4800 )
221                 ch = mime2utf(ch-0x4800);
222             else
223             {
224                 ch -= 0x3800;
225                 *out++ = mime2utf(ch&0x3f);
226                 count++;
227                 ch = mime2utf((ch>>6)&0x3f);
228             }
229         }
230         *out++ = ch;
231         count++;
232     }
233     *out = 0;
234     return count;
235 }
236
237 void enum_stream_names( IStorage *stg )
238 {
239     IEnumSTATSTG *stgenum = NULL;
240     HRESULT r;
241     STATSTG stat;
242     ULONG n, count;
243     WCHAR name[0x40];
244
245     r = IStorage_EnumElements( stg, 0, NULL, 0, &stgenum );
246     if( FAILED( r ) )
247         return;
248
249     n = 0;
250     while( 1 )
251     {
252         count = 0;
253         r = IEnumSTATSTG_Next( stgenum, 1, &stat, &count );
254         if( FAILED( r ) || !count )
255             break;
256         decode_streamname( stat.pwcsName, name );
257         TRACE("stream %2d -> %s %s\n", n,
258               debugstr_w(stat.pwcsName), debugstr_w(name) );
259         n++;
260     }
261
262     IEnumSTATSTG_Release( stgenum );
263 }
264
265 UINT read_stream_data( IStorage *stg, LPCWSTR stname,
266                        BYTE **pdata, UINT *psz )
267 {
268     HRESULT r;
269     UINT ret = ERROR_FUNCTION_FAILED;
270     VOID *data;
271     ULONG sz, count;
272     IStream *stm = NULL;
273     STATSTG stat;
274     LPWSTR encname;
275
276     encname = encode_streamname(TRUE, stname);
277
278     TRACE("%s -> %s\n",debugstr_w(stname),debugstr_w(encname));
279
280     r = IStorage_OpenStream(stg, encname, NULL, 
281             STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm);
282     msi_free( encname );
283     if( FAILED( r ) )
284     {
285         WARN("open stream failed r = %08x - empty table?\n", r);
286         return ret;
287     }
288
289     r = IStream_Stat(stm, &stat, STATFLAG_NONAME );
290     if( FAILED( r ) )
291     {
292         WARN("open stream failed r = %08x!\n", r);
293         goto end;
294     }
295
296     if( stat.cbSize.QuadPart >> 32 )
297     {
298         WARN("Too big!\n");
299         goto end;
300     }
301         
302     sz = stat.cbSize.QuadPart;
303     data = msi_alloc( sz );
304     if( !data )
305     {
306         WARN("couldn't allocate memory r=%08x!\n", r);
307         ret = ERROR_NOT_ENOUGH_MEMORY;
308         goto end;
309     }
310         
311     r = IStream_Read(stm, data, sz, &count );
312     if( FAILED( r ) || ( count != sz ) )
313     {
314         msi_free( data );
315         WARN("read stream failed r = %08x!\n", r);
316         goto end;
317     }
318
319     *pdata = data;
320     *psz = sz;
321     ret = ERROR_SUCCESS;
322
323 end:
324     IStream_Release( stm );
325
326     return ret;
327 }
328
329 UINT db_get_raw_stream( MSIDATABASE *db, LPCWSTR stname, IStream **stm )
330 {
331     LPWSTR encname;
332     HRESULT r;
333
334     encname = encode_streamname(FALSE, stname);
335
336     TRACE("%s -> %s\n",debugstr_w(stname),debugstr_w(encname));
337
338     r = IStorage_OpenStream(db->storage, encname, NULL, 
339             STGM_READ | STGM_SHARE_EXCLUSIVE, 0, stm);
340     if( FAILED( r ) )
341     {
342         MSITRANSFORM *transform;
343
344         LIST_FOR_EACH_ENTRY( transform, &db->transforms, MSITRANSFORM, entry )
345         {
346             TRACE("looking for %s in transform storage\n", debugstr_w(stname) );
347             r = IStorage_OpenStream( transform->stg, encname, NULL, 
348                     STGM_READ | STGM_SHARE_EXCLUSIVE, 0, stm );
349             if (SUCCEEDED(r))
350                 break;
351         }
352     }
353
354     msi_free( encname );
355
356     return SUCCEEDED(r) ? ERROR_SUCCESS : ERROR_FUNCTION_FAILED;
357 }
358
359 UINT read_raw_stream_data( MSIDATABASE *db, LPCWSTR stname,
360                               USHORT **pdata, UINT *psz )
361 {
362     HRESULT r;
363     UINT ret = ERROR_FUNCTION_FAILED;
364     VOID *data;
365     ULONG sz, count;
366     IStream *stm = NULL;
367     STATSTG stat;
368
369     r = db_get_raw_stream( db, stname, &stm );
370     if( r != ERROR_SUCCESS)
371         return ret;
372     r = IStream_Stat(stm, &stat, STATFLAG_NONAME );
373     if( FAILED( r ) )
374     {
375         WARN("open stream failed r = %08x!\n", r);
376         goto end;
377     }
378
379     if( stat.cbSize.QuadPart >> 32 )
380     {
381         WARN("Too big!\n");
382         goto end;
383     }
384         
385     sz = stat.cbSize.QuadPart;
386     data = msi_alloc( sz );
387     if( !data )
388     {
389         WARN("couldn't allocate memory r=%08x!\n", r);
390         ret = ERROR_NOT_ENOUGH_MEMORY;
391         goto end;
392     }
393         
394     r = IStream_Read(stm, data, sz, &count );
395     if( FAILED( r ) || ( count != sz ) )
396     {
397         msi_free( data );
398         WARN("read stream failed r = %08x!\n", r);
399         goto end;
400     }
401
402     *pdata = data;
403     *psz = sz;
404     ret = ERROR_SUCCESS;
405
406 end:
407     IStream_Release( stm );
408
409     return ret;
410 }
411
412 UINT write_stream_data( IStorage *stg, LPCWSTR stname,
413                         LPCVOID data, UINT sz, BOOL bTable )
414 {
415     HRESULT r;
416     UINT ret = ERROR_FUNCTION_FAILED;
417     ULONG count;
418     IStream *stm = NULL;
419     ULARGE_INTEGER size;
420     LARGE_INTEGER pos;
421     LPWSTR encname;
422
423     encname = encode_streamname(bTable, stname );
424     r = IStorage_OpenStream( stg, encname, NULL, 
425             STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, &stm);
426     if( FAILED(r) )
427     {
428         r = IStorage_CreateStream( stg, encname,
429                 STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stm);
430     }
431     msi_free( encname );
432     if( FAILED( r ) )
433     {
434         WARN("open stream failed r = %08x\n", r);
435         return ret;
436     }
437
438     size.QuadPart = sz;
439     r = IStream_SetSize( stm, size );
440     if( FAILED( r ) )
441     {
442         WARN("Failed to SetSize\n");
443         goto end;
444     }
445
446     pos.QuadPart = 0;
447     r = IStream_Seek( stm, pos, STREAM_SEEK_SET, NULL );
448     if( FAILED( r ) )
449     {
450         WARN("Failed to Seek\n");
451         goto end;
452     }
453
454     if (sz)
455     {
456         r = IStream_Write(stm, data, sz, &count );
457         if( FAILED( r ) || ( count != sz ) )
458         {
459             WARN("Failed to Write\n");
460             goto end;
461         }
462     }
463
464     ret = ERROR_SUCCESS;
465
466 end:
467     IStream_Release( stm );
468
469     return ret;
470 }
471
472 static void free_table( MSITABLE *table )
473 {
474     int i;
475     for( i=0; i<table->row_count; i++ )
476         msi_free( table->data[i] );
477     msi_free( table->data );
478     for( i=0; i<table->nonpersistent_row_count; i++ )
479         msi_free( table->nonpersistent_data[i] );
480     msi_free( table->nonpersistent_data );
481     if( (table->colinfo != _Tables_cols) &&
482         (table->colinfo != _Columns_cols) )
483     {
484         msi_free_colinfo( table->colinfo, table->col_count );
485         msi_free( table->colinfo );
486     }
487     msi_free( table );
488 }
489
490 static UINT msi_table_get_row_size( const MSICOLUMNINFO *cols, UINT count )
491 {
492     const MSICOLUMNINFO *last_col = &cols[count-1];
493     if (!count)
494         return 0;
495     return last_col->offset + bytes_per_column( last_col );
496 }
497
498 /* add this table to the list of cached tables in the database */
499 static UINT read_table_from_storage( MSITABLE *t, IStorage *stg )
500 {
501     BYTE *rawdata = NULL;
502     UINT rawsize = 0, i, j, row_size = 0;
503
504     TRACE("%s\n",debugstr_w(t->name));
505
506     row_size = msi_table_get_row_size( t->colinfo, t->col_count );
507
508     /* if we can't read the table, just assume that it's empty */
509     read_stream_data( stg, t->name, &rawdata, &rawsize );
510     if( !rawdata )
511         return ERROR_SUCCESS;
512
513     TRACE("Read %d bytes\n", rawsize );
514
515     if( rawsize % row_size )
516     {
517         WARN("Table size is invalid %d/%d\n", rawsize, row_size );
518         goto err;
519     }
520
521     t->row_count = rawsize / row_size;
522     t->data = msi_alloc_zero( t->row_count * sizeof (USHORT*) );
523     if( !t->data )
524         goto err;
525
526     /* transpose all the data */
527     TRACE("Transposing data from %d rows\n", t->row_count );
528     for( i=0; i<t->row_count; i++ )
529     {
530         t->data[i] = msi_alloc( row_size );
531         if( !t->data[i] )
532             goto err;
533
534         for( j=0; j<t->col_count; j++ )
535         {
536             UINT ofs = t->colinfo[j].offset;
537             UINT n = bytes_per_column( &t->colinfo[j] );
538             UINT k;
539
540             if ( n != 2 && n != 3 && n != 4 )
541             {
542                 ERR("oops - unknown column width %d\n", n);
543                 goto err;
544             }
545
546             for ( k = 0; k < n; k++ )
547                 t->data[i][ofs + k] = rawdata[ofs*t->row_count + i * n + k];
548         }
549     }
550
551     msi_free( rawdata );
552     return ERROR_SUCCESS;
553 err:
554     msi_free( rawdata );
555     return ERROR_FUNCTION_FAILED;
556 }
557
558 void free_cached_tables( MSIDATABASE *db )
559 {
560     while( !list_empty( &db->tables ) )
561     {
562         MSITABLE *t = LIST_ENTRY( list_head( &db->tables ), MSITABLE, entry );
563
564         list_remove( &t->entry );
565         free_table( t );
566     }
567 }
568
569 static MSITABLE *find_cached_table( MSIDATABASE *db, LPCWSTR name )
570 {
571     MSITABLE *t;
572
573     LIST_FOR_EACH_ENTRY( t, &db->tables, MSITABLE, entry )
574         if( !lstrcmpW( name, t->name ) )
575             return t;
576
577     return NULL;
578 }
579
580 static UINT table_get_column_info( MSIDATABASE *db, LPCWSTR name, MSICOLUMNINFO **pcols, UINT *pcount )
581 {
582     UINT r, column_count = 0;
583     MSICOLUMNINFO *columns;
584
585     /* get the number of columns in this table */
586     column_count = 0;
587     r = get_tablecolumns( db, name, NULL, &column_count );
588     if( r != ERROR_SUCCESS )
589         return r;
590
591     /* if there's no columns, there's no table */
592     if( column_count == 0 )
593         return ERROR_INVALID_PARAMETER;
594
595     TRACE("Table %s found\n", debugstr_w(name) );
596
597     columns = msi_alloc( column_count*sizeof (MSICOLUMNINFO) );
598     if( !columns )
599         return ERROR_FUNCTION_FAILED;
600
601     r = get_tablecolumns( db, name, columns, &column_count );
602     if( r != ERROR_SUCCESS )
603     {
604         msi_free( columns );
605         return ERROR_FUNCTION_FAILED;
606     }
607
608     *pcols = columns;
609     *pcount = column_count;
610
611     return r;
612 }
613
614 UINT msi_create_table( MSIDATABASE *db, LPCWSTR name, column_info *col_info,
615                        BOOL persistent, MSITABLE **table_ret)
616 {
617     UINT r, nField;
618     MSIVIEW *tv = NULL;
619     MSIRECORD *rec = NULL;
620     column_info *col;
621     MSITABLE *table;
622     UINT i;
623
624     /* only add tables that don't exist already */
625     if( TABLE_Exists(db, name ) )
626     {
627         WARN("table %s exists\n", debugstr_w(name));
628         return ERROR_BAD_QUERY_SYNTAX;
629     }
630
631     table = msi_alloc( sizeof (MSITABLE) + lstrlenW(name)*sizeof (WCHAR) );
632     if( !table )
633         return ERROR_FUNCTION_FAILED;
634
635     table->row_count = 0;
636     table->data = NULL;
637     table->nonpersistent_row_count = 0;
638     table->nonpersistent_data = NULL;
639     table->colinfo = NULL;
640     table->col_count = 0;
641     table->persistent = persistent;
642     lstrcpyW( table->name, name );
643
644     for( col = col_info; col; col = col->next )
645         table->col_count++;
646
647     table->colinfo = msi_alloc( table->col_count * sizeof(MSICOLUMNINFO) );
648     if (!table->colinfo)
649     {
650         free_table( table );
651         return ERROR_FUNCTION_FAILED;
652     }
653
654     for( i = 0, col = col_info; col; i++, col = col->next )
655     {
656         table->colinfo[ i ].tablename = strdupW( col->table );
657         table->colinfo[ i ].number = i + 1;
658         table->colinfo[ i ].colname = strdupW( col->column );
659         table->colinfo[ i ].type = col->type;
660         table->colinfo[ i ].offset = 0;
661         table->colinfo[ i ].hash_table = NULL;
662     }
663     table_calc_column_offsets( table->colinfo, table->col_count);
664
665     r = TABLE_CreateView( db, szTables, &tv );
666     TRACE("CreateView returned %x\n", r);
667     if( r )
668     {
669         free_table( table );
670         return r;
671     }
672
673     r = tv->ops->execute( tv, 0 );
674     TRACE("tv execute returned %x\n", r);
675     if( r )
676         goto err;
677
678     rec = MSI_CreateRecord( 1 );
679     if( !rec )
680         goto err;
681
682     r = MSI_RecordSetStringW( rec, 1, name );
683     if( r )
684         goto err;
685
686     r = tv->ops->insert_row( tv, rec, !persistent );
687     TRACE("insert_row returned %x\n", r);
688     if( r )
689         goto err;
690
691     tv->ops->delete( tv );
692     tv = NULL;
693
694     msiobj_release( &rec->hdr );
695     rec = NULL;
696
697     if( persistent )
698     {
699         /* add each column to the _Columns table */
700         r = TABLE_CreateView( db, szColumns, &tv );
701         if( r )
702             return r;
703
704         r = tv->ops->execute( tv, 0 );
705         TRACE("tv execute returned %x\n", r);
706         if( r )
707             goto err;
708
709         rec = MSI_CreateRecord( 4 );
710         if( !rec )
711             goto err;
712
713         r = MSI_RecordSetStringW( rec, 1, name );
714         if( r )
715             goto err;
716
717         /*
718          * need to set the table, column number, col name and type
719          * for each column we enter in the table
720          */
721         nField = 1;
722         for( col = col_info; col; col = col->next )
723         {
724             r = MSI_RecordSetInteger( rec, 2, nField );
725             if( r )
726                 goto err;
727
728             r = MSI_RecordSetStringW( rec, 3, col->column );
729             if( r )
730                 goto err;
731
732             r = MSI_RecordSetInteger( rec, 4, col->type );
733             if( r )
734                 goto err;
735
736             r = tv->ops->insert_row( tv, rec, FALSE );
737             if( r )
738                 goto err;
739
740             nField++;
741         }
742         if( !col )
743             r = ERROR_SUCCESS;
744     }
745
746 err:
747     if (rec)
748         msiobj_release( &rec->hdr );
749     /* FIXME: remove values from the string table on error */
750     if( tv )
751         tv->ops->delete( tv );
752
753     if (r == ERROR_SUCCESS)
754     {
755         list_add_head( &db->tables, &table->entry );
756         *table_ret = table;
757     }
758     else
759         free_table( table );
760
761     return r;
762 }
763
764 static UINT get_table( MSIDATABASE *db, LPCWSTR name, MSITABLE **table_ret )
765 {
766     MSITABLE *table;
767     UINT r;
768
769     /* first, see if the table is cached */
770     table = find_cached_table( db, name );
771     if( table )
772     {
773         *table_ret = table;
774         return ERROR_SUCCESS;
775     }
776
777     /* nonexistent tables should be interpreted as empty tables */
778     table = msi_alloc( sizeof (MSITABLE) + lstrlenW(name)*sizeof (WCHAR) );
779     if( !table )
780         return ERROR_FUNCTION_FAILED;
781
782     table->row_count = 0;
783     table->data = NULL;
784     table->nonpersistent_row_count = 0;
785     table->nonpersistent_data = NULL;
786     table->colinfo = NULL;
787     table->col_count = 0;
788     table->persistent = TRUE;
789     lstrcpyW( table->name, name );
790
791     /* these two tables are special - we know the column types already */
792     if( !lstrcmpW( name, szColumns ) )
793     {
794         table->colinfo = _Columns_cols;
795         table->col_count = sizeof(_Columns_cols)/sizeof(_Columns_cols[0]);
796     }
797     else if( !lstrcmpW( name, szTables ) )
798     {
799         table->colinfo = _Tables_cols;
800         table->col_count = sizeof(_Tables_cols)/sizeof(_Tables_cols[0]);
801     }
802     else
803     {
804         r = table_get_column_info( db, name, &table->colinfo, &table->col_count);
805         if (r != ERROR_SUCCESS)
806         {
807             free_table ( table );
808             return r;
809         }
810     }
811
812     r = read_table_from_storage( table, db->storage );
813     if( r != ERROR_SUCCESS )
814     {
815         free_table( table );
816         return r;
817     }
818
819     list_add_head( &db->tables, &table->entry );
820     *table_ret = table;
821     return ERROR_SUCCESS;
822 }
823
824 static UINT save_table( MSIDATABASE *db, const MSITABLE *t )
825 {
826     BYTE *rawdata = NULL, *p;
827     UINT rawsize, r, i, j, row_size;
828
829     /* Nothing to do for non-persistent tables */
830     if( !t->persistent )
831         return ERROR_SUCCESS;
832
833     TRACE("Saving %s\n", debugstr_w( t->name ) );
834
835     row_size = msi_table_get_row_size( t->colinfo, t->col_count );
836
837     rawsize = t->row_count * row_size;
838     rawdata = msi_alloc_zero( rawsize );
839     if( !rawdata )
840     {
841         r = ERROR_NOT_ENOUGH_MEMORY;
842         goto err;
843     }
844
845     p = rawdata;
846     for( i=0; i<t->col_count; i++ )
847     {
848         for( j=0; j<t->row_count; j++ )
849         {
850             UINT offset = t->colinfo[i].offset;
851
852             *p++ = t->data[j][offset];
853             *p++ = t->data[j][offset + 1];
854             if( 4 == bytes_per_column( &t->colinfo[i] ) )
855             {
856                 *p++ = t->data[j][offset + 2];
857                 *p++ = t->data[j][offset + 3];
858             }
859         }
860     }
861
862     TRACE("writing %d bytes\n", rawsize);
863     r = write_stream_data( db->storage, t->name, rawdata, rawsize, TRUE );
864
865 err:
866     msi_free( rawdata );
867
868     return r;
869 }
870
871 static void table_calc_column_offsets( MSICOLUMNINFO *colinfo, DWORD count )
872 {
873     DWORD i;
874
875     for( i=0; colinfo && (i<count); i++ )
876     {
877          assert( (i+1) == colinfo[ i ].number );
878          if (i)
879              colinfo[i].offset = colinfo[ i - 1 ].offset
880                                + bytes_per_column( &colinfo[ i - 1 ] );
881          else
882              colinfo[i].offset = 0;
883          TRACE("column %d is [%s] with type %08x ofs %d\n",
884                colinfo[i].number, debugstr_w(colinfo[i].colname),
885                colinfo[i].type, colinfo[i].offset);
886     }
887 }
888
889 static UINT get_defaulttablecolumns( LPCWSTR name, MSICOLUMNINFO *colinfo, UINT *sz)
890 {
891     const MSICOLUMNINFO *p;
892     DWORD i, n;
893
894     TRACE("%s\n", debugstr_w(name));
895
896     if (!lstrcmpW( name, szTables ))
897     {
898         p = _Tables_cols;
899         n = 1;
900     }
901     else if (!lstrcmpW( name, szColumns ))
902     {
903         p = _Columns_cols;
904         n = 4;
905     }
906     else
907         return ERROR_FUNCTION_FAILED;
908
909     /* duplicate the string data so we can free it in msi_free_colinfo */
910     for (i=0; i<n; i++)
911     {
912         if (colinfo && (i < *sz) )
913         {
914             memcpy( &colinfo[i], &p[i], sizeof(MSICOLUMNINFO) );
915             colinfo[i].tablename = strdupW( p[i].tablename );
916             colinfo[i].colname = strdupW( p[i].colname );
917         }
918         if( colinfo && (i >= *sz) )
919             break;
920     }
921     table_calc_column_offsets( colinfo, n );
922     *sz = n;
923     return ERROR_SUCCESS;
924 }
925
926 static void msi_free_colinfo( MSICOLUMNINFO *colinfo, UINT count )
927 {
928     UINT i;
929
930     for( i=0; i<count; i++ )
931     {
932         msi_free( (LPWSTR) colinfo[i].tablename );
933         msi_free( (LPWSTR) colinfo[i].colname );
934         msi_free( colinfo[i].hash_table );
935     }
936 }
937
938 static LPWSTR msi_makestring( const MSIDATABASE *db, UINT stringid)
939 {
940     return strdupW(msi_string_lookup_id( db->strings, stringid ));
941 }
942
943 static UINT read_table_int(BYTE *const *data, UINT row, UINT col, UINT bytes)
944 {
945     UINT ret = 0, i;
946
947     for (i = 0; i < bytes; i++)
948         ret += (data[row][col + i] << i * 8);
949
950     return ret;
951 }
952
953 static UINT get_tablecolumns( MSIDATABASE *db,
954        LPCWSTR szTableName, MSICOLUMNINFO *colinfo, UINT *sz)
955 {
956     UINT r, i, n=0, table_id, count, maxcount = *sz;
957     MSITABLE *table = NULL;
958
959     TRACE("%s\n", debugstr_w(szTableName));
960
961     /* first check if there is a default table with that name */
962     r = get_defaulttablecolumns( szTableName, colinfo, sz );
963     if( ( r == ERROR_SUCCESS ) && *sz )
964         return r;
965
966     r = get_table( db, szColumns, &table );
967     if( r != ERROR_SUCCESS )
968     {
969         ERR("couldn't load _Columns table\n");
970         return ERROR_FUNCTION_FAILED;
971     }
972
973     /* convert table and column names to IDs from the string table */
974     r = msi_string2idW( db->strings, szTableName, &table_id );
975     if( r != ERROR_SUCCESS )
976     {
977         WARN("Couldn't find id for %s\n", debugstr_w(szTableName));
978         return r;
979     }
980
981     TRACE("Table id is %d, row count is %d\n", table_id, table->row_count);
982
983     /* Note: _Columns table doesn't have non-persistent data */
984
985     /* if maxcount is non-zero, assume it's exactly right for this table */
986     memset( colinfo, 0, maxcount*sizeof(*colinfo) );
987     count = table->row_count;
988     for( i=0; i<count; i++ )
989     {
990         if( read_table_int(table->data, i, 0, db->bytes_per_strref) != table_id )
991             continue;
992         if( colinfo )
993         {
994             UINT id = read_table_int(table->data, i, _Columns_cols[2].offset, db->bytes_per_strref);
995             UINT col = read_table_int(table->data, i, _Columns_cols[1].offset, sizeof(USHORT)) - (1<<15);
996
997             /* check the column number is in range */
998             if (col<1 || col>maxcount)
999             {
1000                 ERR("column %d out of range\n", col);
1001                 continue;
1002             }
1003
1004             /* check if this column was already set */
1005             if (colinfo[ col - 1 ].number)
1006             {
1007                 ERR("duplicate column %d\n", col);
1008                 continue;
1009             }
1010
1011             colinfo[ col - 1 ].tablename = msi_makestring( db, table_id );
1012             colinfo[ col - 1 ].number = col;
1013             colinfo[ col - 1 ].colname = msi_makestring( db, id );
1014             colinfo[ col - 1 ].type = read_table_int(table->data, i, _Columns_cols[3].offset, sizeof(USHORT)) - (1<<15);
1015             colinfo[ col - 1 ].offset = 0;
1016             colinfo[ col - 1 ].hash_table = NULL;
1017         }
1018         n++;
1019     }
1020
1021     TRACE("%s has %d columns\n", debugstr_w(szTableName), n);
1022
1023     if (colinfo && n != maxcount)
1024     {
1025         ERR("missing column in table %s\n", debugstr_w(szTableName));
1026         msi_free_colinfo(colinfo, maxcount );
1027         return ERROR_FUNCTION_FAILED;
1028     }
1029
1030     table_calc_column_offsets( colinfo, n );
1031     *sz = n;
1032
1033     return ERROR_SUCCESS;
1034 }
1035
1036 /* try to find the table name in the _Tables table */
1037 BOOL TABLE_Exists( MSIDATABASE *db, LPCWSTR name )
1038 {
1039     UINT r, table_id = 0, i, count;
1040     MSITABLE *table = NULL;
1041
1042     if( !lstrcmpW( name, szTables ) )
1043         return TRUE;
1044     if( !lstrcmpW( name, szColumns ) )
1045         return TRUE;
1046
1047     r = msi_string2idW( db->strings, name, &table_id );
1048     if( r != ERROR_SUCCESS )
1049     {
1050         TRACE("Couldn't find id for %s\n", debugstr_w(name));
1051         return FALSE;
1052     }
1053
1054     r = get_table( db, szTables, &table );
1055     if( r != ERROR_SUCCESS )
1056     {
1057         ERR("table %s not available\n", debugstr_w(szTables));
1058         return FALSE;
1059     }
1060
1061     count = table->row_count;
1062     for( i=0; i<count; i++ )
1063         if( table->data[ i ][ 0 ] == table_id )
1064             break;
1065
1066     if (i!=count)
1067         return TRUE;
1068
1069     count = table->nonpersistent_row_count;
1070     for( i=0; i<count; i++ )
1071         if( table->nonpersistent_data[ i ][ 0 ] == table_id )
1072             break;
1073
1074     if (i!=count)
1075         return TRUE;
1076
1077     TRACE("Searched %d tables, but %d was not found\n", count, table_id );
1078
1079     return FALSE;
1080 }
1081
1082 /* below is the query interface to a table */
1083
1084 typedef struct tagMSITABLEVIEW
1085 {
1086     MSIVIEW        view;
1087     MSIDATABASE   *db;
1088     MSITABLE      *table;
1089     MSICOLUMNINFO *columns;
1090     UINT           num_cols;
1091     UINT           row_size;
1092     WCHAR          name[1];
1093 } MSITABLEVIEW;
1094
1095 static UINT TABLE_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val )
1096 {
1097     MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
1098     UINT offset, n;
1099     BYTE **data;
1100
1101     if( !tv->table )
1102         return ERROR_INVALID_PARAMETER;
1103
1104     if( (col==0) || (col>tv->num_cols) )
1105         return ERROR_INVALID_PARAMETER;
1106
1107     /* how many rows are there ? */
1108     if( row >= tv->table->row_count + tv->table->nonpersistent_row_count )
1109         return ERROR_NO_MORE_ITEMS;
1110
1111     if( tv->columns[col-1].offset >= tv->row_size )
1112     {
1113         ERR("Stuffed up %d >= %d\n", tv->columns[col-1].offset, tv->row_size );
1114         ERR("%p %p\n", tv, tv->columns );
1115         return ERROR_FUNCTION_FAILED;
1116     }
1117
1118     if (row >= tv->table->row_count)
1119     {
1120         row -= tv->table->row_count;
1121         data = tv->table->nonpersistent_data;
1122     }
1123     else
1124         data = tv->table->data;
1125
1126     n = bytes_per_column( &tv->columns[col-1] );
1127     if (n != 2 && n != 3 && n != 4)
1128     {
1129         ERR("oops! what is %d bytes per column?\n", n );
1130         return ERROR_FUNCTION_FAILED;
1131     }
1132
1133     offset = tv->columns[col-1].offset;
1134     *val = read_table_int(data, row, offset, n);
1135
1136     /* TRACE("Data [%d][%d] = %d\n", row, col, *val ); */
1137
1138     return ERROR_SUCCESS;
1139 }
1140
1141 /*
1142  * We need a special case for streams, as we need to reference column with
1143  * the name of the stream in the same table, and the table name
1144  * which may not be available at higher levels of the query
1145  */
1146 static UINT TABLE_fetch_stream( struct tagMSIVIEW *view, UINT row, UINT col, IStream **stm )
1147 {
1148     MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
1149     UINT ival = 0, refcol = 0, r;
1150     LPCWSTR sval;
1151     LPWSTR full_name;
1152     DWORD len;
1153     static const WCHAR szDot[] = { '.', 0 };
1154     WCHAR number[0x20];
1155
1156     if( !view->ops->fetch_int )
1157         return ERROR_INVALID_PARAMETER;
1158
1159     /*
1160      * The column marked with the type stream data seems to have a single number
1161      * which references the column containing the name of the stream data
1162      *
1163      * Fetch the column to reference first.
1164      */
1165     r = view->ops->fetch_int( view, row, col, &ival );
1166     if( r != ERROR_SUCCESS )
1167         return r;
1168
1169     /* check the column value is in range */
1170     if (ival < 0 || ival > tv->num_cols || ival == col)
1171     {
1172         ERR("bad column ref (%u) for stream\n", ival);
1173         return ERROR_FUNCTION_FAILED;
1174     }
1175
1176     if ( tv->columns[ival - 1].type & MSITYPE_STRING )
1177     {
1178         /* now get the column with the name of the stream */
1179         r = view->ops->fetch_int( view, row, ival, &refcol );
1180         if ( r != ERROR_SUCCESS )
1181             return r;
1182
1183         /* lookup the string value from the string table */
1184         sval = msi_string_lookup_id( tv->db->strings, refcol );
1185         if ( !sval )
1186             return ERROR_INVALID_PARAMETER;
1187     }
1188     else
1189     {
1190         static const WCHAR fmt[] = { '%','d',0 };
1191         sprintfW( number, fmt, ival );
1192         sval = number;
1193     }
1194
1195     len = lstrlenW( tv->name ) + 2 + lstrlenW( sval );
1196     full_name = msi_alloc( len*sizeof(WCHAR) );
1197     lstrcpyW( full_name, tv->name );
1198     lstrcatW( full_name, szDot );
1199     lstrcatW( full_name, sval );
1200
1201     r = db_get_raw_stream( tv->db, full_name, stm );
1202     if( r )
1203         ERR("fetching stream %s, error = %d\n",debugstr_w(full_name), r);
1204     msi_free( full_name );
1205
1206     return r;
1207 }
1208
1209 static UINT TABLE_set_int( MSITABLEVIEW *tv, UINT row, UINT col, UINT val )
1210 {
1211     UINT offset, n, i;
1212     BYTE **data;
1213
1214     if( !tv->table )
1215         return ERROR_INVALID_PARAMETER;
1216
1217     if( (col==0) || (col>tv->num_cols) )
1218         return ERROR_INVALID_PARAMETER;
1219
1220     if( row >= tv->table->row_count + tv->table->nonpersistent_row_count )
1221         return ERROR_INVALID_PARAMETER;
1222
1223     if( tv->columns[col-1].offset >= tv->row_size )
1224     {
1225         ERR("Stuffed up %d >= %d\n", tv->columns[col-1].offset, tv->row_size );
1226         ERR("%p %p\n", tv, tv->columns );
1227         return ERROR_FUNCTION_FAILED;
1228     }
1229
1230     msi_free( tv->columns[col-1].hash_table );
1231     tv->columns[col-1].hash_table = NULL;
1232
1233     if (row >= tv->table->row_count)
1234     {
1235         row -= tv->table->row_count;
1236         data = tv->table->nonpersistent_data;
1237     }
1238     else
1239         data = tv->table->data;
1240
1241     n = bytes_per_column( &tv->columns[col-1] );
1242     if ( n != 2 && n != 3 && n != 4 )
1243     {
1244         ERR("oops! what is %d bytes per column?\n", n );
1245         return ERROR_FUNCTION_FAILED;
1246     }
1247
1248     offset = tv->columns[col-1].offset;
1249     for ( i = 0; i < n; i++ )
1250         data[row][offset + i] = (val >> i * 8) & 0xff;
1251
1252     return ERROR_SUCCESS;
1253 }
1254
1255 static UINT TABLE_set_row( struct tagMSIVIEW *view, UINT row, MSIRECORD *rec, UINT mask )
1256 {
1257     MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
1258     UINT i, val, r = ERROR_SUCCESS;
1259
1260     if ( !tv->table )
1261         return ERROR_INVALID_PARAMETER;
1262
1263     /* test if any of the mask bits are invalid */
1264     if ( mask >= (1<<tv->num_cols) )
1265         return ERROR_INVALID_PARAMETER;
1266
1267     for ( i = 0; i < tv->num_cols; i++ )
1268     {
1269         BOOL persistent;
1270
1271         /* only update the fields specified in the mask */
1272         if ( !(mask&(1<<i)) )
1273             continue;
1274
1275         /* if row >= tv->table->row_count then it is a non-persistent row */
1276         persistent = tv->table->persistent && (row < tv->table->row_count);
1277         /* FIXME: should we allow updating keys? */
1278
1279         val = 0;
1280         if ( !MSI_RecordIsNull( rec, i + 1 ) )
1281         {
1282             if ( MSITYPE_IS_BINARY(tv->columns[ i ].type) )
1283             {
1284                 val = 1; /* refers to the first key column */
1285             }
1286             else if ( tv->columns[i].type & MSITYPE_STRING )
1287             {
1288                 LPCWSTR sval = MSI_RecordGetString( rec, i + 1 );
1289                 val = msi_addstringW( tv->db->strings, 0, sval, -1, 1,
1290                                       persistent ? StringPersistent : StringNonPersistent );
1291             }
1292             else if ( 2 == bytes_per_column( &tv->columns[ i ] ) )
1293             {
1294                 val = 0x8000 + MSI_RecordGetInteger( rec, i + 1 );
1295                 if ( val & 0xffff0000 )
1296                 {
1297                     ERR("field %u value %d out of range\n", i+1, val - 0x8000 );
1298                     return ERROR_FUNCTION_FAILED;
1299                 }
1300             }
1301             else
1302             {
1303                 INT ival = MSI_RecordGetInteger( rec, i + 1 );
1304                 val = ival ^ 0x80000000;
1305             }
1306         }
1307
1308         r = TABLE_set_int( tv, row, i+1, val );
1309         if ( r != ERROR_SUCCESS )
1310             break;
1311     }
1312     return r;
1313 }
1314
1315 static UINT table_create_new_row( struct tagMSIVIEW *view, UINT *num, BOOL temporary )
1316 {
1317     MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
1318     BYTE **p, *row;
1319     UINT sz;
1320     BYTE ***data_ptr;
1321     UINT *row_count;
1322
1323     TRACE("%p %s\n", view, temporary ? "TRUE" : "FALSE");
1324
1325     if( !tv->table )
1326         return ERROR_INVALID_PARAMETER;
1327
1328     row = msi_alloc_zero( tv->row_size );
1329     if( !row )
1330         return ERROR_NOT_ENOUGH_MEMORY;
1331
1332     if( temporary )
1333     {
1334         row_count = &tv->table->nonpersistent_row_count;
1335         data_ptr = &tv->table->nonpersistent_data;
1336         *num = tv->table->row_count + tv->table->nonpersistent_row_count;
1337     }
1338     else
1339     {
1340         row_count = &tv->table->row_count;
1341         data_ptr = &tv->table->data;
1342         *num = tv->table->row_count;
1343     }
1344
1345     sz = (*row_count + 1) * sizeof (BYTE*);
1346     if( *data_ptr )
1347         p = msi_realloc( *data_ptr, sz );
1348     else
1349         p = msi_alloc( sz );
1350     if( !p )
1351     {
1352         msi_free( row );
1353         return ERROR_NOT_ENOUGH_MEMORY;
1354     }
1355
1356     *data_ptr = p;
1357     (*data_ptr)[*row_count] = row;
1358     (*row_count)++;
1359
1360     return ERROR_SUCCESS;
1361 }
1362
1363 static UINT TABLE_execute( struct tagMSIVIEW *view, MSIRECORD *record )
1364 {
1365     MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
1366
1367     TRACE("%p %p\n", tv, record);
1368
1369     TRACE("There are %d columns\n", tv->num_cols );
1370
1371     return ERROR_SUCCESS;
1372 }
1373
1374 static UINT TABLE_close( struct tagMSIVIEW *view )
1375 {
1376     TRACE("%p\n", view );
1377     
1378     return ERROR_SUCCESS;
1379 }
1380
1381 static UINT TABLE_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols)
1382 {
1383     MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
1384
1385     TRACE("%p %p %p\n", view, rows, cols );
1386
1387     if( cols )
1388         *cols = tv->num_cols;
1389     if( rows )
1390     {
1391         if( !tv->table )
1392             return ERROR_INVALID_PARAMETER;
1393         *rows = tv->table->row_count + tv->table->nonpersistent_row_count;
1394     }
1395
1396     return ERROR_SUCCESS;
1397 }
1398
1399 static UINT TABLE_get_column_info( struct tagMSIVIEW *view,
1400                 UINT n, LPWSTR *name, UINT *type )
1401 {
1402     MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
1403
1404     TRACE("%p %d %p %p\n", tv, n, name, type );
1405
1406     if( ( n == 0 ) || ( n > tv->num_cols ) )
1407         return ERROR_INVALID_PARAMETER;
1408
1409     if( name )
1410     {
1411         *name = strdupW( tv->columns[n-1].colname );
1412         if( !*name )
1413             return ERROR_FUNCTION_FAILED;
1414     }
1415     if( type )
1416         *type = tv->columns[n-1].type;
1417
1418     return ERROR_SUCCESS;
1419 }
1420
1421 static UINT msi_table_find_row( MSITABLEVIEW *tv, MSIRECORD *rec, UINT *row );
1422
1423 static UINT table_validate_new( MSITABLEVIEW *tv, MSIRECORD *rec )
1424 {
1425     UINT r, row, i;
1426
1427     /* check there's no null values where they're not allowed */
1428     for( i = 0; i < tv->num_cols; i++ )
1429     {
1430         if ( tv->columns[i].type & MSITYPE_NULLABLE )
1431             continue;
1432
1433         if ( MSITYPE_IS_BINARY(tv->columns[i].type) )
1434             TRACE("skipping binary column\n");
1435         else if ( tv->columns[i].type & MSITYPE_STRING )
1436         {
1437             LPCWSTR str;
1438
1439             str = MSI_RecordGetString( rec, i+1 );
1440             if (str == NULL || str[0] == 0)
1441                 return ERROR_INVALID_DATA;
1442         }
1443         else
1444         {
1445             UINT n;
1446
1447             n = MSI_RecordGetInteger( rec, i+1 );
1448             if (n == MSI_NULL_INTEGER)
1449                 return ERROR_INVALID_DATA;
1450         }
1451     }
1452
1453     /* check there's no duplicate keys */
1454     r = msi_table_find_row( tv, rec, &row );
1455     if (r == ERROR_SUCCESS)
1456         return ERROR_INVALID_DATA;
1457
1458     return ERROR_SUCCESS;
1459 }
1460
1461 static UINT TABLE_insert_row( struct tagMSIVIEW *view, MSIRECORD *rec, BOOL temporary )
1462 {
1463     MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
1464     UINT r, row = -1;
1465
1466     TRACE("%p %p %s\n", tv, rec, temporary ? "TRUE" : "FALSE" );
1467
1468     /* check that the key is unique - can we find a matching row? */
1469     r = table_validate_new( tv, rec );
1470     if( r != ERROR_SUCCESS )
1471         return ERROR_FUNCTION_FAILED;
1472
1473     r = table_create_new_row( view, &row, temporary );
1474     TRACE("insert_row returned %08x\n", r);
1475     if( r != ERROR_SUCCESS )
1476         return r;
1477
1478     return TABLE_set_row( view, row, rec, (1<<tv->num_cols) - 1 );
1479 }
1480
1481 static UINT TABLE_delete_row( struct tagMSIVIEW *view, UINT row )
1482 {
1483     MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
1484     UINT r, num_rows, num_cols;
1485     BYTE *src, *dest;
1486
1487     TRACE("%p %d\n", tv, row);
1488
1489     if ( !tv->table )
1490         return ERROR_INVALID_PARAMETER;
1491
1492     r = TABLE_get_dimensions( view, &num_rows, &num_cols );
1493     if ( r != ERROR_SUCCESS )
1494         return r;
1495
1496     if ( row >= num_rows )
1497         return ERROR_FUNCTION_FAILED;
1498
1499     tv->table->row_count--;
1500
1501     if ( row == num_rows - 1 )
1502         return ERROR_SUCCESS;
1503
1504     dest = tv->table->data[row];
1505     src = tv->table->data[row + 1];
1506     memmove(dest, src, (num_rows - row - 1) * tv->row_size);
1507     return ERROR_SUCCESS;
1508 }
1509
1510 static UINT TABLE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode,
1511                 MSIRECORD *rec)
1512 {
1513     MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
1514     UINT r;
1515
1516     TRACE("%p %d %p\n", view, eModifyMode, rec );
1517
1518     switch (eModifyMode)
1519     {
1520     case MSIMODIFY_VALIDATE_NEW:
1521         r = table_validate_new( tv, rec );
1522         break;
1523
1524     case MSIMODIFY_INSERT_TEMPORARY:
1525         r = table_validate_new( tv, rec );
1526         if (r != ERROR_SUCCESS)
1527             break;
1528         r = TABLE_insert_row( view, rec, TRUE );
1529         break;
1530
1531     case MSIMODIFY_REFRESH:
1532     case MSIMODIFY_INSERT:
1533     case MSIMODIFY_UPDATE:
1534     case MSIMODIFY_ASSIGN:
1535     case MSIMODIFY_REPLACE:
1536     case MSIMODIFY_MERGE:
1537     case MSIMODIFY_DELETE:
1538     case MSIMODIFY_VALIDATE:
1539     case MSIMODIFY_VALIDATE_FIELD:
1540     case MSIMODIFY_VALIDATE_DELETE:
1541         FIXME("%p %d %p - mode not implemented\n", view, eModifyMode, rec );
1542         r = ERROR_CALL_NOT_IMPLEMENTED;
1543         break;
1544
1545     default:
1546         r = ERROR_INVALID_DATA;
1547     }
1548
1549     return r;
1550 }
1551
1552 static UINT TABLE_delete( struct tagMSIVIEW *view )
1553 {
1554     MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
1555
1556     TRACE("%p\n", view );
1557
1558     tv->table = NULL;
1559
1560     tv->columns = NULL;
1561
1562     msi_free( tv );
1563
1564     return ERROR_SUCCESS;
1565 }
1566
1567 static UINT TABLE_find_matching_rows( struct tagMSIVIEW *view, UINT col,
1568     UINT val, UINT *row, MSIITERHANDLE *handle )
1569 {
1570     MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
1571     const MSICOLUMNHASHENTRY *entry;
1572
1573     TRACE("%p, %d, %u, %p\n", view, col, val, *handle);
1574
1575     if( !tv->table )
1576         return ERROR_INVALID_PARAMETER;
1577
1578     if( (col==0) || (col > tv->num_cols) )
1579         return ERROR_INVALID_PARAMETER;
1580
1581     if( !tv->columns[col-1].hash_table )
1582     {
1583         UINT i;
1584         UINT num_rows = tv->table->row_count + tv->table->nonpersistent_row_count;
1585         MSICOLUMNHASHENTRY **hash_table;
1586         MSICOLUMNHASHENTRY *new_entry;
1587
1588         if( tv->columns[col-1].offset >= tv->row_size )
1589         {
1590             ERR("Stuffed up %d >= %d\n", tv->columns[col-1].offset, tv->row_size );
1591             ERR("%p %p\n", tv, tv->columns );
1592             return ERROR_FUNCTION_FAILED;
1593         }
1594
1595         /* allocate contiguous memory for the table and its entries so we
1596          * don't have to do an expensive cleanup */
1597         hash_table = msi_alloc(MSITABLE_HASH_TABLE_SIZE * sizeof(MSICOLUMNHASHENTRY*) +
1598             num_rows * sizeof(MSICOLUMNHASHENTRY));
1599         if (!hash_table)
1600             return ERROR_OUTOFMEMORY;
1601
1602         memset(hash_table, 0, MSITABLE_HASH_TABLE_SIZE * sizeof(MSICOLUMNHASHENTRY*));
1603         tv->columns[col-1].hash_table = hash_table;
1604
1605         new_entry = (MSICOLUMNHASHENTRY *)(hash_table + MSITABLE_HASH_TABLE_SIZE);
1606
1607         for (i = 0; i < num_rows; i++, new_entry++)
1608         {
1609             UINT row_value;
1610
1611             if (view->ops->fetch_int( view, i, col, &row_value ) != ERROR_SUCCESS)
1612                 continue;
1613
1614             new_entry->next = NULL;
1615             new_entry->value = row_value;
1616             new_entry->row = i;
1617             if (hash_table[row_value % MSITABLE_HASH_TABLE_SIZE])
1618             {
1619                 MSICOLUMNHASHENTRY *prev_entry = hash_table[row_value % MSITABLE_HASH_TABLE_SIZE];
1620                 while (prev_entry->next)
1621                     prev_entry = prev_entry->next;
1622                 prev_entry->next = new_entry;
1623             }
1624             else
1625                 hash_table[row_value % MSITABLE_HASH_TABLE_SIZE] = new_entry;
1626         }
1627     }
1628
1629     if( !*handle )
1630         entry = tv->columns[col-1].hash_table[val % MSITABLE_HASH_TABLE_SIZE];
1631     else
1632         entry = (*handle)->next;
1633
1634     while (entry && entry->value != val)
1635         entry = entry->next;
1636
1637     *handle = entry;
1638     if (!entry)
1639         return ERROR_NO_MORE_ITEMS;
1640
1641     *row = entry->row;
1642     return ERROR_SUCCESS;
1643 }
1644
1645
1646 static const MSIVIEWOPS table_ops =
1647 {
1648     TABLE_fetch_int,
1649     TABLE_fetch_stream,
1650     TABLE_set_row,
1651     TABLE_insert_row,
1652     TABLE_delete_row,
1653     TABLE_execute,
1654     TABLE_close,
1655     TABLE_get_dimensions,
1656     TABLE_get_column_info,
1657     TABLE_modify,
1658     TABLE_delete,
1659     TABLE_find_matching_rows
1660 };
1661
1662 UINT TABLE_CreateView( MSIDATABASE *db, LPCWSTR name, MSIVIEW **view )
1663 {
1664     MSITABLEVIEW *tv ;
1665     UINT r, sz;
1666
1667     static const WCHAR Streams[] = {'_','S','t','r','e','a','m','s',0};
1668
1669     TRACE("%p %s %p\n", db, debugstr_w(name), view );
1670
1671     if ( !lstrcmpW( name, Streams ) )
1672         return STREAMS_CreateView( db, view );
1673
1674     sz = sizeof *tv + lstrlenW(name)*sizeof name[0] ;
1675     tv = msi_alloc_zero( sz );
1676     if( !tv )
1677         return ERROR_FUNCTION_FAILED;
1678
1679     r = get_table( db, name, &tv->table );
1680     if( r != ERROR_SUCCESS )
1681     {
1682         msi_free( tv );
1683         WARN("table not found\n");
1684         return r;
1685     }
1686
1687     TRACE("table %p found with %d columns\n", tv->table, tv->table->col_count);
1688
1689     /* fill the structure */
1690     tv->view.ops = &table_ops;
1691     tv->db = db;
1692     tv->columns = tv->table->colinfo;
1693     tv->num_cols = tv->table->col_count;
1694     tv->row_size = msi_table_get_row_size( tv->table->colinfo, tv->table->col_count );
1695
1696     TRACE("%s one row is %d bytes\n", debugstr_w(name), tv->row_size );
1697
1698     *view = (MSIVIEW*) tv;
1699     lstrcpyW( tv->name, name );
1700
1701     return ERROR_SUCCESS;
1702 }
1703
1704 UINT MSI_CommitTables( MSIDATABASE *db )
1705 {
1706     UINT r;
1707     MSITABLE *table = NULL;
1708
1709     TRACE("%p\n",db);
1710
1711     r = msi_save_string_table( db->strings, db->storage );
1712     if( r != ERROR_SUCCESS )
1713     {
1714         WARN("failed to save string table r=%08x\n",r);
1715         return r;
1716     }
1717
1718     LIST_FOR_EACH_ENTRY( table, &db->tables, MSITABLE, entry )
1719     {
1720         r = save_table( db, table );
1721         if( r != ERROR_SUCCESS )
1722         {
1723             WARN("failed to save table %s (r=%08x)\n",
1724                   debugstr_w(table->name), r);
1725             return r;
1726         }
1727     }
1728
1729     /* force everything to reload next time */
1730     free_cached_tables( db );
1731
1732     return ERROR_SUCCESS;
1733 }
1734
1735 MSICONDITION MSI_DatabaseIsTablePersistent( MSIDATABASE *db, LPCWSTR table )
1736 {
1737     MSITABLE *t;
1738     UINT r;
1739
1740     TRACE("%p %s\n", db, debugstr_w(table));
1741
1742     if (!table)
1743         return MSICONDITION_ERROR;
1744
1745     r = get_table( db, table, &t );
1746     if (r != ERROR_SUCCESS)
1747         return MSICONDITION_NONE;
1748
1749     if (t->persistent)
1750         return MSICONDITION_TRUE;
1751     else
1752         return MSICONDITION_FALSE;
1753 }
1754
1755 static UINT read_raw_int(const BYTE *data, UINT col, UINT bytes)
1756 {
1757     UINT ret = 0, i;
1758
1759     for (i = 0; i < bytes; i++)
1760         ret += (data[col + i] << i * 8);
1761
1762     return ret;
1763 }
1764
1765 static MSIRECORD *msi_get_transform_record( const MSITABLEVIEW *tv, const string_table *st,
1766                                             const BYTE *rawdata, UINT bytes_per_strref )
1767 {
1768     UINT i, val, ofs = 0;
1769     USHORT mask;
1770     MSICOLUMNINFO *columns = tv->columns;
1771     MSIRECORD *rec;
1772
1773     mask = rawdata[0] | (rawdata[1] << 8);
1774     rawdata += 2;
1775
1776     rec = MSI_CreateRecord( tv->num_cols );
1777     if( !rec )
1778         return rec;
1779
1780     TRACE("row ->\n");
1781     for( i=0; i<tv->num_cols; i++ )
1782     {
1783         if ( (mask&1) && (i>=(mask>>8)) )
1784             break;
1785         /* all keys must be present */
1786         if ( (~mask&1) && (~columns[i].type & MSITYPE_KEY) && ((1<<i) & ~mask) )
1787             continue;
1788
1789         if( (columns[i].type & MSITYPE_STRING) &&
1790             ! MSITYPE_IS_BINARY(tv->columns[i].type) )
1791         {
1792             LPCWSTR sval;
1793
1794             val = read_raw_int(rawdata, ofs, bytes_per_strref);
1795             sval = msi_string_lookup_id( st, val );
1796             MSI_RecordSetStringW( rec, i+1, sval );
1797             TRACE(" field %d [%s]\n", i+1, debugstr_w(sval));
1798             ofs += bytes_per_strref;
1799         }
1800         else
1801         {
1802             UINT n = bytes_per_column( &columns[i] );
1803             switch( n )
1804             {
1805             case 2:
1806                 val = read_raw_int(rawdata, ofs, n);
1807                 if (val)
1808                     MSI_RecordSetInteger( rec, i+1, val^0x8000 );
1809                 TRACE(" field %d [0x%04x]\n", i+1, val );
1810                 break;
1811             case 4:
1812                 val = read_raw_int(rawdata, ofs, n);
1813                 if (val)
1814                     MSI_RecordSetInteger( rec, i+1, val^0x80000000 );
1815                 TRACE(" field %d [0x%08x]\n", i+1, val );
1816                 break;
1817             default:
1818                 ERR("oops - unknown column width %d\n", n);
1819                 break;
1820             }
1821             ofs += n;
1822         }
1823     }
1824     return rec;
1825 }
1826
1827 static void dump_record( MSIRECORD *rec )
1828 {
1829     UINT i, n;
1830
1831     n = MSI_RecordGetFieldCount( rec );
1832     for( i=1; i<=n; i++ )
1833     {
1834         LPCWSTR sval = MSI_RecordGetString( rec, i );
1835
1836         if( MSI_RecordIsNull( rec, i ) )
1837             TRACE("row -> []\n");
1838         else if( (sval = MSI_RecordGetString( rec, i )) )
1839             TRACE("row -> [%s]\n", debugstr_w(sval));
1840         else
1841             TRACE("row -> [0x%08x]\n", MSI_RecordGetInteger( rec, i ) );
1842     }
1843 }
1844
1845 static void dump_table( const string_table *st, const USHORT *rawdata, UINT rawsize )
1846 {
1847     LPCWSTR sval;
1848     UINT i;
1849
1850     for( i=0; i<(rawsize/2); i++ )
1851     {
1852         sval = msi_string_lookup_id( st, rawdata[i] );
1853         MESSAGE(" %04x %s\n", rawdata[i], debugstr_w(sval) );
1854     }
1855 }
1856
1857 static UINT* msi_record_to_row( const MSITABLEVIEW *tv, MSIRECORD *rec )
1858 {
1859     LPCWSTR str;
1860     UINT i, r, *data;
1861
1862     data = msi_alloc( tv->num_cols *sizeof (UINT) );
1863     for( i=0; i<tv->num_cols; i++ )
1864     {
1865         data[i] = 0;
1866
1867         if ( ~tv->columns[i].type & MSITYPE_KEY )
1868             continue;
1869
1870         /* turn the transform column value into a row value */
1871         if ( ( tv->columns[i].type & MSITYPE_STRING ) &&
1872              ! MSITYPE_IS_BINARY(tv->columns[i].type) )
1873         {
1874             str = MSI_RecordGetString( rec, i+1 );
1875             r = msi_string2idW( tv->db->strings, str, &data[i] );
1876
1877             /* if there's no matching string in the string table,
1878                these keys can't match any record, so fail now. */
1879             if( ERROR_SUCCESS != r )
1880             {
1881                 msi_free( data );
1882                 return NULL;
1883             }
1884         }
1885         else
1886         {
1887             data[i] = MSI_RecordGetInteger( rec, i+1 );
1888             if ((tv->columns[i].type&0xff) == 2)
1889                 data[i] += 0x8000;
1890             else
1891                 data[i] += 0x80000000;
1892         }
1893     }
1894     return data;
1895 }
1896
1897 static UINT msi_row_matches( MSITABLEVIEW *tv, UINT row, const UINT *data )
1898 {
1899     UINT i, r, x, ret = ERROR_FUNCTION_FAILED;
1900
1901     for( i=0; i<tv->num_cols; i++ )
1902     {
1903         if ( ~tv->columns[i].type & MSITYPE_KEY )
1904             continue;
1905
1906         /* turn the transform column value into a row value */
1907         r = TABLE_fetch_int( &tv->view, row, i+1, &x );
1908         if ( r != ERROR_SUCCESS )
1909         {
1910             ERR("TABLE_fetch_int shouldn't fail here\n");
1911             break;
1912         }
1913
1914         /* if this key matches, move to the next column */
1915         if ( x != data[i] )
1916         {
1917             ret = ERROR_FUNCTION_FAILED;
1918             break;
1919         }
1920
1921         ret = ERROR_SUCCESS;
1922     }
1923
1924     return ret;
1925 }
1926
1927 static UINT msi_table_find_row( MSITABLEVIEW *tv, MSIRECORD *rec, UINT *row )
1928 {
1929     UINT i, r = ERROR_FUNCTION_FAILED, *data;
1930
1931     data = msi_record_to_row( tv, rec );
1932     if( !data )
1933         return r;
1934     for( i = 0; i < tv->table->row_count + tv->table->nonpersistent_row_count; i++ )
1935     {
1936         r = msi_row_matches( tv, i, data );
1937         if( r == ERROR_SUCCESS )
1938         {
1939             *row = i;
1940             break;
1941         }
1942     }
1943     msi_free( data );
1944     return r;
1945 }
1946
1947 static void msi_update_table_columns( MSIDATABASE *db, LPWSTR name )
1948 {
1949     MSITABLE *table;
1950     UINT size, offset;
1951     int n;
1952
1953     table = find_cached_table( db, name );
1954     msi_free( table->colinfo );
1955     table_get_column_info( db, name, &table->colinfo, &table->col_count );
1956
1957     size = msi_table_get_row_size( table->colinfo, table->col_count );
1958     offset = table->colinfo[table->col_count - 1].offset;
1959
1960     for ( n = 0; n < table->row_count; n++ )
1961     {
1962         table->data[n] = msi_realloc( table->data[n], size );
1963         table->data[n][offset] = (BYTE)MSI_NULL_INTEGER;
1964     }
1965 }
1966
1967 typedef struct
1968 {
1969     struct list entry;
1970     LPWSTR name;
1971 } TRANSFORMDATA;
1972
1973 static UINT msi_table_load_transform( MSIDATABASE *db, IStorage *stg,
1974                                       string_table *st, TRANSFORMDATA *transform,
1975                                       UINT bytes_per_strref )
1976 {
1977     UINT rawsize = 0;
1978     BYTE *rawdata = NULL;
1979     MSITABLEVIEW *tv = NULL;
1980     UINT r, n, sz, i, mask;
1981     MSIRECORD *rec = NULL;
1982     UINT colcol = 0;
1983     WCHAR coltable[32];
1984     LPWSTR name = transform->name;
1985
1986     coltable[0] = 0;
1987     TRACE("%p %p %p %s\n", db, stg, st, debugstr_w(name) );
1988
1989     /* read the transform data */
1990     read_stream_data( stg, name, &rawdata, &rawsize );
1991     if ( !rawdata )
1992     {
1993         TRACE("table %s empty\n", debugstr_w(name) );
1994         return ERROR_INVALID_TABLE;
1995     }
1996
1997     /* create a table view */
1998     r = TABLE_CreateView( db, name, (MSIVIEW**) &tv );
1999     if( r != ERROR_SUCCESS )
2000         goto err;
2001
2002     r = tv->view.ops->execute( &tv->view, NULL );
2003     if( r != ERROR_SUCCESS )
2004         goto err;
2005
2006     TRACE("name = %s columns = %u row_size = %u raw size = %u\n",
2007           debugstr_w(name), tv->num_cols, tv->row_size, rawsize );
2008
2009     /* interpret the data */
2010     r = ERROR_SUCCESS;
2011     for( n=0; n < rawsize;  )
2012     {
2013         mask = rawdata[n] | (rawdata[n+1] << 8);
2014
2015         if (mask&1)
2016         {
2017             /*
2018              * if the low bit is set, columns are continuous and
2019              * the number of columns is specified in the high byte
2020              */
2021             sz = 2;
2022             for( i=0; i<tv->num_cols; i++ )
2023             {
2024                 if( (tv->columns[i].type & MSITYPE_STRING) &&
2025                     ! MSITYPE_IS_BINARY(tv->columns[i].type) )
2026                     sz += bytes_per_strref;
2027                 else
2028                     sz += bytes_per_column( &tv->columns[i] );
2029             }
2030         }
2031         else
2032         {
2033             /*
2034              * If the low bit is not set, mask is a bitmask.
2035              * Excepting for key fields, which are always present,
2036              *  each bit indicates that a field is present in the transform record.
2037              *
2038              * mask == 0 is a special case ... only the keys will be present
2039              * and it means that this row should be deleted.
2040              */
2041             sz = 2;
2042             for( i=0; i<tv->num_cols; i++ )
2043             {
2044                 if( (tv->columns[i].type & MSITYPE_KEY) || ((1<<i)&mask))
2045                 {
2046                     if( (tv->columns[i].type & MSITYPE_STRING) &&
2047                         ! MSITYPE_IS_BINARY(tv->columns[i].type) )
2048                         sz += bytes_per_strref;
2049                     else
2050                         sz += bytes_per_column( &tv->columns[i] );
2051                 }
2052             }
2053         }
2054
2055         /* check we didn't run of the end of the table */
2056         if ( (n+sz) > rawsize )
2057         {
2058             ERR("borked.\n");
2059             dump_table( st, (USHORT *)rawdata, rawsize );
2060             break;
2061         }
2062
2063         rec = msi_get_transform_record( tv, st, &rawdata[n], bytes_per_strref );
2064         if (rec)
2065         {
2066             if ( mask & 1 )
2067             {
2068                 WCHAR table[32];
2069                 DWORD sz = 32;
2070                 UINT number = MSI_NULL_INTEGER;
2071
2072                 TRACE("inserting record\n");
2073
2074                 if (!lstrcmpW(name, szColumns))
2075                 {
2076                     MSI_RecordGetStringW( rec, 1, table, &sz );
2077                     number = MSI_RecordGetInteger( rec, 2 );
2078
2079                     /*
2080                      * Native msi seems writes nul into the Number (2nd) column of
2081                      * the _Columns table, only when the columns are from a new table
2082                      */
2083                     if ( number == MSI_NULL_INTEGER )
2084                     {
2085                         /* reset the column number on a new table */
2086                         if ( lstrcmpW(coltable, table) )
2087                         {
2088                             colcol = 0;
2089                             lstrcpyW( coltable, table );
2090                         }
2091
2092                         /* fix nul column numbers */
2093                         MSI_RecordSetInteger( rec, 2, ++colcol );
2094                     }
2095                 }
2096
2097                 r = TABLE_insert_row( &tv->view, rec, FALSE );
2098                 if (r != ERROR_SUCCESS)
2099                     ERR("insert row failed\n");
2100
2101                 if ( number != MSI_NULL_INTEGER && !lstrcmpW(name, szColumns) )
2102                     msi_update_table_columns( db, table );
2103             }
2104             else
2105             {
2106                 UINT row = 0;
2107
2108                 r = msi_table_find_row( tv, rec, &row );
2109                 if (r != ERROR_SUCCESS)
2110                     ERR("no matching row to transform\n");
2111                 else if ( mask )
2112                 {
2113                     TRACE("modifying row [%d]:\n", row);
2114                     TABLE_set_row( &tv->view, row, rec, mask );
2115                 }
2116                 else
2117                 {
2118                     TRACE("deleting row [%d]:\n", row);
2119                     TABLE_delete_row( &tv->view, row );
2120                 }
2121             }
2122             if( TRACE_ON(msidb) ) dump_record( rec );
2123             msiobj_release( &rec->hdr );
2124         }
2125
2126         n += sz;
2127     }
2128
2129 err:
2130     /* no need to free the table, it's associated with the database */
2131     msi_free( rawdata );
2132     if( tv )
2133         tv->view.ops->delete( &tv->view );
2134
2135     return ERROR_SUCCESS;
2136 }
2137
2138 /*
2139  * msi_table_apply_transform
2140  *
2141  * Enumerate the table transforms in a transform storage and apply each one.
2142  */
2143 UINT msi_table_apply_transform( MSIDATABASE *db, IStorage *stg )
2144 {
2145     struct list transforms;
2146     IEnumSTATSTG *stgenum = NULL;
2147     TRANSFORMDATA *transform;
2148     TRANSFORMDATA *tables = NULL, *columns = NULL;
2149     HRESULT r;
2150     STATSTG stat;
2151     string_table *strings;
2152     UINT ret = ERROR_FUNCTION_FAILED;
2153     UINT bytes_per_strref;
2154
2155     TRACE("%p %p\n", db, stg );
2156
2157     strings = msi_load_string_table( stg, &bytes_per_strref );
2158     if( !strings )
2159         goto end;
2160
2161     r = IStorage_EnumElements( stg, 0, NULL, 0, &stgenum );
2162     if( FAILED( r ) )
2163         goto end;
2164
2165     list_init(&transforms);
2166
2167     while ( TRUE )
2168     {
2169         MSITABLEVIEW *tv = NULL;
2170         WCHAR name[0x40];
2171         ULONG count = 0;
2172
2173         r = IEnumSTATSTG_Next( stgenum, 1, &stat, &count );
2174         if ( FAILED( r ) || !count )
2175             break;
2176
2177         decode_streamname( stat.pwcsName, name );
2178         if ( name[0] != 0x4840 )
2179             continue;
2180
2181         if ( !lstrcmpW( name+1, szStringPool ) ||
2182              !lstrcmpW( name+1, szStringData ) )
2183             continue;
2184
2185         transform = msi_alloc_zero( sizeof(TRANSFORMDATA) );
2186         if ( !transform )
2187             break;
2188
2189         list_add_tail( &transforms, &transform->entry );
2190
2191         transform->name = strdupW( name + 1 );
2192
2193         if ( !lstrcmpW( transform->name, szTables ) )
2194             tables = transform;
2195         else if (!lstrcmpW( transform->name, szColumns ) )
2196             columns = transform;
2197
2198         TRACE("transform contains stream %s\n", debugstr_w(name));
2199
2200         /* load the table */
2201         r = TABLE_CreateView( db, transform->name, (MSIVIEW**) &tv );
2202         if( r != ERROR_SUCCESS )
2203             continue;
2204
2205         r = tv->view.ops->execute( &tv->view, NULL );
2206         if( r != ERROR_SUCCESS )
2207         {
2208             tv->view.ops->delete( &tv->view );
2209             continue;
2210         }
2211
2212         tv->view.ops->delete( &tv->view );
2213     }
2214
2215     /*
2216      * Apply _Tables and _Columns transforms first so that
2217      * the table metadata is correct, and empty tables exist.
2218      */
2219     ret = msi_table_load_transform( db, stg, strings, tables, bytes_per_strref );
2220     if (ret != ERROR_SUCCESS && ret != ERROR_INVALID_TABLE)
2221         goto end;
2222
2223     ret = msi_table_load_transform( db, stg, strings, columns, bytes_per_strref );
2224     if (ret != ERROR_SUCCESS && ret != ERROR_INVALID_TABLE)
2225         goto end;
2226
2227     ret = ERROR_SUCCESS;
2228
2229     while ( !list_empty( &transforms ) )
2230     {
2231         transform = LIST_ENTRY( list_head( &transforms ), TRANSFORMDATA, entry );
2232
2233         if ( lstrcmpW( transform->name, szColumns ) &&
2234              lstrcmpW( transform->name, szTables ) &&
2235              ret == ERROR_SUCCESS )
2236         {
2237             ret = msi_table_load_transform( db, stg, strings, transform, bytes_per_strref );
2238         }
2239
2240         list_remove( &transform->entry );
2241         msi_free( transform->name );
2242         msi_free( transform );
2243     }
2244
2245     if ( ret == ERROR_SUCCESS )
2246         append_storage_to_db( db, stg );
2247
2248 end:
2249     if ( stgenum )
2250         IEnumSTATSTG_Release( stgenum );
2251     if ( strings )
2252         msi_destroy_stringtable( strings );
2253
2254     return ret;
2255 }
2256
2257 void append_storage_to_db( MSIDATABASE *db, IStorage *stg )
2258 {
2259     MSITRANSFORM *t;
2260
2261     t = msi_alloc( sizeof *t );
2262     t->stg = stg;
2263     IStorage_AddRef( stg );
2264     list_add_tail( &db->transforms, &t->entry );
2265 }
2266
2267 void msi_free_transforms( MSIDATABASE *db )
2268 {
2269     while( !list_empty( &db->transforms ) )
2270     {
2271         MSITRANSFORM *t = LIST_ENTRY( list_head( &db->transforms ),
2272                                       MSITRANSFORM, entry );
2273         list_remove( &t->entry );
2274         IStorage_Release( t->stg );
2275         msi_free( t );
2276     }
2277 }