wined3d: Fix a bug in BtlFast which was uncovered by the 32-bit dibsection support.
[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     LPWSTR tablename;
57     UINT   number;
58     LPWSTR colname;
59     UINT   type;
60     UINT   offset;
61     INT    ref_count;
62     BOOL   temporary;
63     MSICOLUMNHASHENTRY **hash_table;
64 } MSICOLUMNINFO;
65
66 typedef struct tagMSIORDERINFO
67 {
68     UINT *reorder;
69     UINT num_cols;
70     UINT cols[1];
71 } MSIORDERINFO;
72
73 struct tagMSITABLE
74 {
75     BYTE **data;
76     BOOL *data_persistent;
77     UINT row_count;
78     struct list entry;
79     MSICOLUMNINFO *colinfo;
80     UINT col_count;
81     MSICONDITION persistent;
82     INT ref_count;
83     WCHAR name[1];
84 };
85
86 typedef struct tagMSITRANSFORM {
87     struct list entry;
88     IStorage *stg;
89 } MSITRANSFORM;
90
91 typedef struct tagMSISTREAM {
92     struct list entry;
93     IStream *stm;
94 } MSISTREAM;
95
96 static const WCHAR szStringData[] = {
97     '_','S','t','r','i','n','g','D','a','t','a',0 };
98 static const WCHAR szStringPool[] = {
99     '_','S','t','r','i','n','g','P','o','o','l',0 };
100
101 /* information for default tables */
102 static WCHAR szTables[]  = { '_','T','a','b','l','e','s',0 };
103 static WCHAR szTable[]  = { 'T','a','b','l','e',0 };
104 static WCHAR szName[]    = { 'N','a','m','e',0 };
105 static WCHAR szColumns[] = { '_','C','o','l','u','m','n','s',0 };
106 static WCHAR szNumber[]  = { 'N','u','m','b','e','r',0 };
107 static WCHAR szType[]    = { 'T','y','p','e',0 };
108
109 static const MSICOLUMNINFO _Columns_cols[4] = {
110     { szColumns, 1, szTable,  MSITYPE_VALID | MSITYPE_STRING | MSITYPE_KEY | 64, 0, 0, 0, NULL },
111     { szColumns, 2, szNumber, MSITYPE_VALID | MSITYPE_KEY | 2,     2, 0, 0, NULL },
112     { szColumns, 3, szName,   MSITYPE_VALID | MSITYPE_STRING | 64, 4, 0, 0, NULL },
113     { szColumns, 4, szType,   MSITYPE_VALID | 2,                   6, 0, 0, NULL },
114 };
115
116 static const MSICOLUMNINFO _Tables_cols[1] = {
117     { szTables,  1, szName,   MSITYPE_VALID | MSITYPE_STRING | MSITYPE_KEY | 64, 0, 0, 0, NULL },
118 };
119
120 #define MAX_STREAM_NAME 0x1f
121
122 static UINT table_get_column_info( MSIDATABASE *db, LPCWSTR name,
123        MSICOLUMNINFO **pcols, UINT *pcount );
124 static void table_calc_column_offsets( MSIDATABASE *db, MSICOLUMNINFO *colinfo,
125        DWORD count );
126 static UINT get_tablecolumns( MSIDATABASE *db,
127        LPCWSTR szTableName, MSICOLUMNINFO *colinfo, UINT *sz);
128 static void msi_free_colinfo( MSICOLUMNINFO *colinfo, UINT count );
129
130 static inline UINT bytes_per_column( MSIDATABASE *db, const MSICOLUMNINFO *col )
131 {
132     if( MSITYPE_IS_BINARY(col->type) )
133         return 2;
134
135     if( col->type & MSITYPE_STRING )
136         return db->bytes_per_strref;
137
138     if( (col->type & 0xff) <= 2)
139         return 2;
140
141     if( (col->type & 0xff) != 4 )
142         ERR("Invalid column size!\n");
143
144     return 4;
145 }
146
147 static int utf2mime(int x)
148 {
149     if( (x>='0') && (x<='9') )
150         return x-'0';
151     if( (x>='A') && (x<='Z') )
152         return x-'A'+10;
153     if( (x>='a') && (x<='z') )
154         return x-'a'+10+26;
155     if( x=='.' )
156         return 10+26+26;
157     if( x=='_' )
158         return 10+26+26+1;
159     return -1;
160 }
161
162 static LPWSTR encode_streamname(BOOL bTable, LPCWSTR in)
163 {
164     DWORD count = MAX_STREAM_NAME;
165     DWORD ch, next;
166     LPWSTR out, p;
167
168     if( !bTable )
169         count = lstrlenW( in )+2;
170     out = msi_alloc( count*sizeof(WCHAR) );
171     p = out;
172
173     if( bTable )
174     {
175          *p++ = 0x4840;
176          count --;
177     }
178     while( count -- ) 
179     {
180         ch = *in++;
181         if( !ch )
182         {
183             *p = ch;
184             return out;
185         }
186         if( ( ch < 0x80 ) && ( utf2mime(ch) >= 0 ) )
187         {
188             ch = utf2mime(ch) + 0x4800;
189             next = *in;
190             if( next && (next<0x80) )
191             {
192                 next = utf2mime(next);
193                 if( next != -1 )
194                 {
195                      next += 0x3ffffc0;
196                      ch += (next<<6);
197                      in++;
198                 }
199             }
200         }
201         *p++ = ch;
202     }
203     ERR("Failed to encode stream name (%s)\n",debugstr_w(in));
204     msi_free( out );
205     return NULL;
206 }
207
208 static int mime2utf(int x)
209 {
210     if( x<10 )
211         return x + '0';
212     if( x<(10+26))
213         return x - 10 + 'A';
214     if( x<(10+26+26))
215         return x - 10 - 26 + 'a';
216     if( x == (10+26+26) )
217         return '.';
218     return '_';
219 }
220
221 BOOL decode_streamname(LPCWSTR in, LPWSTR out)
222 {
223     WCHAR ch;
224     DWORD count = 0;
225
226     while ( (ch = *in++) )
227     {
228         if( (ch >= 0x3800 ) && (ch < 0x4840 ) )
229         {
230             if( ch >= 0x4800 )
231                 ch = mime2utf(ch-0x4800);
232             else
233             {
234                 ch -= 0x3800;
235                 *out++ = mime2utf(ch&0x3f);
236                 count++;
237                 ch = mime2utf((ch>>6)&0x3f);
238             }
239         }
240         *out++ = ch;
241         count++;
242     }
243     *out = 0;
244     return count;
245 }
246
247 void enum_stream_names( IStorage *stg )
248 {
249     IEnumSTATSTG *stgenum = NULL;
250     HRESULT r;
251     STATSTG stat;
252     ULONG n, count;
253     WCHAR name[0x40];
254
255     r = IStorage_EnumElements( stg, 0, NULL, 0, &stgenum );
256     if( FAILED( r ) )
257         return;
258
259     n = 0;
260     while( 1 )
261     {
262         count = 0;
263         r = IEnumSTATSTG_Next( stgenum, 1, &stat, &count );
264         if( FAILED( r ) || !count )
265             break;
266         decode_streamname( stat.pwcsName, name );
267         TRACE("stream %2d -> %s %s\n", n,
268               debugstr_w(stat.pwcsName), debugstr_w(name) );
269         CoTaskMemFree( stat.pwcsName );
270         n++;
271     }
272
273     IEnumSTATSTG_Release( stgenum );
274 }
275
276 UINT read_stream_data( IStorage *stg, LPCWSTR stname, BOOL table,
277                        BYTE **pdata, UINT *psz )
278 {
279     HRESULT r;
280     UINT ret = ERROR_FUNCTION_FAILED;
281     VOID *data;
282     ULONG sz, count;
283     IStream *stm = NULL;
284     STATSTG stat;
285     LPWSTR encname;
286
287     encname = encode_streamname(table, stname);
288
289     TRACE("%s -> %s\n",debugstr_w(stname),debugstr_w(encname));
290
291     r = IStorage_OpenStream(stg, encname, NULL, 
292             STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm);
293     msi_free( encname );
294     if( FAILED( r ) )
295     {
296         WARN("open stream failed r = %08x - empty table?\n", r);
297         return ret;
298     }
299
300     r = IStream_Stat(stm, &stat, STATFLAG_NONAME );
301     if( FAILED( r ) )
302     {
303         WARN("open stream failed r = %08x!\n", r);
304         goto end;
305     }
306
307     if( stat.cbSize.QuadPart >> 32 )
308     {
309         WARN("Too big!\n");
310         goto end;
311     }
312         
313     sz = stat.cbSize.QuadPart;
314     data = msi_alloc( sz );
315     if( !data )
316     {
317         WARN("couldn't allocate memory r=%08x!\n", r);
318         ret = ERROR_NOT_ENOUGH_MEMORY;
319         goto end;
320     }
321         
322     r = IStream_Read(stm, data, sz, &count );
323     if( FAILED( r ) || ( count != sz ) )
324     {
325         msi_free( data );
326         WARN("read stream failed r = %08x!\n", r);
327         goto end;
328     }
329
330     *pdata = data;
331     *psz = sz;
332     ret = ERROR_SUCCESS;
333
334 end:
335     IStream_Release( stm );
336
337     return ret;
338 }
339
340 static UINT find_open_stream( MSIDATABASE *db, LPCWSTR name, IStream **stm )
341 {
342     MSISTREAM *stream;
343
344     LIST_FOR_EACH_ENTRY( stream, &db->streams, MSISTREAM, entry )
345     {
346         HRESULT r;
347         STATSTG stat;
348
349         r = IStream_Stat( stream->stm, &stat, 0 );
350         if( FAILED( r ) )
351         {
352             WARN("failed to stat stream r = %08x!\n", r);
353             continue;
354         }
355
356         if( !lstrcmpW( name, stat.pwcsName ) )
357         {
358             TRACE("found %s\n", debugstr_w(name));
359             *stm = stream->stm;
360             CoTaskMemFree( stat.pwcsName );
361             return ERROR_SUCCESS;
362         }
363
364         CoTaskMemFree( stat.pwcsName );
365     }
366
367     return ERROR_FUNCTION_FAILED;
368 }
369
370 static UINT clone_open_stream( MSIDATABASE *db, LPCWSTR name, IStream **stm )
371 {
372     IStream *stream;
373
374     if (find_open_stream( db, name, &stream ) == ERROR_SUCCESS)
375     {
376         HRESULT r;
377         LARGE_INTEGER pos;
378
379         r = IStream_Clone( stream, stm );
380         if( FAILED( r ) )
381         {
382             WARN("failed to clone stream r = %08x!\n", r);
383             return ERROR_FUNCTION_FAILED;
384         }
385
386         pos.QuadPart = 0;
387         r = IStream_Seek( *stm, pos, STREAM_SEEK_SET, NULL );
388         if( FAILED( r ) )
389         {
390             IStream_Release( *stm );
391             return ERROR_FUNCTION_FAILED;
392         }
393
394         return ERROR_SUCCESS;
395     }
396
397     return ERROR_FUNCTION_FAILED;
398 }
399
400 static UINT db_get_raw_stream( MSIDATABASE *db, LPCWSTR stname, IStream **stm )
401 {
402     LPWSTR encname;
403     HRESULT r;
404
405     encname = encode_streamname(FALSE, stname);
406
407     TRACE("%s -> %s\n",debugstr_w(stname),debugstr_w(encname));
408
409     if (clone_open_stream( db, encname, stm ) == ERROR_SUCCESS)
410     {
411         msi_free( encname );
412         return ERROR_SUCCESS;
413     }
414
415     r = IStorage_OpenStream(db->storage, encname, NULL, 
416             STGM_READ | STGM_SHARE_EXCLUSIVE, 0, stm);
417     if( FAILED( r ) )
418     {
419         MSITRANSFORM *transform;
420
421         LIST_FOR_EACH_ENTRY( transform, &db->transforms, MSITRANSFORM, entry )
422         {
423             TRACE("looking for %s in transform storage\n", debugstr_w(stname) );
424             r = IStorage_OpenStream( transform->stg, encname, NULL, 
425                     STGM_READ | STGM_SHARE_EXCLUSIVE, 0, stm );
426             if (SUCCEEDED(r))
427                 break;
428         }
429     }
430
431     msi_free( encname );
432
433     if( SUCCEEDED(r) )
434     {
435         MSISTREAM *stream;
436
437         stream = msi_alloc( sizeof(MSISTREAM) );
438         if( !stream )
439             return ERROR_NOT_ENOUGH_MEMORY;
440
441         stream->stm = *stm;
442         IStream_AddRef( *stm );
443         list_add_tail( &db->streams, &stream->entry );
444     }
445
446     return ERROR_SUCCESS;
447 }
448
449 UINT read_raw_stream_data( MSIDATABASE *db, LPCWSTR stname,
450                               USHORT **pdata, UINT *psz )
451 {
452     HRESULT r;
453     UINT ret = ERROR_FUNCTION_FAILED;
454     VOID *data;
455     ULONG sz, count;
456     IStream *stm = NULL;
457     STATSTG stat;
458
459     r = db_get_raw_stream( db, stname, &stm );
460     if( r != ERROR_SUCCESS)
461         return ret;
462     r = IStream_Stat(stm, &stat, STATFLAG_NONAME );
463     if( FAILED( r ) )
464     {
465         WARN("open stream failed r = %08x!\n", r);
466         goto end;
467     }
468
469     if( stat.cbSize.QuadPart >> 32 )
470     {
471         WARN("Too big!\n");
472         goto end;
473     }
474         
475     sz = stat.cbSize.QuadPart;
476     data = msi_alloc( sz );
477     if( !data )
478     {
479         WARN("couldn't allocate memory r=%08x!\n", r);
480         ret = ERROR_NOT_ENOUGH_MEMORY;
481         goto end;
482     }
483         
484     r = IStream_Read(stm, data, sz, &count );
485     if( FAILED( r ) || ( count != sz ) )
486     {
487         msi_free( data );
488         WARN("read stream failed r = %08x!\n", r);
489         goto end;
490     }
491
492     *pdata = data;
493     *psz = sz;
494     ret = ERROR_SUCCESS;
495
496 end:
497     IStream_Release( stm );
498
499     return ret;
500 }
501
502 UINT write_stream_data( IStorage *stg, LPCWSTR stname,
503                         LPCVOID data, UINT sz, BOOL bTable )
504 {
505     HRESULT r;
506     UINT ret = ERROR_FUNCTION_FAILED;
507     ULONG count;
508     IStream *stm = NULL;
509     ULARGE_INTEGER size;
510     LARGE_INTEGER pos;
511     LPWSTR encname;
512
513     encname = encode_streamname(bTable, stname );
514     r = IStorage_OpenStream( stg, encname, NULL, 
515             STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, &stm);
516     if( FAILED(r) )
517     {
518         r = IStorage_CreateStream( stg, encname,
519                 STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stm);
520     }
521     msi_free( encname );
522     if( FAILED( r ) )
523     {
524         WARN("open stream failed r = %08x\n", r);
525         return ret;
526     }
527
528     size.QuadPart = sz;
529     r = IStream_SetSize( stm, size );
530     if( FAILED( r ) )
531     {
532         WARN("Failed to SetSize\n");
533         goto end;
534     }
535
536     pos.QuadPart = 0;
537     r = IStream_Seek( stm, pos, STREAM_SEEK_SET, NULL );
538     if( FAILED( r ) )
539     {
540         WARN("Failed to Seek\n");
541         goto end;
542     }
543
544     if (sz)
545     {
546         r = IStream_Write(stm, data, sz, &count );
547         if( FAILED( r ) || ( count != sz ) )
548         {
549             WARN("Failed to Write\n");
550             goto end;
551         }
552     }
553
554     ret = ERROR_SUCCESS;
555
556 end:
557     IStream_Release( stm );
558
559     return ret;
560 }
561
562 static void free_table( MSITABLE *table )
563 {
564     UINT i;
565     for( i=0; i<table->row_count; i++ )
566         msi_free( table->data[i] );
567     msi_free( table->data );
568     msi_free( table->data_persistent );
569     msi_free_colinfo( table->colinfo, table->col_count );
570     msi_free( table->colinfo );
571     msi_free( table );
572 }
573
574 static UINT msi_table_get_row_size( MSIDATABASE *db,const MSICOLUMNINFO *cols,
575                                     UINT count )
576 {
577     const MSICOLUMNINFO *last_col = &cols[count-1];
578     if (!count)
579         return 0;
580     return last_col->offset + bytes_per_column( db, last_col );
581 }
582
583 /* add this table to the list of cached tables in the database */
584 static UINT read_table_from_storage( MSIDATABASE *db, MSITABLE *t, IStorage *stg )
585 {
586     BYTE *rawdata = NULL;
587     UINT rawsize = 0, i, j, row_size = 0;
588
589     TRACE("%s\n",debugstr_w(t->name));
590
591     row_size = msi_table_get_row_size( db, t->colinfo, t->col_count );
592
593     /* if we can't read the table, just assume that it's empty */
594     read_stream_data( stg, t->name, TRUE, &rawdata, &rawsize );
595     if( !rawdata )
596         return ERROR_SUCCESS;
597
598     TRACE("Read %d bytes\n", rawsize );
599
600     if( rawsize % row_size )
601     {
602         WARN("Table size is invalid %d/%d\n", rawsize, row_size );
603         goto err;
604     }
605
606     t->row_count = rawsize / row_size;
607     t->data = msi_alloc_zero( t->row_count * sizeof (USHORT*) );
608     if( !t->data )
609         goto err;
610     t->data_persistent = msi_alloc_zero( t->row_count * sizeof(BOOL));
611     if ( !t->data_persistent )
612         goto err;
613
614     /* transpose all the data */
615     TRACE("Transposing data from %d rows\n", t->row_count );
616     for( i=0; i<t->row_count; i++ )
617     {
618         t->data[i] = msi_alloc( row_size );
619         if( !t->data[i] )
620             goto err;
621         t->data_persistent[i] = TRUE;
622
623         for( j=0; j<t->col_count; j++ )
624         {
625             UINT ofs = t->colinfo[j].offset;
626             UINT n = bytes_per_column( db, &t->colinfo[j] );
627             UINT k;
628
629             if ( n != 2 && n != 3 && n != 4 )
630             {
631                 ERR("oops - unknown column width %d\n", n);
632                 goto err;
633             }
634
635             for ( k = 0; k < n; k++ )
636                 t->data[i][ofs + k] = rawdata[ofs*t->row_count + i * n + k];
637         }
638     }
639
640     msi_free( rawdata );
641     return ERROR_SUCCESS;
642 err:
643     msi_free( rawdata );
644     return ERROR_FUNCTION_FAILED;
645 }
646
647 void free_cached_tables( MSIDATABASE *db )
648 {
649     while( !list_empty( &db->tables ) )
650     {
651         MSITABLE *t = LIST_ENTRY( list_head( &db->tables ), MSITABLE, entry );
652
653         list_remove( &t->entry );
654         free_table( t );
655     }
656 }
657
658 static MSITABLE *find_cached_table( MSIDATABASE *db, LPCWSTR name )
659 {
660     MSITABLE *t;
661
662     LIST_FOR_EACH_ENTRY( t, &db->tables, MSITABLE, entry )
663         if( !lstrcmpW( name, t->name ) )
664             return t;
665
666     return NULL;
667 }
668
669 static UINT table_get_column_info( MSIDATABASE *db, LPCWSTR name, MSICOLUMNINFO **pcols, UINT *pcount )
670 {
671     UINT r, column_count = 0;
672     MSICOLUMNINFO *columns;
673
674     /* get the number of columns in this table */
675     column_count = 0;
676     r = get_tablecolumns( db, name, NULL, &column_count );
677     if( r != ERROR_SUCCESS )
678         return r;
679
680     *pcount = column_count;
681
682     /* if there's no columns, there's no table */
683     if( column_count == 0 )
684         return ERROR_INVALID_PARAMETER;
685
686     TRACE("Table %s found\n", debugstr_w(name) );
687
688     columns = msi_alloc( column_count*sizeof (MSICOLUMNINFO) );
689     if( !columns )
690         return ERROR_FUNCTION_FAILED;
691
692     r = get_tablecolumns( db, name, columns, &column_count );
693     if( r != ERROR_SUCCESS )
694     {
695         msi_free( columns );
696         return ERROR_FUNCTION_FAILED;
697     }
698
699     *pcols = columns;
700
701     return r;
702 }
703
704 UINT msi_create_table( MSIDATABASE *db, LPCWSTR name, column_info *col_info,
705                        MSICONDITION persistent, MSITABLE **table_ret)
706 {
707     UINT r, nField;
708     MSIVIEW *tv = NULL;
709     MSIRECORD *rec = NULL;
710     column_info *col;
711     MSITABLE *table;
712     UINT i;
713
714     /* only add tables that don't exist already */
715     if( TABLE_Exists(db, name ) )
716     {
717         WARN("table %s exists\n", debugstr_w(name));
718         return ERROR_BAD_QUERY_SYNTAX;
719     }
720
721     table = msi_alloc( sizeof (MSITABLE) + lstrlenW(name)*sizeof (WCHAR) );
722     if( !table )
723         return ERROR_FUNCTION_FAILED;
724
725     table->ref_count = 1;
726     table->row_count = 0;
727     table->data = NULL;
728     table->data_persistent = NULL;
729     table->colinfo = NULL;
730     table->col_count = 0;
731     table->persistent = persistent;
732     lstrcpyW( table->name, name );
733
734     for( col = col_info; col; col = col->next )
735         table->col_count++;
736
737     table->colinfo = msi_alloc( table->col_count * sizeof(MSICOLUMNINFO) );
738     if (!table->colinfo)
739     {
740         free_table( table );
741         return ERROR_FUNCTION_FAILED;
742     }
743
744     for( i = 0, col = col_info; col; i++, col = col->next )
745     {
746         table->colinfo[ i ].tablename = strdupW( col->table );
747         table->colinfo[ i ].number = i + 1;
748         table->colinfo[ i ].colname = strdupW( col->column );
749         table->colinfo[ i ].type = col->type;
750         table->colinfo[ i ].offset = 0;
751         table->colinfo[ i ].ref_count = 0;
752         table->colinfo[ i ].hash_table = NULL;
753         table->colinfo[ i ].temporary = col->temporary;
754     }
755     table_calc_column_offsets( db, table->colinfo, table->col_count);
756
757     r = TABLE_CreateView( db, szTables, &tv );
758     TRACE("CreateView returned %x\n", r);
759     if( r )
760     {
761         free_table( table );
762         return r;
763     }
764
765     r = tv->ops->execute( tv, 0 );
766     TRACE("tv execute returned %x\n", r);
767     if( r )
768         goto err;
769
770     rec = MSI_CreateRecord( 1 );
771     if( !rec )
772         goto err;
773
774     r = MSI_RecordSetStringW( rec, 1, name );
775     if( r )
776         goto err;
777
778     r = tv->ops->insert_row( tv, rec, -1, persistent == MSICONDITION_FALSE );
779     TRACE("insert_row returned %x\n", r);
780     if( r )
781         goto err;
782
783     tv->ops->delete( tv );
784     tv = NULL;
785
786     msiobj_release( &rec->hdr );
787     rec = NULL;
788
789     if( persistent != MSICONDITION_FALSE )
790     {
791         /* add each column to the _Columns table */
792         r = TABLE_CreateView( db, szColumns, &tv );
793         if( r )
794             return r;
795
796         r = tv->ops->execute( tv, 0 );
797         TRACE("tv execute returned %x\n", r);
798         if( r )
799             goto err;
800
801         rec = MSI_CreateRecord( 4 );
802         if( !rec )
803             goto err;
804
805         r = MSI_RecordSetStringW( rec, 1, name );
806         if( r )
807             goto err;
808
809         /*
810          * need to set the table, column number, col name and type
811          * for each column we enter in the table
812          */
813         nField = 1;
814         for( col = col_info; col; col = col->next )
815         {
816             r = MSI_RecordSetInteger( rec, 2, nField );
817             if( r )
818                 goto err;
819
820             r = MSI_RecordSetStringW( rec, 3, col->column );
821             if( r )
822                 goto err;
823
824             r = MSI_RecordSetInteger( rec, 4, col->type );
825             if( r )
826                 goto err;
827
828             r = tv->ops->insert_row( tv, rec, -1, FALSE );
829             if( r )
830                 goto err;
831
832             nField++;
833         }
834         if( !col )
835             r = ERROR_SUCCESS;
836     }
837
838 err:
839     if (rec)
840         msiobj_release( &rec->hdr );
841     /* FIXME: remove values from the string table on error */
842     if( tv )
843         tv->ops->delete( tv );
844
845     if (r == ERROR_SUCCESS)
846     {
847         list_add_head( &db->tables, &table->entry );
848         *table_ret = table;
849     }
850     else
851         free_table( table );
852
853     return r;
854 }
855
856 static UINT get_table( MSIDATABASE *db, LPCWSTR name, MSITABLE **table_ret )
857 {
858     MSITABLE *table;
859     UINT r;
860
861     /* first, see if the table is cached */
862     table = find_cached_table( db, name );
863     if( table )
864     {
865         *table_ret = table;
866         return ERROR_SUCCESS;
867     }
868
869     /* nonexistent tables should be interpreted as empty tables */
870     table = msi_alloc( sizeof (MSITABLE) + lstrlenW(name)*sizeof (WCHAR) );
871     if( !table )
872         return ERROR_FUNCTION_FAILED;
873
874     table->row_count = 0;
875     table->data = NULL;
876     table->data_persistent = NULL;
877     table->colinfo = NULL;
878     table->col_count = 0;
879     table->persistent = MSICONDITION_TRUE;
880     lstrcpyW( table->name, name );
881
882     if ( !lstrcmpW(name, szTables) || !lstrcmpW(name, szColumns) )
883         table->persistent = MSICONDITION_NONE;
884
885     r = table_get_column_info( db, name, &table->colinfo, &table->col_count);
886     if (r != ERROR_SUCCESS)
887     {
888         free_table ( table );
889         return r;
890     }
891
892     r = read_table_from_storage( db, table, db->storage );
893     if( r != ERROR_SUCCESS )
894     {
895         free_table( table );
896         return r;
897     }
898
899     list_add_head( &db->tables, &table->entry );
900     *table_ret = table;
901     return ERROR_SUCCESS;
902 }
903
904 static UINT save_table( MSIDATABASE *db, const MSITABLE *t )
905 {
906     BYTE *rawdata = NULL, *p;
907     UINT rawsize, r, i, j, row_size;
908
909     /* Nothing to do for non-persistent tables */
910     if( t->persistent == MSICONDITION_FALSE )
911         return ERROR_SUCCESS;
912
913     TRACE("Saving %s\n", debugstr_w( t->name ) );
914
915     row_size = msi_table_get_row_size( db, t->colinfo, t->col_count );
916
917     rawsize = t->row_count * row_size;
918     rawdata = msi_alloc_zero( rawsize );
919     if( !rawdata )
920     {
921         r = ERROR_NOT_ENOUGH_MEMORY;
922         goto err;
923     }
924
925     rawsize = 0;
926     p = rawdata;
927     for( i=0; i<t->col_count; i++ )
928     {
929         for( j=0; j<t->row_count; j++ )
930         {
931             UINT offset = t->colinfo[i].offset;
932
933             if (!t->data_persistent[j]) continue;
934             if (i == 0)
935                 rawsize += row_size;
936
937             *p++ = t->data[j][offset];
938             *p++ = t->data[j][offset + 1];
939             if( 4 == bytes_per_column( db, &t->colinfo[i] ) )
940             {
941                 *p++ = t->data[j][offset + 2];
942                 *p++ = t->data[j][offset + 3];
943             }
944         }
945     }
946
947     TRACE("writing %d bytes\n", rawsize);
948     r = write_stream_data( db->storage, t->name, rawdata, rawsize, TRUE );
949
950 err:
951     msi_free( rawdata );
952
953     return r;
954 }
955
956 static void table_calc_column_offsets( MSIDATABASE *db, MSICOLUMNINFO *colinfo,
957                                        DWORD count )
958 {
959     DWORD i;
960
961     for( i=0; colinfo && (i<count); i++ )
962     {
963          assert( (i+1) == colinfo[ i ].number );
964          if (i)
965              colinfo[i].offset = colinfo[ i - 1 ].offset
966                                + bytes_per_column( db, &colinfo[ i - 1 ] );
967          else
968              colinfo[i].offset = 0;
969          TRACE("column %d is [%s] with type %08x ofs %d\n",
970                colinfo[i].number, debugstr_w(colinfo[i].colname),
971                colinfo[i].type, colinfo[i].offset);
972     }
973 }
974
975 static UINT get_defaulttablecolumns( MSIDATABASE *db, LPCWSTR name,
976                                      MSICOLUMNINFO *colinfo, UINT *sz)
977 {
978     const MSICOLUMNINFO *p;
979     DWORD i, n;
980
981     TRACE("%s\n", debugstr_w(name));
982
983     if (!lstrcmpW( name, szTables ))
984     {
985         p = _Tables_cols;
986         n = 1;
987     }
988     else if (!lstrcmpW( name, szColumns ))
989     {
990         p = _Columns_cols;
991         n = 4;
992     }
993     else
994         return ERROR_FUNCTION_FAILED;
995
996     /* duplicate the string data so we can free it in msi_free_colinfo */
997     for (i=0; i<n; i++)
998     {
999         if (colinfo && (i < *sz) )
1000         {
1001             colinfo[i] = p[i];
1002             colinfo[i].tablename = strdupW( p[i].tablename );
1003             colinfo[i].colname = strdupW( p[i].colname );
1004         }
1005         if( colinfo && (i >= *sz) )
1006             break;
1007     }
1008     table_calc_column_offsets( db, colinfo, n );
1009     *sz = n;
1010     return ERROR_SUCCESS;
1011 }
1012
1013 static void msi_free_colinfo( MSICOLUMNINFO *colinfo, UINT count )
1014 {
1015     UINT i;
1016
1017     for( i=0; i<count; i++ )
1018     {
1019         msi_free( colinfo[i].tablename );
1020         msi_free( colinfo[i].colname );
1021         msi_free( colinfo[i].hash_table );
1022     }
1023 }
1024
1025 static LPWSTR msi_makestring( const MSIDATABASE *db, UINT stringid)
1026 {
1027     return strdupW(msi_string_lookup_id( db->strings, stringid ));
1028 }
1029
1030 static UINT read_table_int(BYTE *const *data, UINT row, UINT col, UINT bytes)
1031 {
1032     UINT ret = 0, i;
1033
1034     for (i = 0; i < bytes; i++)
1035         ret += (data[row][col + i] << i * 8);
1036
1037     return ret;
1038 }
1039
1040 static UINT get_tablecolumns( MSIDATABASE *db,
1041        LPCWSTR szTableName, MSICOLUMNINFO *colinfo, UINT *sz)
1042 {
1043     UINT r, i, n=0, table_id, count, maxcount = *sz;
1044     MSITABLE *table = NULL;
1045
1046     TRACE("%s\n", debugstr_w(szTableName));
1047
1048     /* first check if there is a default table with that name */
1049     r = get_defaulttablecolumns( db, szTableName, colinfo, sz );
1050     if( ( r == ERROR_SUCCESS ) && *sz )
1051         return r;
1052
1053     r = get_table( db, szColumns, &table );
1054     if( r != ERROR_SUCCESS )
1055     {
1056         ERR("couldn't load _Columns table\n");
1057         return ERROR_FUNCTION_FAILED;
1058     }
1059
1060     /* convert table and column names to IDs from the string table */
1061     r = msi_string2idW( db->strings, szTableName, &table_id );
1062     if( r != ERROR_SUCCESS )
1063     {
1064         WARN("Couldn't find id for %s\n", debugstr_w(szTableName));
1065         return r;
1066     }
1067
1068     TRACE("Table id is %d, row count is %d\n", table_id, table->row_count);
1069
1070     /* Note: _Columns table doesn't have non-persistent data */
1071
1072     /* if maxcount is non-zero, assume it's exactly right for this table */
1073     memset( colinfo, 0, maxcount*sizeof(*colinfo) );
1074     count = table->row_count;
1075     for( i=0; i<count; i++ )
1076     {
1077         if( read_table_int(table->data, i, 0, db->bytes_per_strref) != table_id )
1078             continue;
1079         if( colinfo )
1080         {
1081             UINT id = read_table_int(table->data, i, table->colinfo[2].offset, db->bytes_per_strref);
1082             UINT col = read_table_int(table->data, i, table->colinfo[1].offset, sizeof(USHORT)) - (1<<15);
1083
1084             /* check the column number is in range */
1085             if (col<1 || col>maxcount)
1086             {
1087                 ERR("column %d out of range\n", col);
1088                 continue;
1089             }
1090
1091             /* check if this column was already set */
1092             if (colinfo[ col - 1 ].number)
1093             {
1094                 ERR("duplicate column %d\n", col);
1095                 continue;
1096             }
1097
1098             colinfo[ col - 1 ].tablename = msi_makestring( db, table_id );
1099             colinfo[ col - 1 ].number = col;
1100             colinfo[ col - 1 ].colname = msi_makestring( db, id );
1101             colinfo[ col - 1 ].type = read_table_int(table->data, i,
1102                                                      table->colinfo[3].offset,
1103                                                      sizeof(USHORT)) - (1<<15);
1104             colinfo[ col - 1 ].offset = 0;
1105             colinfo[ col - 1 ].ref_count = 0;
1106             colinfo[ col - 1 ].hash_table = NULL;
1107         }
1108         n++;
1109     }
1110
1111     TRACE("%s has %d columns\n", debugstr_w(szTableName), n);
1112
1113     if (colinfo && n != maxcount)
1114     {
1115         ERR("missing column in table %s\n", debugstr_w(szTableName));
1116         msi_free_colinfo(colinfo, maxcount );
1117         return ERROR_FUNCTION_FAILED;
1118     }
1119
1120     table_calc_column_offsets( db, colinfo, n );
1121     *sz = n;
1122
1123     return ERROR_SUCCESS;
1124 }
1125
1126 static void msi_update_table_columns( MSIDATABASE *db, LPCWSTR name )
1127 {
1128     MSITABLE *table;
1129     LPWSTR tablename;
1130     UINT size, offset, old_count;
1131     UINT n;
1132
1133     /* We may free name in msi_free_colinfo. */
1134     tablename = strdupW( name );
1135
1136     table = find_cached_table( db, tablename );
1137     old_count = table->col_count;
1138     msi_free_colinfo( table->colinfo, table->col_count );
1139     msi_free( table->colinfo );
1140     table->colinfo = NULL;
1141
1142     table_get_column_info( db, tablename, &table->colinfo, &table->col_count );
1143     if (!table->col_count)
1144         goto done;
1145
1146     size = msi_table_get_row_size( db, table->colinfo, table->col_count );
1147     offset = table->colinfo[table->col_count - 1].offset;
1148
1149     for ( n = 0; n < table->row_count; n++ )
1150     {
1151         table->data[n] = msi_realloc( table->data[n], size );
1152         if (old_count < table->col_count)
1153             memset( &table->data[n][offset], 0, size - offset );
1154     }
1155
1156 done:
1157     msi_free(tablename);
1158 }
1159
1160 /* try to find the table name in the _Tables table */
1161 BOOL TABLE_Exists( MSIDATABASE *db, LPCWSTR name )
1162 {
1163     UINT r, table_id = 0, i, count;
1164     MSITABLE *table = NULL;
1165
1166     static const WCHAR szStreams[] = {'_','S','t','r','e','a','m','s',0};
1167     static const WCHAR szStorages[] = {'_','S','t','o','r','a','g','e','s',0};
1168
1169     if( !lstrcmpW( name, szTables ) || !lstrcmpW( name, szColumns ) ||
1170         !lstrcmpW( name, szStreams ) || !lstrcmpW( name, szStorages ) )
1171         return TRUE;
1172
1173     r = msi_string2idW( db->strings, name, &table_id );
1174     if( r != ERROR_SUCCESS )
1175     {
1176         TRACE("Couldn't find id for %s\n", debugstr_w(name));
1177         return FALSE;
1178     }
1179
1180     r = get_table( db, szTables, &table );
1181     if( r != ERROR_SUCCESS )
1182     {
1183         ERR("table %s not available\n", debugstr_w(szTables));
1184         return FALSE;
1185     }
1186
1187     count = table->row_count;
1188     for( i=0; i<count; i++ )
1189         if( table->data[ i ][ 0 ] == table_id )
1190             return TRUE;
1191
1192     return FALSE;
1193 }
1194
1195 /* below is the query interface to a table */
1196
1197 typedef struct tagMSITABLEVIEW
1198 {
1199     MSIVIEW        view;
1200     MSIDATABASE   *db;
1201     MSITABLE      *table;
1202     MSICOLUMNINFO *columns;
1203     MSIORDERINFO  *order;
1204     UINT           num_cols;
1205     UINT           row_size;
1206     WCHAR          name[1];
1207 } MSITABLEVIEW;
1208
1209 static UINT TABLE_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val )
1210 {
1211     MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
1212     UINT offset, n;
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     /* how many rows are there ? */
1221     if( row >= tv->table->row_count )
1222         return ERROR_NO_MORE_ITEMS;
1223
1224     if( tv->columns[col-1].offset >= tv->row_size )
1225     {
1226         ERR("Stuffed up %d >= %d\n", tv->columns[col-1].offset, tv->row_size );
1227         ERR("%p %p\n", tv, tv->columns );
1228         return ERROR_FUNCTION_FAILED;
1229     }
1230
1231     if (tv->order)
1232         row = tv->order->reorder[row];
1233
1234     n = bytes_per_column( tv->db, &tv->columns[col-1] );
1235     if (n != 2 && n != 3 && n != 4)
1236     {
1237         ERR("oops! what is %d bytes per column?\n", n );
1238         return ERROR_FUNCTION_FAILED;
1239     }
1240
1241     offset = tv->columns[col-1].offset;
1242     *val = read_table_int(tv->table->data, row, offset, n);
1243
1244     /* TRACE("Data [%d][%d] = %d\n", row, col, *val ); */
1245
1246     return ERROR_SUCCESS;
1247 }
1248
1249 static UINT msi_stream_name( const MSITABLEVIEW *tv, UINT row, LPWSTR *pstname )
1250 {
1251     LPWSTR p, stname = NULL;
1252     UINT i, r, type, ival;
1253     DWORD len;
1254     LPCWSTR sval;
1255     MSIVIEW *view = (MSIVIEW *) tv;
1256
1257     TRACE("%p %d\n", tv, row);
1258
1259     len = lstrlenW( tv->name ) + 1;
1260     stname = msi_alloc( len*sizeof(WCHAR) );
1261     if ( !stname )
1262     {
1263        r = ERROR_OUTOFMEMORY;
1264        goto err;
1265     }
1266
1267     lstrcpyW( stname, tv->name );
1268
1269     for ( i = 0; i < tv->num_cols; i++ )
1270     {
1271         type = tv->columns[i].type;
1272         if ( type & MSITYPE_KEY )
1273         {
1274             r = TABLE_fetch_int( view, row, i+1, &ival );
1275             if ( r != ERROR_SUCCESS )
1276                 goto err;
1277
1278             if ( tv->columns[i].type & MSITYPE_STRING )
1279             {
1280                 sval = msi_string_lookup_id( tv->db->strings, ival );
1281                 if ( !sval )
1282                 {
1283                     r = ERROR_INVALID_PARAMETER;
1284                     goto err;
1285                 }
1286             }
1287             else
1288             {
1289                 static const WCHAR fmt[] = { '%','d',0 };
1290                 WCHAR number[0x20];
1291                 UINT n = bytes_per_column( tv->db, &tv->columns[i] );
1292
1293                 switch( n )
1294                 {
1295                 case 2:
1296                     sprintfW( number, fmt, ival-0x8000 );
1297                     break;
1298                 case 4:
1299                     sprintfW( number, fmt, ival^0x80000000 );
1300                     break;
1301                 default:
1302                     ERR( "oops - unknown column width %d\n", n );
1303                     r = ERROR_FUNCTION_FAILED;
1304                     goto err;
1305                 }
1306                 sval = number;
1307             }
1308
1309             len += lstrlenW( szDot ) + lstrlenW( sval );
1310             p = msi_realloc ( stname, len*sizeof(WCHAR) );
1311             if ( !p )
1312             {
1313                 r = ERROR_OUTOFMEMORY;
1314                 goto err;
1315             }
1316             stname = p;
1317
1318             lstrcatW( stname, szDot );
1319             lstrcatW( stname, sval );
1320         }
1321         else
1322            continue;
1323     }
1324
1325     *pstname = stname;
1326     return ERROR_SUCCESS;
1327
1328 err:
1329     msi_free( stname );
1330     *pstname = NULL;
1331     return r;
1332 }
1333
1334 /*
1335  * We need a special case for streams, as we need to reference column with
1336  * the name of the stream in the same table, and the table name
1337  * which may not be available at higher levels of the query
1338  */
1339 static UINT TABLE_fetch_stream( struct tagMSIVIEW *view, UINT row, UINT col, IStream **stm )
1340 {
1341     MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
1342     UINT r;
1343     LPWSTR full_name = NULL;
1344
1345     if( !view->ops->fetch_int )
1346         return ERROR_INVALID_PARAMETER;
1347
1348     r = msi_stream_name( tv, row, &full_name );
1349     if ( r != ERROR_SUCCESS )
1350     {
1351         ERR("fetching stream, error = %d\n", r);
1352         return r;
1353     }
1354
1355     r = db_get_raw_stream( tv->db, full_name, stm );
1356     if( r )
1357         ERR("fetching stream %s, error = %d\n",debugstr_w(full_name), r);
1358     msi_free( full_name );
1359
1360     return r;
1361 }
1362
1363 static UINT TABLE_set_int( MSITABLEVIEW *tv, UINT row, UINT col, UINT val )
1364 {
1365     UINT offset, n, i;
1366
1367     if( !tv->table )
1368         return ERROR_INVALID_PARAMETER;
1369
1370     if( (col==0) || (col>tv->num_cols) )
1371         return ERROR_INVALID_PARAMETER;
1372
1373     if( row >= tv->table->row_count )
1374         return ERROR_INVALID_PARAMETER;
1375
1376     if( tv->columns[col-1].offset >= tv->row_size )
1377     {
1378         ERR("Stuffed up %d >= %d\n", tv->columns[col-1].offset, tv->row_size );
1379         ERR("%p %p\n", tv, tv->columns );
1380         return ERROR_FUNCTION_FAILED;
1381     }
1382
1383     msi_free( tv->columns[col-1].hash_table );
1384     tv->columns[col-1].hash_table = NULL;
1385
1386     n = bytes_per_column( tv->db, &tv->columns[col-1] );
1387     if ( n != 2 && n != 3 && n != 4 )
1388     {
1389         ERR("oops! what is %d bytes per column?\n", n );
1390         return ERROR_FUNCTION_FAILED;
1391     }
1392
1393     offset = tv->columns[col-1].offset;
1394     for ( i = 0; i < n; i++ )
1395         tv->table->data[row][offset + i] = (val >> i * 8) & 0xff;
1396
1397     return ERROR_SUCCESS;
1398 }
1399
1400 static UINT TABLE_get_row( struct tagMSIVIEW *view, UINT row, MSIRECORD **rec )
1401 {
1402     MSITABLEVIEW *tv = (MSITABLEVIEW *)view;
1403
1404     if (!tv->table)
1405         return ERROR_INVALID_PARAMETER;
1406
1407     if (tv->order)
1408         row = tv->order->reorder[row];
1409
1410     return msi_view_get_row(tv->db, view, row, rec);
1411 }
1412
1413 static UINT msi_addstreamW( MSIDATABASE *db, LPCWSTR name, IStream *data )
1414 {
1415     UINT r;
1416     MSIQUERY *query = NULL;
1417     MSIRECORD *rec = NULL;
1418
1419     static const WCHAR insert[] = {
1420        'I','N','S','E','R','T',' ','I','N','T','O',' ',
1421           '`','_','S','t','r','e','a','m','s','`',' ',
1422          '(','`','N','a','m','e','`',',',
1423              '`','D','a','t','a','`',')',' ',
1424          'V','A','L','U','E','S',' ','(','?',',','?',')',0};
1425
1426     TRACE("%p %s %p\n", db, debugstr_w(name), data);
1427
1428     rec = MSI_CreateRecord( 2 );
1429     if ( !rec )
1430         return ERROR_OUTOFMEMORY;
1431
1432     r = MSI_RecordSetStringW( rec, 1, name );
1433     if ( r != ERROR_SUCCESS )
1434        goto err;
1435
1436     r = MSI_RecordSetIStream( rec, 2, data );
1437     if ( r != ERROR_SUCCESS )
1438        goto err;
1439
1440     r = MSI_DatabaseOpenViewW( db, insert, &query );
1441     if ( r != ERROR_SUCCESS )
1442        goto err;
1443
1444     r = MSI_ViewExecute( query, rec );
1445
1446 err:
1447     msiobj_release( &query->hdr );
1448     msiobj_release( &rec->hdr );
1449
1450     return r;
1451 }
1452
1453 static UINT get_table_value_from_record( MSITABLEVIEW *tv, MSIRECORD *rec, UINT iField, UINT *pvalue )
1454 {
1455     MSICOLUMNINFO columninfo;
1456     UINT r;
1457
1458     if ( (iField <= 0) ||
1459          (iField > tv->num_cols) ||
1460           MSI_RecordIsNull( rec, iField ) )
1461         return ERROR_FUNCTION_FAILED;
1462
1463     columninfo = tv->columns[ iField - 1 ];
1464
1465     if ( MSITYPE_IS_BINARY(columninfo.type) )
1466     {
1467         *pvalue = 1; /* refers to the first key column */
1468     }
1469     else if ( columninfo.type & MSITYPE_STRING )
1470     {
1471         LPCWSTR sval = MSI_RecordGetString( rec, iField );
1472
1473         r = msi_string2idW(tv->db->strings, sval, pvalue);
1474         if (r != ERROR_SUCCESS)
1475            return ERROR_NOT_FOUND;
1476     }
1477     else if ( 2 == bytes_per_column( tv->db, &columninfo ) )
1478     {
1479         *pvalue = 0x8000 + MSI_RecordGetInteger( rec, iField );
1480         if ( *pvalue & 0xffff0000 )
1481         {
1482             ERR("field %u value %d out of range\n", iField, *pvalue - 0x8000);
1483             return ERROR_FUNCTION_FAILED;
1484         }
1485     }
1486     else
1487     {
1488         INT ival = MSI_RecordGetInteger( rec, iField );
1489         *pvalue = ival ^ 0x80000000;
1490     }
1491
1492     return ERROR_SUCCESS;
1493 }
1494
1495 static UINT TABLE_set_row( struct tagMSIVIEW *view, UINT row, MSIRECORD *rec, UINT mask )
1496 {
1497     MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
1498     UINT i, val, r = ERROR_SUCCESS;
1499
1500     if ( !tv->table )
1501         return ERROR_INVALID_PARAMETER;
1502
1503     /* test if any of the mask bits are invalid */
1504     if ( mask >= (1<<tv->num_cols) )
1505         return ERROR_INVALID_PARAMETER;
1506
1507     for ( i = 0; i < tv->num_cols; i++ )
1508     {
1509         BOOL persistent;
1510
1511         /* only update the fields specified in the mask */
1512         if ( !(mask&(1<<i)) )
1513             continue;
1514
1515         persistent = (tv->table->persistent != MSICONDITION_FALSE) &&
1516                      (tv->table->data_persistent[row]);
1517         /* FIXME: should we allow updating keys? */
1518
1519         val = 0;
1520         if ( !MSI_RecordIsNull( rec, i + 1 ) )
1521         {
1522             r = get_table_value_from_record (tv, rec, i + 1, &val);
1523             if ( MSITYPE_IS_BINARY(tv->columns[ i ].type) )
1524             {
1525                 IStream *stm;
1526                 LPWSTR stname;
1527
1528                 if ( r != ERROR_SUCCESS )
1529                     return ERROR_FUNCTION_FAILED;
1530
1531                 r = MSI_RecordGetIStream( rec, i + 1, &stm );
1532                 if ( r != ERROR_SUCCESS )
1533                     return r;
1534
1535                 r = msi_stream_name( tv, row, &stname );
1536                 if ( r != ERROR_SUCCESS )
1537                 {
1538                     IStream_Release( stm );
1539                     return r;
1540                 }
1541
1542                 r = msi_addstreamW( tv->db, stname, stm );
1543                 IStream_Release( stm );
1544                 msi_free ( stname );
1545
1546                 if ( r != ERROR_SUCCESS )
1547                     return r;
1548             }
1549             else if ( tv->columns[i].type & MSITYPE_STRING )
1550             {
1551                 UINT x;
1552
1553                 if ( r != ERROR_SUCCESS )
1554                 {
1555                     LPCWSTR sval = MSI_RecordGetString( rec, i + 1 );
1556                     val = msi_addstringW( tv->db->strings, 0, sval, -1, 1,
1557                       persistent ? StringPersistent : StringNonPersistent );
1558
1559                 }
1560                 else
1561                 {
1562                     TABLE_fetch_int(&tv->view, row, i + 1, &x);
1563                     if (val == x)
1564                         continue;
1565                 }
1566             }
1567             else
1568             {
1569                 if ( r != ERROR_SUCCESS )
1570                     return ERROR_FUNCTION_FAILED;
1571             }
1572         }
1573
1574         r = TABLE_set_int( tv, row, i+1, val );
1575         if ( r != ERROR_SUCCESS )
1576             break;
1577     }
1578     return r;
1579 }
1580
1581 static UINT table_create_new_row( struct tagMSIVIEW *view, UINT *num, BOOL temporary )
1582 {
1583     MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
1584     BYTE **p, *row;
1585     BOOL *b;
1586     UINT sz;
1587     BYTE ***data_ptr;
1588     BOOL **data_persist_ptr;
1589     UINT *row_count;
1590
1591     TRACE("%p %s\n", view, temporary ? "TRUE" : "FALSE");
1592
1593     if( !tv->table )
1594         return ERROR_INVALID_PARAMETER;
1595
1596     row = msi_alloc_zero( tv->row_size );
1597     if( !row )
1598         return ERROR_NOT_ENOUGH_MEMORY;
1599
1600     row_count = &tv->table->row_count;
1601     data_ptr = &tv->table->data;
1602     data_persist_ptr = &tv->table->data_persistent;
1603     if (*num == -1)
1604         *num = tv->table->row_count;
1605
1606     sz = (*row_count + 1) * sizeof (BYTE*);
1607     if( *data_ptr )
1608         p = msi_realloc( *data_ptr, sz );
1609     else
1610         p = msi_alloc( sz );
1611     if( !p )
1612     {
1613         msi_free( row );
1614         return ERROR_NOT_ENOUGH_MEMORY;
1615     }
1616
1617     sz = (*row_count + 1) * sizeof (BOOL);
1618     if( *data_persist_ptr )
1619         b = msi_realloc( *data_persist_ptr, sz );
1620     else
1621         b = msi_alloc( sz );
1622     if( !b )
1623     {
1624         msi_free( row );
1625         msi_free( p );
1626         return ERROR_NOT_ENOUGH_MEMORY;
1627     }
1628
1629     *data_ptr = p;
1630     (*data_ptr)[*row_count] = row;
1631
1632     *data_persist_ptr = b;
1633     (*data_persist_ptr)[*row_count] = !temporary;
1634
1635     (*row_count)++;
1636
1637     return ERROR_SUCCESS;
1638 }
1639
1640 static UINT TABLE_execute( struct tagMSIVIEW *view, MSIRECORD *record )
1641 {
1642     MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
1643
1644     TRACE("%p %p\n", tv, record);
1645
1646     TRACE("There are %d columns\n", tv->num_cols );
1647
1648     return ERROR_SUCCESS;
1649 }
1650
1651 static UINT TABLE_close( struct tagMSIVIEW *view )
1652 {
1653     TRACE("%p\n", view );
1654     
1655     return ERROR_SUCCESS;
1656 }
1657
1658 static UINT TABLE_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols)
1659 {
1660     MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
1661
1662     TRACE("%p %p %p\n", view, rows, cols );
1663
1664     if( cols )
1665         *cols = tv->num_cols;
1666     if( rows )
1667     {
1668         if( !tv->table )
1669             return ERROR_INVALID_PARAMETER;
1670         *rows = tv->table->row_count;
1671     }
1672
1673     return ERROR_SUCCESS;
1674 }
1675
1676 static UINT TABLE_get_column_info( struct tagMSIVIEW *view,
1677                 UINT n, LPWSTR *name, UINT *type, BOOL *temporary,
1678                 LPWSTR *table_name )
1679 {
1680     MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
1681
1682     TRACE("%p %d %p %p\n", tv, n, name, type );
1683
1684     if( ( n == 0 ) || ( n > tv->num_cols ) )
1685         return ERROR_INVALID_PARAMETER;
1686
1687     if( name )
1688     {
1689         *name = strdupW( tv->columns[n-1].colname );
1690         if( !*name )
1691             return ERROR_FUNCTION_FAILED;
1692     }
1693
1694     if( table_name )
1695     {
1696         *table_name = strdupW( tv->columns[n-1].tablename );
1697         if( !*table_name )
1698             return ERROR_FUNCTION_FAILED;
1699     }
1700
1701     if( type )
1702         *type = tv->columns[n-1].type;
1703
1704     if( temporary )
1705         *temporary = tv->columns[n-1].temporary;
1706
1707     return ERROR_SUCCESS;
1708 }
1709
1710 static UINT msi_table_find_row( MSITABLEVIEW *tv, MSIRECORD *rec, UINT *row );
1711
1712 static UINT table_validate_new( MSITABLEVIEW *tv, MSIRECORD *rec )
1713 {
1714     UINT r, row, i;
1715
1716     /* check there's no null values where they're not allowed */
1717     for( i = 0; i < tv->num_cols; i++ )
1718     {
1719         if ( tv->columns[i].type & MSITYPE_NULLABLE )
1720             continue;
1721
1722         if ( MSITYPE_IS_BINARY(tv->columns[i].type) )
1723             TRACE("skipping binary column\n");
1724         else if ( tv->columns[i].type & MSITYPE_STRING )
1725         {
1726             LPCWSTR str;
1727
1728             str = MSI_RecordGetString( rec, i+1 );
1729             if (str == NULL || str[0] == 0)
1730                 return ERROR_INVALID_DATA;
1731         }
1732         else
1733         {
1734             UINT n;
1735
1736             n = MSI_RecordGetInteger( rec, i+1 );
1737             if (n == MSI_NULL_INTEGER)
1738                 return ERROR_INVALID_DATA;
1739         }
1740     }
1741
1742     /* check there's no duplicate keys */
1743     r = msi_table_find_row( tv, rec, &row );
1744     if (r == ERROR_SUCCESS)
1745         return ERROR_FUNCTION_FAILED;
1746
1747     return ERROR_SUCCESS;
1748 }
1749
1750 static UINT find_insert_index( MSITABLEVIEW *tv, MSIRECORD *rec, UINT *pidx )
1751 {
1752     UINT r, idx, j, ivalue, x;
1753
1754     TRACE("%p %p %p\n", tv, rec, pidx);
1755
1756     for (idx = 0; idx < tv->table->row_count; idx++)
1757     {
1758         for (j = 0; j < tv->num_cols; j++ )
1759         {
1760             r = get_table_value_from_record (tv, rec, j+1, &ivalue);
1761             if (r != ERROR_SUCCESS)
1762                 break;
1763
1764             r = TABLE_fetch_int(&tv->view, idx, j + 1, &x);
1765             if (r != ERROR_SUCCESS)
1766                 return r;
1767
1768             if (ivalue > x)
1769                 break;
1770             else if (ivalue == x)
1771                 continue;
1772             else {
1773                 TRACE("Found %d.\n", idx);
1774                 *pidx = idx;
1775                 return ERROR_SUCCESS;
1776             }
1777         }
1778     }
1779
1780     TRACE("Found %d.\n", idx);
1781     *pidx = idx;
1782     return ERROR_SUCCESS;
1783 }
1784
1785 static UINT TABLE_insert_row( struct tagMSIVIEW *view, MSIRECORD *rec, UINT row, BOOL temporary )
1786 {
1787     MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
1788     UINT i, r;
1789
1790     TRACE("%p %p %s\n", tv, rec, temporary ? "TRUE" : "FALSE" );
1791
1792     /* check that the key is unique - can we find a matching row? */
1793     r = table_validate_new( tv, rec );
1794     if( r != ERROR_SUCCESS )
1795         return ERROR_FUNCTION_FAILED;
1796
1797     if (row == -1)
1798     {
1799         r = find_insert_index(tv, rec, &row);
1800         if( r != ERROR_SUCCESS )
1801             return ERROR_FUNCTION_FAILED;
1802     }
1803
1804     r = table_create_new_row( view, &row, temporary );
1805     TRACE("insert_row returned %08x\n", r);
1806     if( r != ERROR_SUCCESS )
1807         return r;
1808
1809     /* shift the rows to make room for the new row */
1810     for (i = tv->table->row_count - 1; i > row; i--)
1811     {
1812         memmove(&(tv->table->data[i][0]),
1813                 &(tv->table->data[i - 1][0]), tv->row_size);
1814         tv->table->data_persistent[i] = tv->table->data_persistent[i - 1];
1815     }
1816
1817     /* Re-set the persistence flag */
1818     tv->table->data_persistent[row] = !temporary;
1819     return TABLE_set_row( view, row, rec, (1<<tv->num_cols) - 1 );
1820 }
1821
1822 static UINT TABLE_delete_row( struct tagMSIVIEW *view, UINT row )
1823 {
1824     MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
1825     UINT r, num_rows, num_cols, i;
1826
1827     TRACE("%p %d\n", tv, row);
1828
1829     if ( !tv->table )
1830         return ERROR_INVALID_PARAMETER;
1831
1832     r = TABLE_get_dimensions( view, &num_rows, &num_cols );
1833     if ( r != ERROR_SUCCESS )
1834         return r;
1835
1836     if ( row >= num_rows )
1837         return ERROR_FUNCTION_FAILED;
1838
1839     num_rows = tv->table->row_count;
1840     tv->table->row_count--;
1841
1842     /* reset the hash tables */
1843     for (i = 0; i < tv->num_cols; i++)
1844     {
1845         msi_free( tv->columns[i].hash_table );
1846         tv->columns[i].hash_table = NULL;
1847     }
1848
1849     for (i = row + 1; i < num_rows; i++)
1850     {
1851         memcpy(tv->table->data[i - 1], tv->table->data[i], tv->row_size);
1852         tv->table->data_persistent[i - 1] = tv->table->data_persistent[i];
1853     }
1854
1855     msi_free(tv->table->data[num_rows - 1]);
1856
1857     return ERROR_SUCCESS;
1858 }
1859
1860 static UINT msi_table_update(struct tagMSIVIEW *view, MSIRECORD *rec, UINT row)
1861 {
1862     MSITABLEVIEW *tv = (MSITABLEVIEW *)view;
1863     UINT r, new_row;
1864
1865     /* FIXME: MsiViewFetch should set rec index 0 to some ID that
1866      * sets the fetched record apart from other records
1867      */
1868
1869     if (!tv->table)
1870         return ERROR_INVALID_PARAMETER;
1871
1872     r = msi_table_find_row(tv, rec, &new_row);
1873     if (r != ERROR_SUCCESS)
1874     {
1875         ERR("can't find row to modify\n");
1876         return ERROR_FUNCTION_FAILED;
1877     }
1878
1879     /* the row cannot be changed */
1880     if (row != new_row + 1)
1881         return ERROR_FUNCTION_FAILED;
1882
1883     return TABLE_set_row(view, new_row, rec, (1 << tv->num_cols) - 1);
1884 }
1885
1886 static UINT msi_table_assign(struct tagMSIVIEW *view, MSIRECORD *rec)
1887 {
1888     MSITABLEVIEW *tv = (MSITABLEVIEW *)view;
1889     UINT r, row;
1890
1891     if (!tv->table)
1892         return ERROR_INVALID_PARAMETER;
1893
1894     r = msi_table_find_row(tv, rec, &row);
1895     if (r == ERROR_SUCCESS)
1896         return TABLE_set_row(view, row, rec, (1 << tv->num_cols) - 1);
1897     else
1898         return TABLE_insert_row( view, rec, -1, FALSE );
1899 }
1900
1901 static UINT modify_delete_row( struct tagMSIVIEW *view, MSIRECORD *rec )
1902 {
1903     MSITABLEVIEW *tv = (MSITABLEVIEW *)view;
1904     UINT row, r;
1905
1906     r = msi_table_find_row(tv, rec, &row);
1907     if (r != ERROR_SUCCESS)
1908         return r;
1909
1910     return TABLE_delete_row(view, row);
1911 }
1912
1913 static UINT msi_refresh_record( struct tagMSIVIEW *view, MSIRECORD *rec, UINT row )
1914 {
1915     MSIRECORD *curr;
1916     UINT r, i, count;
1917
1918     r = TABLE_get_row(view, row - 1, &curr);
1919     if (r != ERROR_SUCCESS)
1920         return r;
1921
1922     /* Close the original record */
1923     MSI_CloseRecord(&rec->hdr);
1924
1925     count = MSI_RecordGetFieldCount(rec);
1926     for (i = 0; i < count; i++)
1927         MSI_RecordCopyField(curr, i + 1, rec, i + 1);
1928
1929     msiobj_release(&curr->hdr);
1930     return ERROR_SUCCESS;
1931 }
1932
1933 static UINT TABLE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode,
1934                           MSIRECORD *rec, UINT row)
1935 {
1936     MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
1937     UINT r;
1938
1939     TRACE("%p %d %p\n", view, eModifyMode, rec );
1940
1941     switch (eModifyMode)
1942     {
1943     case MSIMODIFY_DELETE:
1944         r = modify_delete_row( view, rec );
1945         break;
1946     case MSIMODIFY_VALIDATE_NEW:
1947         r = table_validate_new( tv, rec );
1948         break;
1949
1950     case MSIMODIFY_INSERT:
1951         r = table_validate_new( tv, rec );
1952         if (r != ERROR_SUCCESS)
1953             break;
1954         r = TABLE_insert_row( view, rec, -1, FALSE );
1955         break;
1956
1957     case MSIMODIFY_INSERT_TEMPORARY:
1958         r = table_validate_new( tv, rec );
1959         if (r != ERROR_SUCCESS)
1960             break;
1961         r = TABLE_insert_row( view, rec, -1, TRUE );
1962         break;
1963
1964     case MSIMODIFY_REFRESH:
1965         r = msi_refresh_record( view, rec, row );
1966         break;
1967
1968     case MSIMODIFY_UPDATE:
1969         r = msi_table_update( view, rec, row );
1970         break;
1971
1972     case MSIMODIFY_ASSIGN:
1973         r = msi_table_assign( view, rec );
1974         break;
1975
1976     case MSIMODIFY_REPLACE:
1977     case MSIMODIFY_MERGE:
1978     case MSIMODIFY_VALIDATE:
1979     case MSIMODIFY_VALIDATE_FIELD:
1980     case MSIMODIFY_VALIDATE_DELETE:
1981         FIXME("%p %d %p - mode not implemented\n", view, eModifyMode, rec );
1982         r = ERROR_CALL_NOT_IMPLEMENTED;
1983         break;
1984
1985     default:
1986         r = ERROR_INVALID_DATA;
1987     }
1988
1989     return r;
1990 }
1991
1992 static UINT TABLE_delete( struct tagMSIVIEW *view )
1993 {
1994     MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
1995
1996     TRACE("%p\n", view );
1997
1998     tv->table = NULL;
1999     tv->columns = NULL;
2000
2001     if (tv->order)
2002     {
2003         msi_free( tv->order->reorder );
2004         msi_free( tv->order );
2005         tv->order = NULL;
2006     }
2007
2008     msi_free( tv );
2009
2010     return ERROR_SUCCESS;
2011 }
2012
2013 static UINT TABLE_find_matching_rows( struct tagMSIVIEW *view, UINT col,
2014     UINT val, UINT *row, MSIITERHANDLE *handle )
2015 {
2016     MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
2017     const MSICOLUMNHASHENTRY *entry;
2018
2019     TRACE("%p, %d, %u, %p\n", view, col, val, *handle);
2020
2021     if( !tv->table )
2022         return ERROR_INVALID_PARAMETER;
2023
2024     if( (col==0) || (col > tv->num_cols) )
2025         return ERROR_INVALID_PARAMETER;
2026
2027     if( !tv->columns[col-1].hash_table )
2028     {
2029         UINT i;
2030         UINT num_rows = tv->table->row_count;
2031         MSICOLUMNHASHENTRY **hash_table;
2032         MSICOLUMNHASHENTRY *new_entry;
2033
2034         if( tv->columns[col-1].offset >= tv->row_size )
2035         {
2036             ERR("Stuffed up %d >= %d\n", tv->columns[col-1].offset, tv->row_size );
2037             ERR("%p %p\n", tv, tv->columns );
2038             return ERROR_FUNCTION_FAILED;
2039         }
2040
2041         /* allocate contiguous memory for the table and its entries so we
2042          * don't have to do an expensive cleanup */
2043         hash_table = msi_alloc(MSITABLE_HASH_TABLE_SIZE * sizeof(MSICOLUMNHASHENTRY*) +
2044             num_rows * sizeof(MSICOLUMNHASHENTRY));
2045         if (!hash_table)
2046             return ERROR_OUTOFMEMORY;
2047
2048         memset(hash_table, 0, MSITABLE_HASH_TABLE_SIZE * sizeof(MSICOLUMNHASHENTRY*));
2049         tv->columns[col-1].hash_table = hash_table;
2050
2051         new_entry = (MSICOLUMNHASHENTRY *)(hash_table + MSITABLE_HASH_TABLE_SIZE);
2052
2053         for (i = 0; i < num_rows; i++, new_entry++)
2054         {
2055             UINT row_value;
2056
2057             if (view->ops->fetch_int( view, i, col, &row_value ) != ERROR_SUCCESS)
2058                 continue;
2059
2060             new_entry->next = NULL;
2061             new_entry->value = row_value;
2062             new_entry->row = i;
2063             if (hash_table[row_value % MSITABLE_HASH_TABLE_SIZE])
2064             {
2065                 MSICOLUMNHASHENTRY *prev_entry = hash_table[row_value % MSITABLE_HASH_TABLE_SIZE];
2066                 while (prev_entry->next)
2067                     prev_entry = prev_entry->next;
2068                 prev_entry->next = new_entry;
2069             }
2070             else
2071                 hash_table[row_value % MSITABLE_HASH_TABLE_SIZE] = new_entry;
2072         }
2073     }
2074
2075     if( !*handle )
2076         entry = tv->columns[col-1].hash_table[val % MSITABLE_HASH_TABLE_SIZE];
2077     else
2078         entry = (*handle)->next;
2079
2080     while (entry && entry->value != val)
2081         entry = entry->next;
2082
2083     *handle = entry;
2084     if (!entry)
2085         return ERROR_NO_MORE_ITEMS;
2086
2087     *row = entry->row;
2088
2089     return ERROR_SUCCESS;
2090 }
2091
2092 static UINT TABLE_add_ref(struct tagMSIVIEW *view)
2093 {
2094     MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
2095     UINT i;
2096
2097     TRACE("%p %d\n", view, tv->table->ref_count);
2098
2099     for (i = 0; i < tv->table->col_count; i++)
2100     {
2101         if (tv->table->colinfo[i].type & MSITYPE_TEMPORARY)
2102             InterlockedIncrement(&tv->table->colinfo[i].ref_count);
2103     }
2104
2105     return InterlockedIncrement(&tv->table->ref_count);
2106 }
2107
2108 static UINT TABLE_remove_column(struct tagMSIVIEW *view, LPCWSTR table, UINT number)
2109 {
2110     MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
2111     MSIRECORD *rec = NULL;
2112     MSIVIEW *columns = NULL;
2113     UINT row, r;
2114
2115     rec = MSI_CreateRecord(2);
2116     if (!rec)
2117         return ERROR_OUTOFMEMORY;
2118
2119     MSI_RecordSetStringW(rec, 1, table);
2120     MSI_RecordSetInteger(rec, 2, number);
2121
2122     r = TABLE_CreateView(tv->db, szColumns, &columns);
2123     if (r != ERROR_SUCCESS)
2124         return r;
2125
2126     r = msi_table_find_row((MSITABLEVIEW *)columns, rec, &row);
2127     if (r != ERROR_SUCCESS)
2128         goto done;
2129
2130     r = TABLE_delete_row(columns, row);
2131     if (r != ERROR_SUCCESS)
2132         goto done;
2133
2134     msi_update_table_columns(tv->db, table);
2135
2136 done:
2137     msiobj_release(&rec->hdr);
2138     columns->ops->delete(columns);
2139     return r;
2140 }
2141
2142 static UINT TABLE_release(struct tagMSIVIEW *view)
2143 {
2144     MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
2145     INT ref = tv->table->ref_count;
2146     UINT i, r;
2147
2148     TRACE("%p %d\n", view, ref);
2149
2150     for (i = 0; i < tv->table->col_count; i++)
2151     {
2152         if (tv->table->colinfo[i].type & MSITYPE_TEMPORARY)
2153         {
2154             ref = InterlockedDecrement(&tv->table->colinfo[i].ref_count);
2155             if (ref == 0)
2156             {
2157                 r = TABLE_remove_column(view, tv->table->colinfo[i].tablename,
2158                                         tv->table->colinfo[i].number);
2159                 if (r != ERROR_SUCCESS)
2160                     break;
2161             }
2162         }
2163     }
2164
2165     ref = InterlockedDecrement(&tv->table->ref_count);
2166     if (ref == 0)
2167     {
2168         if (!tv->table->row_count)
2169         {
2170             list_remove(&tv->table->entry);
2171             free_table(tv->table);
2172             TABLE_delete(view);
2173         }
2174     }
2175
2176     return ref;
2177 }
2178
2179 static UINT TABLE_add_column(struct tagMSIVIEW *view, LPCWSTR table, UINT number,
2180                              LPCWSTR column, UINT type, BOOL hold)
2181 {
2182     MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
2183     MSITABLE *msitable;
2184     MSIRECORD *rec;
2185     UINT r, i;
2186
2187     rec = MSI_CreateRecord(4);
2188     if (!rec)
2189         return ERROR_OUTOFMEMORY;
2190
2191     MSI_RecordSetStringW(rec, 1, table);
2192     MSI_RecordSetInteger(rec, 2, number);
2193     MSI_RecordSetStringW(rec, 3, column);
2194     MSI_RecordSetInteger(rec, 4, type);
2195
2196     r = TABLE_insert_row(&tv->view, rec, -1, FALSE);
2197     if (r != ERROR_SUCCESS)
2198         goto done;
2199
2200     msi_update_table_columns(tv->db, table);
2201
2202     if (!hold)
2203         goto done;
2204
2205     msitable = find_cached_table(tv->db, table);
2206     for (i = 0; i < msitable->col_count; i++)
2207     {
2208         if (!lstrcmpW(msitable->colinfo[i].colname, column))
2209         {
2210             InterlockedIncrement(&msitable->colinfo[i].ref_count);
2211             break;
2212         }
2213     }
2214
2215 done:
2216     msiobj_release(&rec->hdr);
2217     return r;
2218 }
2219
2220 static UINT order_add_column(struct tagMSIVIEW *view, MSIORDERINFO *order, LPCWSTR name)
2221 {
2222     UINT n, r, count;
2223     MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
2224
2225     r = TABLE_get_dimensions(view, NULL, &count);
2226     if (r != ERROR_SUCCESS)
2227         return r;
2228
2229     if (order->num_cols >= count)
2230         return ERROR_FUNCTION_FAILED;
2231
2232     r = VIEW_find_column(view, name, tv->name, &n);
2233     if (r != ERROR_SUCCESS)
2234         return r;
2235
2236     order->cols[order->num_cols] = n;
2237     TRACE("Ordering by column %s (%d)\n", debugstr_w(name), n);
2238
2239     order->num_cols++;
2240
2241     return ERROR_SUCCESS;
2242 }
2243
2244 static UINT order_compare(struct tagMSIVIEW *view, MSIORDERINFO *order,
2245                           UINT a, UINT b, UINT *swap)
2246 {
2247     UINT r, i, a_val = 0, b_val = 0;
2248
2249     *swap = 0;
2250     for (i = 0; i < order->num_cols; i++)
2251     {
2252         r = TABLE_fetch_int(view, a, order->cols[i], &a_val);
2253         if (r != ERROR_SUCCESS)
2254             return r;
2255
2256         r = TABLE_fetch_int(view, b, order->cols[i], &b_val);
2257         if (r != ERROR_SUCCESS)
2258             return r;
2259
2260         if (a_val != b_val)
2261         {
2262             if (a_val > b_val)
2263                 *swap = 1;
2264             break;
2265         }
2266     }
2267
2268     return ERROR_SUCCESS;
2269 }
2270
2271 static UINT order_mergesort(struct tagMSIVIEW *view, MSIORDERINFO *order,
2272                             UINT left, UINT right)
2273 {
2274     UINT r, i, j, temp;
2275     UINT swap = 0, center = (left + right) / 2;
2276     UINT *array = order->reorder;
2277
2278     if (left == right)
2279         return ERROR_SUCCESS;
2280
2281     /* sort the left half */
2282     r = order_mergesort(view, order, left, center);
2283     if (r != ERROR_SUCCESS)
2284         return r;
2285
2286     /* sort the right half */
2287     r = order_mergesort(view, order, center + 1, right);
2288     if (r != ERROR_SUCCESS)
2289         return r;
2290
2291     for (i = left, j = center + 1; (i <= center) && (j <= right); i++)
2292     {
2293         r = order_compare(view, order, array[i], array[j], &swap);
2294         if (r != ERROR_SUCCESS)
2295             return r;
2296
2297         if (swap)
2298         {
2299             temp = array[j];
2300             memmove(&array[i + 1], &array[i], (j - i) * sizeof(UINT));
2301             array[i] = temp;
2302             j++;
2303             center++;
2304         }
2305     }
2306
2307     return ERROR_SUCCESS;
2308 }
2309
2310 static UINT order_verify(struct tagMSIVIEW *view, MSIORDERINFO *order, UINT num_rows)
2311 {
2312     UINT i, swap, r;
2313
2314     for (i = 1; i < num_rows; i++)
2315     {
2316         r = order_compare(view, order, order->reorder[i - 1],
2317                           order->reorder[i], &swap);
2318         if (r != ERROR_SUCCESS)
2319             return r;
2320
2321         if (!swap)
2322             continue;
2323
2324         ERR("Bad order! %d\n", i);
2325         return ERROR_FUNCTION_FAILED;
2326     }
2327
2328     return ERROR_SUCCESS;
2329 }
2330
2331 static UINT TABLE_sort(struct tagMSIVIEW *view, column_info *columns)
2332 {
2333     MSITABLEVIEW *tv = (MSITABLEVIEW *)view;
2334     MSIORDERINFO *order;
2335     column_info *ptr;
2336     UINT r, i;
2337     UINT rows, cols;
2338
2339     TRACE("sorting table %s\n", debugstr_w(tv->name));
2340
2341     r = TABLE_get_dimensions(view, &rows, &cols);
2342     if (r != ERROR_SUCCESS)
2343         return r;
2344
2345     if (rows == 0)
2346         return ERROR_SUCCESS;
2347
2348     order = msi_alloc_zero(sizeof(MSIORDERINFO) + sizeof(UINT) * cols);
2349     if (!order)
2350         return ERROR_OUTOFMEMORY;
2351
2352     for (ptr = columns; ptr; ptr = ptr->next)
2353         order_add_column(view, order, ptr->column);
2354
2355     order->reorder = msi_alloc(rows * sizeof(UINT));
2356     if (!order->reorder)
2357         return ERROR_OUTOFMEMORY;
2358
2359     for (i = 0; i < rows; i++)
2360         order->reorder[i] = i;
2361
2362     r = order_mergesort(view, order, 0, rows - 1);
2363     if (r != ERROR_SUCCESS)
2364         return r;
2365
2366     r = order_verify(view, order, rows);
2367     if (r != ERROR_SUCCESS)
2368         return r;
2369
2370     tv->order = order;
2371
2372     return ERROR_SUCCESS;
2373 }
2374
2375 static UINT TABLE_drop(struct tagMSIVIEW *view)
2376 {
2377     MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
2378     MSIVIEW *tables = NULL;
2379     MSIRECORD *rec = NULL;
2380     UINT r, row;
2381     INT i;
2382
2383     TRACE("dropping table %s\n", debugstr_w(tv->name));
2384
2385     for (i = tv->table->col_count - 1; i >= 0; i--)
2386     {
2387         r = TABLE_remove_column(view, tv->table->colinfo[i].tablename,
2388                                 tv->table->colinfo[i].number);
2389         if (r != ERROR_SUCCESS)
2390             return r;
2391     }
2392
2393     rec = MSI_CreateRecord(1);
2394     if (!rec)
2395         return ERROR_OUTOFMEMORY;
2396
2397     MSI_RecordSetStringW(rec, 1, tv->name);
2398
2399     r = TABLE_CreateView(tv->db, szTables, &tables);
2400     if (r != ERROR_SUCCESS)
2401         return r;
2402
2403     r = msi_table_find_row((MSITABLEVIEW *)tables, rec, &row);
2404     if (r != ERROR_SUCCESS)
2405         goto done;
2406
2407     r = TABLE_delete_row(tables, row);
2408     if (r != ERROR_SUCCESS)
2409         goto done;
2410
2411     list_remove(&tv->table->entry);
2412     free_table(tv->table);
2413
2414 done:
2415     msiobj_release(&rec->hdr);
2416     tables->ops->delete(tables);
2417
2418     return r;
2419 }
2420
2421 static const MSIVIEWOPS table_ops =
2422 {
2423     TABLE_fetch_int,
2424     TABLE_fetch_stream,
2425     TABLE_get_row,
2426     TABLE_set_row,
2427     TABLE_insert_row,
2428     TABLE_delete_row,
2429     TABLE_execute,
2430     TABLE_close,
2431     TABLE_get_dimensions,
2432     TABLE_get_column_info,
2433     TABLE_modify,
2434     TABLE_delete,
2435     TABLE_find_matching_rows,
2436     TABLE_add_ref,
2437     TABLE_release,
2438     TABLE_add_column,
2439     TABLE_remove_column,
2440     TABLE_sort,
2441     TABLE_drop,
2442 };
2443
2444 UINT TABLE_CreateView( MSIDATABASE *db, LPCWSTR name, MSIVIEW **view )
2445 {
2446     MSITABLEVIEW *tv ;
2447     UINT r, sz;
2448
2449     static const WCHAR Streams[] = {'_','S','t','r','e','a','m','s',0};
2450     static const WCHAR Storages[] = {'_','S','t','o','r','a','g','e','s',0};
2451
2452     TRACE("%p %s %p\n", db, debugstr_w(name), view );
2453
2454     if ( !lstrcmpW( name, Streams ) )
2455         return STREAMS_CreateView( db, view );
2456     else if ( !lstrcmpW( name, Storages ) )
2457         return STORAGES_CreateView( db, view );
2458
2459     sz = sizeof *tv + lstrlenW(name)*sizeof name[0] ;
2460     tv = msi_alloc_zero( sz );
2461     if( !tv )
2462         return ERROR_FUNCTION_FAILED;
2463
2464     r = get_table( db, name, &tv->table );
2465     if( r != ERROR_SUCCESS )
2466     {
2467         msi_free( tv );
2468         WARN("table not found\n");
2469         return r;
2470     }
2471
2472     TRACE("table %p found with %d columns\n", tv->table, tv->table->col_count);
2473
2474     /* fill the structure */
2475     tv->view.ops = &table_ops;
2476     tv->db = db;
2477     tv->columns = tv->table->colinfo;
2478     tv->num_cols = tv->table->col_count;
2479     tv->row_size = msi_table_get_row_size( db, tv->table->colinfo, tv->table->col_count );
2480
2481     TRACE("%s one row is %d bytes\n", debugstr_w(name), tv->row_size );
2482
2483     *view = (MSIVIEW*) tv;
2484     lstrcpyW( tv->name, name );
2485
2486     return ERROR_SUCCESS;
2487 }
2488
2489 UINT MSI_CommitTables( MSIDATABASE *db )
2490 {
2491     UINT r;
2492     MSITABLE *table = NULL;
2493
2494     TRACE("%p\n",db);
2495
2496     r = msi_save_string_table( db->strings, db->storage );
2497     if( r != ERROR_SUCCESS )
2498     {
2499         WARN("failed to save string table r=%08x\n",r);
2500         return r;
2501     }
2502
2503     LIST_FOR_EACH_ENTRY( table, &db->tables, MSITABLE, entry )
2504     {
2505         r = save_table( db, table );
2506         if( r != ERROR_SUCCESS )
2507         {
2508             WARN("failed to save table %s (r=%08x)\n",
2509                   debugstr_w(table->name), r);
2510             return r;
2511         }
2512     }
2513
2514     /* force everything to reload next time */
2515     free_cached_tables( db );
2516
2517     return ERROR_SUCCESS;
2518 }
2519
2520 MSICONDITION MSI_DatabaseIsTablePersistent( MSIDATABASE *db, LPCWSTR table )
2521 {
2522     MSITABLE *t;
2523     UINT r;
2524
2525     TRACE("%p %s\n", db, debugstr_w(table));
2526
2527     if (!table)
2528         return MSICONDITION_ERROR;
2529
2530     r = get_table( db, table, &t );
2531     if (r != ERROR_SUCCESS)
2532         return MSICONDITION_NONE;
2533
2534     return t->persistent;
2535 }
2536
2537 static UINT read_raw_int(const BYTE *data, UINT col, UINT bytes)
2538 {
2539     UINT ret = 0, i;
2540
2541     for (i = 0; i < bytes; i++)
2542         ret += (data[col + i] << i * 8);
2543
2544     return ret;
2545 }
2546
2547 static UINT msi_record_encoded_stream_name( const MSITABLEVIEW *tv, MSIRECORD *rec, LPWSTR *pstname )
2548 {
2549     LPWSTR stname = NULL, sval, p;
2550     DWORD len;
2551     UINT i, r;
2552
2553     TRACE("%p %p\n", tv, rec);
2554
2555     len = lstrlenW( tv->name ) + 1;
2556     stname = msi_alloc( len*sizeof(WCHAR) );
2557     if ( !stname )
2558     {
2559        r = ERROR_OUTOFMEMORY;
2560        goto err;
2561     }
2562
2563     lstrcpyW( stname, tv->name );
2564
2565     for ( i = 0; i < tv->num_cols; i++ )
2566     {
2567         if ( tv->columns[i].type & MSITYPE_KEY )
2568         {
2569             sval = msi_dup_record_field( rec, i + 1 );
2570             if ( !sval )
2571             {
2572                 r = ERROR_OUTOFMEMORY;
2573                 goto err;
2574             }
2575
2576             len += lstrlenW( szDot ) + lstrlenW ( sval );
2577             p = msi_realloc ( stname, len*sizeof(WCHAR) );
2578             if ( !p )
2579             {
2580                 r = ERROR_OUTOFMEMORY;
2581                 goto err;
2582             }
2583             stname = p;
2584
2585             lstrcatW( stname, szDot );
2586             lstrcatW( stname, sval );
2587
2588             msi_free( sval );
2589         }
2590         else
2591             continue;
2592     }
2593
2594     *pstname = encode_streamname( FALSE, stname );
2595     msi_free( stname );
2596
2597     return ERROR_SUCCESS;
2598
2599 err:
2600     msi_free ( stname );
2601     *pstname = NULL;
2602     return r;
2603 }
2604
2605 static MSIRECORD *msi_get_transform_record( const MSITABLEVIEW *tv, const string_table *st,
2606                                             IStorage *stg,
2607                                             const BYTE *rawdata, UINT bytes_per_strref )
2608 {
2609     UINT i, val, ofs = 0;
2610     USHORT mask;
2611     MSICOLUMNINFO *columns = tv->columns;
2612     MSIRECORD *rec;
2613
2614     mask = rawdata[0] | (rawdata[1] << 8);
2615     rawdata += 2;
2616
2617     rec = MSI_CreateRecord( tv->num_cols );
2618     if( !rec )
2619         return rec;
2620
2621     TRACE("row ->\n");
2622     for( i=0; i<tv->num_cols; i++ )
2623     {
2624         if ( (mask&1) && (i>=(mask>>8)) )
2625             break;
2626         /* all keys must be present */
2627         if ( (~mask&1) && (~columns[i].type & MSITYPE_KEY) && ((1<<i) & ~mask) )
2628             continue;
2629
2630         if( MSITYPE_IS_BINARY(tv->columns[i].type) )
2631         {
2632             LPWSTR encname;
2633             IStream *stm = NULL;
2634             UINT r;
2635
2636             ofs += bytes_per_column( tv->db, &columns[i] );
2637
2638             r = msi_record_encoded_stream_name( tv, rec, &encname );
2639             if ( r != ERROR_SUCCESS )
2640                 return NULL;
2641
2642             r = IStorage_OpenStream( stg, encname, NULL,
2643                      STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm );
2644             msi_free( encname );
2645             if ( r != ERROR_SUCCESS )
2646                 return NULL;
2647
2648             MSI_RecordSetStream( rec, i+1, stm );
2649             TRACE(" field %d [%s]\n", i+1, debugstr_w(encname));
2650         }
2651         else if( columns[i].type & MSITYPE_STRING )
2652         {
2653             LPCWSTR sval;
2654
2655             val = read_raw_int(rawdata, ofs, bytes_per_strref);
2656             sval = msi_string_lookup_id( st, val );
2657             MSI_RecordSetStringW( rec, i+1, sval );
2658             TRACE(" field %d [%s]\n", i+1, debugstr_w(sval));
2659             ofs += bytes_per_strref;
2660         }
2661         else
2662         {
2663             UINT n = bytes_per_column( tv->db, &columns[i] );
2664             switch( n )
2665             {
2666             case 2:
2667                 val = read_raw_int(rawdata, ofs, n);
2668                 if (val)
2669                     MSI_RecordSetInteger( rec, i+1, val-0x8000 );
2670                 TRACE(" field %d [0x%04x]\n", i+1, val );
2671                 break;
2672             case 4:
2673                 val = read_raw_int(rawdata, ofs, n);
2674                 if (val)
2675                     MSI_RecordSetInteger( rec, i+1, val^0x80000000 );
2676                 TRACE(" field %d [0x%08x]\n", i+1, val );
2677                 break;
2678             default:
2679                 ERR("oops - unknown column width %d\n", n);
2680                 break;
2681             }
2682             ofs += n;
2683         }
2684     }
2685     return rec;
2686 }
2687
2688 static void dump_record( MSIRECORD *rec )
2689 {
2690     UINT i, n;
2691
2692     n = MSI_RecordGetFieldCount( rec );
2693     for( i=1; i<=n; i++ )
2694     {
2695         LPCWSTR sval = MSI_RecordGetString( rec, i );
2696
2697         if( MSI_RecordIsNull( rec, i ) )
2698             TRACE("row -> []\n");
2699         else if( (sval = MSI_RecordGetString( rec, i )) )
2700             TRACE("row -> [%s]\n", debugstr_w(sval));
2701         else
2702             TRACE("row -> [0x%08x]\n", MSI_RecordGetInteger( rec, i ) );
2703     }
2704 }
2705
2706 static void dump_table( const string_table *st, const USHORT *rawdata, UINT rawsize )
2707 {
2708     LPCWSTR sval;
2709     UINT i;
2710
2711     for( i=0; i<(rawsize/2); i++ )
2712     {
2713         sval = msi_string_lookup_id( st, rawdata[i] );
2714         MESSAGE(" %04x %s\n", rawdata[i], debugstr_w(sval) );
2715     }
2716 }
2717
2718 static UINT* msi_record_to_row( const MSITABLEVIEW *tv, MSIRECORD *rec )
2719 {
2720     LPCWSTR str;
2721     UINT i, r, *data;
2722
2723     data = msi_alloc( tv->num_cols *sizeof (UINT) );
2724     for( i=0; i<tv->num_cols; i++ )
2725     {
2726         data[i] = 0;
2727
2728         if ( ~tv->columns[i].type & MSITYPE_KEY )
2729             continue;
2730
2731         /* turn the transform column value into a row value */
2732         if ( ( tv->columns[i].type & MSITYPE_STRING ) &&
2733              ! MSITYPE_IS_BINARY(tv->columns[i].type) )
2734         {
2735             str = MSI_RecordGetString( rec, i+1 );
2736             r = msi_string2idW( tv->db->strings, str, &data[i] );
2737
2738             /* if there's no matching string in the string table,
2739                these keys can't match any record, so fail now. */
2740             if( ERROR_SUCCESS != r )
2741             {
2742                 msi_free( data );
2743                 return NULL;
2744             }
2745         }
2746         else
2747         {
2748             data[i] = MSI_RecordGetInteger( rec, i+1 );
2749
2750             if (data[i] == MSI_NULL_INTEGER)
2751                 data[i] = 0;
2752             else if ((tv->columns[i].type&0xff) == 2)
2753                 data[i] += 0x8000;
2754             else
2755                 data[i] += 0x80000000;
2756         }
2757     }
2758     return data;
2759 }
2760
2761 static UINT msi_row_matches( MSITABLEVIEW *tv, UINT row, const UINT *data )
2762 {
2763     UINT i, r, x, ret = ERROR_FUNCTION_FAILED;
2764
2765     for( i=0; i<tv->num_cols; i++ )
2766     {
2767         if ( ~tv->columns[i].type & MSITYPE_KEY )
2768             continue;
2769
2770         /* turn the transform column value into a row value */
2771         r = TABLE_fetch_int( &tv->view, row, i+1, &x );
2772         if ( r != ERROR_SUCCESS )
2773         {
2774             ERR("TABLE_fetch_int shouldn't fail here\n");
2775             break;
2776         }
2777
2778         /* if this key matches, move to the next column */
2779         if ( x != data[i] )
2780         {
2781             ret = ERROR_FUNCTION_FAILED;
2782             break;
2783         }
2784
2785         ret = ERROR_SUCCESS;
2786     }
2787
2788     return ret;
2789 }
2790
2791 static UINT msi_table_find_row( MSITABLEVIEW *tv, MSIRECORD *rec, UINT *row )
2792 {
2793     UINT i, r = ERROR_FUNCTION_FAILED, *data;
2794
2795     data = msi_record_to_row( tv, rec );
2796     if( !data )
2797         return r;
2798     for( i = 0; i < tv->table->row_count; i++ )
2799     {
2800         r = msi_row_matches( tv, i, data );
2801         if( r == ERROR_SUCCESS )
2802         {
2803             *row = i;
2804             break;
2805         }
2806     }
2807     msi_free( data );
2808     return r;
2809 }
2810
2811 typedef struct
2812 {
2813     struct list entry;
2814     LPWSTR name;
2815 } TRANSFORMDATA;
2816
2817 static UINT msi_table_load_transform( MSIDATABASE *db, IStorage *stg,
2818                                       string_table *st, TRANSFORMDATA *transform,
2819                                       UINT bytes_per_strref )
2820 {
2821     UINT rawsize = 0;
2822     BYTE *rawdata = NULL;
2823     MSITABLEVIEW *tv = NULL;
2824     UINT r, n, sz, i, mask;
2825     MSIRECORD *rec = NULL;
2826     UINT colcol = 0;
2827     WCHAR coltable[32];
2828     LPWSTR name;
2829
2830     if (!transform)
2831         return ERROR_SUCCESS;
2832
2833     name = transform->name;
2834
2835     coltable[0] = 0;
2836     TRACE("%p %p %p %s\n", db, stg, st, debugstr_w(name) );
2837
2838     /* read the transform data */
2839     read_stream_data( stg, name, TRUE, &rawdata, &rawsize );
2840     if ( !rawdata )
2841     {
2842         TRACE("table %s empty\n", debugstr_w(name) );
2843         return ERROR_INVALID_TABLE;
2844     }
2845
2846     /* create a table view */
2847     r = TABLE_CreateView( db, name, (MSIVIEW**) &tv );
2848     if( r != ERROR_SUCCESS )
2849         goto err;
2850
2851     r = tv->view.ops->execute( &tv->view, NULL );
2852     if( r != ERROR_SUCCESS )
2853         goto err;
2854
2855     TRACE("name = %s columns = %u row_size = %u raw size = %u\n",
2856           debugstr_w(name), tv->num_cols, tv->row_size, rawsize );
2857
2858     /* interpret the data */
2859     r = ERROR_SUCCESS;
2860     for( n=0; n < rawsize;  )
2861     {
2862         mask = rawdata[n] | (rawdata[n+1] << 8);
2863
2864         if (mask&1)
2865         {
2866             /*
2867              * if the low bit is set, columns are continuous and
2868              * the number of columns is specified in the high byte
2869              */
2870             sz = 2;
2871             for( i=0; i<tv->num_cols; i++ )
2872             {
2873                 if( (tv->columns[i].type & MSITYPE_STRING) &&
2874                     ! MSITYPE_IS_BINARY(tv->columns[i].type) )
2875                     sz += bytes_per_strref;
2876                 else
2877                     sz += bytes_per_column( tv->db, &tv->columns[i] );
2878             }
2879         }
2880         else
2881         {
2882             /*
2883              * If the low bit is not set, mask is a bitmask.
2884              * Excepting for key fields, which are always present,
2885              *  each bit indicates that a field is present in the transform record.
2886              *
2887              * mask == 0 is a special case ... only the keys will be present
2888              * and it means that this row should be deleted.
2889              */
2890             sz = 2;
2891             for( i=0; i<tv->num_cols; i++ )
2892             {
2893                 if( (tv->columns[i].type & MSITYPE_KEY) || ((1<<i)&mask))
2894                 {
2895                     if( (tv->columns[i].type & MSITYPE_STRING) &&
2896                         ! MSITYPE_IS_BINARY(tv->columns[i].type) )
2897                         sz += bytes_per_strref;
2898                     else
2899                         sz += bytes_per_column( tv->db, &tv->columns[i] );
2900                 }
2901             }
2902         }
2903
2904         /* check we didn't run of the end of the table */
2905         if ( (n+sz) > rawsize )
2906         {
2907             ERR("borked.\n");
2908             dump_table( st, (USHORT *)rawdata, rawsize );
2909             break;
2910         }
2911
2912         rec = msi_get_transform_record( tv, st, stg, &rawdata[n], bytes_per_strref );
2913         if (rec)
2914         {
2915             if ( mask & 1 )
2916             {
2917                 WCHAR table[32];
2918                 DWORD sz = 32;
2919                 UINT number = MSI_NULL_INTEGER;
2920
2921                 TRACE("inserting record\n");
2922
2923                 if (!lstrcmpW(name, szColumns))
2924                 {
2925                     MSI_RecordGetStringW( rec, 1, table, &sz );
2926                     number = MSI_RecordGetInteger( rec, 2 );
2927
2928                     /*
2929                      * Native msi seems writes nul into the Number (2nd) column of
2930                      * the _Columns table, only when the columns are from a new table
2931                      */
2932                     if ( number == MSI_NULL_INTEGER )
2933                     {
2934                         /* reset the column number on a new table */
2935                         if ( lstrcmpW(coltable, table) )
2936                         {
2937                             colcol = 0;
2938                             lstrcpyW( coltable, table );
2939                         }
2940
2941                         /* fix nul column numbers */
2942                         MSI_RecordSetInteger( rec, 2, ++colcol );
2943                     }
2944                 }
2945
2946                 r = TABLE_insert_row( &tv->view, rec, -1, FALSE );
2947                 if (r != ERROR_SUCCESS)
2948                     WARN("insert row failed\n");
2949
2950                 if ( number != MSI_NULL_INTEGER && !lstrcmpW(name, szColumns) )
2951                     msi_update_table_columns( db, table );
2952             }
2953             else
2954             {
2955                 UINT row = 0;
2956
2957                 r = msi_table_find_row( tv, rec, &row );
2958                 if (r != ERROR_SUCCESS)
2959                     WARN("no matching row to transform\n");
2960                 else if ( mask )
2961                 {
2962                     TRACE("modifying row [%d]:\n", row);
2963                     TABLE_set_row( &tv->view, row, rec, mask );
2964                 }
2965                 else
2966                 {
2967                     TRACE("deleting row [%d]:\n", row);
2968                     TABLE_delete_row( &tv->view, row );
2969                 }
2970             }
2971             if( TRACE_ON(msidb) ) dump_record( rec );
2972             msiobj_release( &rec->hdr );
2973         }
2974
2975         n += sz;
2976     }
2977
2978 err:
2979     /* no need to free the table, it's associated with the database */
2980     msi_free( rawdata );
2981     if( tv )
2982         tv->view.ops->delete( &tv->view );
2983
2984     return ERROR_SUCCESS;
2985 }
2986
2987 /*
2988  * msi_table_apply_transform
2989  *
2990  * Enumerate the table transforms in a transform storage and apply each one.
2991  */
2992 UINT msi_table_apply_transform( MSIDATABASE *db, IStorage *stg )
2993 {
2994     struct list transforms;
2995     IEnumSTATSTG *stgenum = NULL;
2996     TRANSFORMDATA *transform;
2997     TRANSFORMDATA *tables = NULL, *columns = NULL;
2998     HRESULT r;
2999     STATSTG stat;
3000     string_table *strings;
3001     UINT ret = ERROR_FUNCTION_FAILED;
3002     UINT bytes_per_strref;
3003
3004     TRACE("%p %p\n", db, stg );
3005
3006     strings = msi_load_string_table( stg, &bytes_per_strref );
3007     if( !strings )
3008         goto end;
3009
3010     r = IStorage_EnumElements( stg, 0, NULL, 0, &stgenum );
3011     if( FAILED( r ) )
3012         goto end;
3013
3014     list_init(&transforms);
3015
3016     while ( TRUE )
3017     {
3018         MSITABLEVIEW *tv = NULL;
3019         WCHAR name[0x40];
3020         ULONG count = 0;
3021
3022         r = IEnumSTATSTG_Next( stgenum, 1, &stat, &count );
3023         if ( FAILED( r ) || !count )
3024             break;
3025
3026         decode_streamname( stat.pwcsName, name );
3027         CoTaskMemFree( stat.pwcsName );
3028         if ( name[0] != 0x4840 )
3029             continue;
3030
3031         if ( !lstrcmpW( name+1, szStringPool ) ||
3032              !lstrcmpW( name+1, szStringData ) )
3033             continue;
3034
3035         transform = msi_alloc_zero( sizeof(TRANSFORMDATA) );
3036         if ( !transform )
3037             break;
3038
3039         list_add_tail( &transforms, &transform->entry );
3040
3041         transform->name = strdupW( name + 1 );
3042
3043         if ( !lstrcmpW( transform->name, szTables ) )
3044             tables = transform;
3045         else if (!lstrcmpW( transform->name, szColumns ) )
3046             columns = transform;
3047
3048         TRACE("transform contains stream %s\n", debugstr_w(name));
3049
3050         /* load the table */
3051         r = TABLE_CreateView( db, transform->name, (MSIVIEW**) &tv );
3052         if( r != ERROR_SUCCESS )
3053             continue;
3054
3055         r = tv->view.ops->execute( &tv->view, NULL );
3056         if( r != ERROR_SUCCESS )
3057         {
3058             tv->view.ops->delete( &tv->view );
3059             continue;
3060         }
3061
3062         tv->view.ops->delete( &tv->view );
3063     }
3064
3065     /*
3066      * Apply _Tables and _Columns transforms first so that
3067      * the table metadata is correct, and empty tables exist.
3068      */
3069     ret = msi_table_load_transform( db, stg, strings, tables, bytes_per_strref );
3070     if (ret != ERROR_SUCCESS && ret != ERROR_INVALID_TABLE)
3071         goto end;
3072
3073     ret = msi_table_load_transform( db, stg, strings, columns, bytes_per_strref );
3074     if (ret != ERROR_SUCCESS && ret != ERROR_INVALID_TABLE)
3075         goto end;
3076
3077     ret = ERROR_SUCCESS;
3078
3079     while ( !list_empty( &transforms ) )
3080     {
3081         transform = LIST_ENTRY( list_head( &transforms ), TRANSFORMDATA, entry );
3082
3083         if ( lstrcmpW( transform->name, szColumns ) &&
3084              lstrcmpW( transform->name, szTables ) &&
3085              ret == ERROR_SUCCESS )
3086         {
3087             ret = msi_table_load_transform( db, stg, strings, transform, bytes_per_strref );
3088         }
3089
3090         list_remove( &transform->entry );
3091         msi_free( transform->name );
3092         msi_free( transform );
3093     }
3094
3095     if ( ret == ERROR_SUCCESS )
3096         append_storage_to_db( db, stg );
3097
3098 end:
3099     if ( stgenum )
3100         IEnumSTATSTG_Release( stgenum );
3101     if ( strings )
3102         msi_destroy_stringtable( strings );
3103
3104     return ret;
3105 }
3106
3107 void append_storage_to_db( MSIDATABASE *db, IStorage *stg )
3108 {
3109     MSITRANSFORM *t;
3110
3111     t = msi_alloc( sizeof *t );
3112     t->stg = stg;
3113     IStorage_AddRef( stg );
3114     list_add_tail( &db->transforms, &t->entry );
3115 }
3116
3117 void msi_free_transforms( MSIDATABASE *db )
3118 {
3119     while( !list_empty( &db->transforms ) )
3120     {
3121         MSITRANSFORM *t = LIST_ENTRY( list_head( &db->transforms ),
3122                                       MSITRANSFORM, entry );
3123         list_remove( &t->entry );
3124         IStorage_Release( t->stg );
3125         msi_free( t );
3126     }
3127 }
3128
3129 void msi_free_streams( MSIDATABASE *db )
3130 {
3131     while( !list_empty( &db->streams ) )
3132     {
3133         MSISTREAM *s = LIST_ENTRY( list_head( &db->streams ),
3134                                    MSISTREAM, entry );
3135         list_remove( &s->entry );
3136         IStream_Release( s->stm );
3137         msi_free( s );
3138     }
3139 }