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