ReactOS 0.4.16-dev-942-g91fadeb
table.c
Go to the documentation of this file.
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
40
41#define MSITABLE_HASH_TABLE_SIZE 37
42
44{
48};
49
51{
58};
59
61{
65 struct list entry;
71};
72
73/* information for default tables */
74static 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
82static 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
89static 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
106static 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
122{
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
167static 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
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
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
235 BYTE **pdata, UINT *psz )
236{
237 HRESULT r;
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,
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 );
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;
291
292end:
293 IStream_Release( stm );
294
295 return ret;
296}
297
299 LPCVOID data, UINT sz, BOOL bTable )
300{
301 HRESULT r;
303 ULONG count;
304 IStream *stm = NULL;
307 LPWSTR encname;
308
309 encname = encode_streamname(bTable, stname );
310 r = IStorage_OpenStream( stg, encname, NULL,
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
351
352end:
353 IStream_Release( stm );
354
355 return ret;
356}
357
358static 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
364static 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
376static 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 */
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;
467err:
468 free( rawdata );
470}
471
473{
474 while( !list_empty( &db->tables ) )
475 {
477
478 list_remove( &t->entry );
479 free_table( t );
480 }
481}
482
484{
485 MSITABLE *t;
486
488 if( !wcscmp( name, t->name ) )
489 return t;
490
491 return NULL;
492}
493
494static 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
511static 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 {
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
540static UINT get_tablecolumns( MSIDATABASE *, const WCHAR *, struct column_info *, UINT * );
541
542static 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)
558
559 TRACE("table %s found\n", debugstr_w(name));
560
561 columns = malloc( column_count * sizeof(*columns) );
562 if (!columns)
564
565 r = get_tablecolumns( db, name, columns, &column_count );
566 if (r != ERROR_SUCCESS)
567 {
568 free( columns );
570 }
571 *pcols = columns;
572 return r;
573}
574
575static UINT get_table( MSIDATABASE *db, LPCWSTR name, MSITABLE **table_ret )
576{
578 UINT r;
579
580 /* first, see if the table is cached */
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)
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 }
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
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
631static 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;
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");
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 );
701 }
702 table_calc_column_offsets( db, colinfo, n );
703 *sz = n;
704 return ERROR_SUCCESS;
705}
706
708 MSICONDITION persistent, BOOL hold )
709{
710 UINT r, nField;
711 MSIVIEW *tv = NULL;
712 MSIRECORD *rec = NULL;
713 column_info *col;
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));
722 }
723
724 table = malloc( sizeof(MSITABLE) + wcslen(name) * sizeof(WCHAR) );
725 if( !table )
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 );
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 )
843 }
844
845err:
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
860static 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;
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 {
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
930err:
931 free( rawdata );
932 return r;
933}
934
935static void update_table_columns( MSIDATABASE *db, const WCHAR *name )
936{
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 */
963{
964 UINT r, table_id, i;
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
997{
1005};
1006
1008{
1009 struct table_view *tv = (struct table_view *)view;
1010 UINT offset, n;
1011
1012 if( !tv->table )
1014
1015 if( (col==0) || (col>tv->num_cols) )
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
1044static 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 {
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 {
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 );
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 {
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
1123err:
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 */
1135{
1136 struct table_view *tv = (struct table_view *)view;
1137 UINT r;
1138 WCHAR *name;
1139
1140 if( !view->ops->fetch_int )
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. */
1159static 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 )
1165
1166 if( (col==0) || (col>tv->num_cols) )
1168
1169 if( row >= tv->table->row_count )
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
1196static 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
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
1243static 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
1281{
1282 struct table_view *tv = (struct table_view *)view;
1283
1284 if (!tv->table)
1286
1287 return msi_view_get_row(tv->db, view, row, rec);
1288}
1289
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
1337done:
1338 msiobj_release( &rec->hdr );
1339 return r;
1340}
1341
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
1358static 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
1391{
1392 struct table_view *tv = (struct table_view *)view;
1393 UINT i, val, r = ERROR_SUCCESS;
1394
1395 if ( !tv->table )
1397
1398 /* test if any of the mask bits are invalid */
1399 if ( mask >= (1<<tv->num_cols) )
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
1475static 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 )
1489
1490 row = calloc( 1, tv->row_size );
1491 if( !row )
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 );
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 );
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
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
1546{
1547 TRACE("%p\n", view );
1548
1549 return ERROR_SUCCESS;
1550}
1551
1552static 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 )
1564 *rows = tv->table->row_count;
1565 }
1566
1567 return ERROR_SUCCESS;
1568}
1569
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 ) )
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
1604static UINT table_find_row( struct table_view *, MSIRECORD *, UINT *, UINT * );
1605
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
1650static 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
1683static 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
1708static 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
1742{
1743 struct table_view *tv = (struct table_view *)view;
1745
1746 TRACE("%p %d\n", tv, row);
1747
1748 if ( !tv->table )
1750
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
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)
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
1806{
1807 struct table_view *tv = (struct table_view *)view;
1808 UINT r, row;
1809
1810 if (!tv->table)
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
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
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
1840static 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;
1854 r = table_validate_new( tv, rec, &column );
1855 if (r != ERROR_SUCCESS)
1856 {
1858 tv->view.error_column = tv->columns[column].colname;
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
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:
1904 FIXME("%p %d %p - mode not implemented\n", view, eModifyMode, rec );
1906 break;
1907
1908 default:
1910 }
1911
1912 return r;
1913}
1914
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
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
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)
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);
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
1977 if (r != ERROR_SUCCESS)
1978 goto done;
1979
1980 update_table_columns(tv->db, tv->name);
1981
1982done:
1983 msiobj_release(&rec->hdr);
1984 columns->ops->delete(columns);
1985 return r;
1986}
1987
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
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);
2019 }
2020 }
2021
2022 return ref;
2023}
2024
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)
2039
2040 for (i = 0; i < tv->table->col_count; i++)
2041 {
2042 if (!wcscmp(tv->table->colinfo[i].colname, column))
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
2065
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);
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)
2117 return ERROR_SUCCESS;
2118}
2119
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
2155 if (r != ERROR_SUCCESS)
2156 goto done;
2157
2158 list_remove(&tv->table->entry);
2159 free_table(tv->table);
2160
2161done:
2162 msiobj_release(&rec->hdr);
2163 tables->ops->delete(tables);
2164
2165 return r;
2166}
2167
2168static const MSIVIEWOPS table_ops =
2169{
2187 NULL,
2188 TABLE_drop,
2189};
2190
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;
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
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
2265static 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
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
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
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" );
2339 }
2340
2341 if (!wcscmp( tv->name, L"_Tables" ))
2342 {
2343 ERR( "trying to modify existing table\n" );
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
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)
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
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
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
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)
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
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");
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
2717{
2718 return ERROR_SUCCESS;
2719}
2720
2722{
2723 return ERROR_SUCCESS;
2724}
2725
2727{
2728 return TABLE_get_dimensions( view, rows, cols );
2729}
2730
2732 BOOL *temporary, LPCWSTR *table_name )
2733{
2734 return TABLE_get_column_info( view, n, name, type, temporary, table_name );
2735}
2736
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
2746{
2749 NULL,
2750 NULL,
2751 NULL,
2759 NULL,
2761 NULL,
2762 NULL,
2763 NULL,
2764 NULL,
2765 NULL
2766};
2767
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 );
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
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
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
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 );
2917 }
2918 return r;
2919}
2920
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
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
2948static 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
2977static 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
3065static 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
3076static 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
3120static UINT row_matches( struct table_view *tv, UINT row, const UINT *data, UINT *column )
3121{
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 {
3141 break;
3142 }
3143 if (column) *column = i;
3145 }
3146 return ret;
3147}
3148
3150{
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
3170{
3171 struct list entry;
3173};
3174
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;
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
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" ))
3347
3348 msiobj_release( &rec->hdr );
3349 }
3350
3351 n += sz;
3352 }
3353
3354err:
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 */
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;
3378 UINT bytes_per_strref;
3379 BOOL property_update = FALSE;
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" ) )
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
3454 if (r != ERROR_SUCCESS)
3455 goto end;
3456
3458 if (r == ERROR_SUCCESS)
3460 msiobj_release( &query->hdr );
3462 goto end;
3463
3464 if (TABLE_CreateView(db, L"_TransformView", &transform_view) != ERROR_SUCCESS)
3465 goto end;
3466
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 );
3482 goto end;
3483
3484 ret = table_load_transform( db, stg, strings, columns, bytes_per_strref, err_cond );
3486 goto end;
3487
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
3512end:
3513 if ( stgenum )
3514 IEnumSTATSTG_Release( stgenum );
3515 if ( 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}
#define stat
Definition: acwin.h:99
static unsigned char bytes[4]
Definition: adnsresfilter.c:74
#define InterlockedIncrement
Definition: armddk.h:53
#define InterlockedDecrement
Definition: armddk.h:52
#define WINE_DEFAULT_DEBUG_CHANNEL(t)
Definition: precomp.h:23
#define ARRAY_SIZE(A)
Definition: main.h:20
static void list_remove(struct list_entry *entry)
Definition: list.h:90
static int list_empty(struct list_entry *head)
Definition: list.h:58
static void list_add_tail(struct list_entry *head, struct list_entry *entry)
Definition: list.h:83
static void list_add_head(struct list_entry *head, struct list_entry *entry)
Definition: list.h:76
static void list_init(struct list_entry *head)
Definition: list.h:51
#define FIXME(fmt,...)
Definition: precomp.h:53
#define WARN(fmt,...)
Definition: precomp.h:61
#define ERR(fmt,...)
Definition: precomp.h:57
r l[0]
Definition: byte_order.h:168
Definition: list.h:37
#define ERROR_NOT_ENOUGH_MEMORY
Definition: dderror.h:7
#define realloc
Definition: debug_ros.c:6
#define free
Definition: debug_ros.c:5
#define malloc
Definition: debug_ros.c:4
#define ERROR_OUTOFMEMORY
Definition: deptool.c:13
#define ERROR_SUCCESS
Definition: deptool.c:10
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
static void transform_view(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id)
Definition: state.c:3964
unsigned int idx
Definition: utils.c:41
#define ERROR_CALL_NOT_IMPLEMENTED
Definition: compat.h:102
#define ERROR_INVALID_PARAMETER
Definition: compat.h:101
#define ERROR_NO_MORE_ITEMS
Definition: compat.h:105
#define TRACE_ON(x)
Definition: compat.h:75
#define lstrcpyW
Definition: compat.h:749
#define lstrlenW
Definition: compat.h:750
void append_storage_to_db(MSIDATABASE *db, IStorage *stg)
Definition: database.c:76
int msiobj_release(MSIOBJECTHDR *info)
Definition: handle.c:241
static UINT TABLE_get_row(struct tagMSIVIEW *view, UINT row, MSIRECORD **rec)
Definition: table.c:1280
static void dump_table(const string_table *st, const USHORT *rawdata, UINT rawsize)
Definition: table.c:3065
static UINT save_table(MSIDATABASE *db, const MSITABLE *t, UINT bytes_per_strref)
Definition: table.c:860
static int find_insert_index(struct table_view *tv, MSIRECORD *rec)
Definition: table.c:1683
static const MSIVIEWOPS table_ops
Definition: table.c:2168
static UINT TABLE_modify(struct tagMSIVIEW *view, MSIMODIFY eModifyMode, MSIRECORD *rec, UINT row)
Definition: table.c:1840
static UINT TABLE_insert_row(struct tagMSIVIEW *view, MSIRECORD *rec, UINT row, BOOL temporary)
Definition: table.c:1708
static UINT TABLE_delete_row(struct tagMSIVIEW *view, UINT row)
Definition: table.c:1741
UINT msi_create_table(MSIDATABASE *db, LPCWSTR name, column_info *col_info, MSICONDITION persistent, BOOL hold)
Definition: table.c:707
static int utf2mime(int x)
Definition: table.c:106
static UINT TransformView_get_column_info(MSIVIEW *view, UINT n, LPCWSTR *name, UINT *type, BOOL *temporary, LPCWSTR *table_name)
Definition: table.c:2731
static UINT TransformView_insert_row(MSIVIEW *view, MSIRECORD *rec, UINT row, BOOL temporary)
Definition: table.c:2557
static UINT TABLE_delete(struct tagMSIVIEW *view)
Definition: table.c:1915
static UINT table_update(struct tagMSIVIEW *view, MSIRECORD *rec, UINT row)
Definition: table.c:1779
static UINT TransformView_delete(MSIVIEW *view)
Definition: table.c:2737
static UINT TABLE_add_column(struct tagMSIVIEW *view, LPCWSTR column, INT type, BOOL hold)
Definition: table.c:2025
static UINT get_stream_name(const struct table_view *tv, UINT row, WCHAR **pstname)
Definition: table.c:1044
static UINT TransformView_add_column(struct table_view *tv, MSIRECORD *rec)
Definition: table.c:2503
static UINT TABLE_set_row(struct tagMSIVIEW *view, UINT row, MSIRECORD *rec, UINT mask)
Definition: table.c:1390
static UINT table_load_transform(MSIDATABASE *db, IStorage *stg, string_table *st, struct transform_data *transform, UINT bytes_per_strref, int err_cond)
Definition: table.c:3175
static UINT record_encoded_stream_name(const struct table_view *tv, MSIRECORD *rec, WCHAR **pstname)
Definition: table.c:2948
static UINT TABLE_get_dimensions(struct tagMSIVIEW *view, UINT *rows, UINT *cols)
Definition: table.c:1552
BOOL TABLE_Exists(MSIDATABASE *db, LPCWSTR name)
Definition: table.c:962
static void free_table(MSITABLE *table)
Definition: table.c:364
static UINT TABLE_drop(struct tagMSIVIEW *view)
Definition: table.c:2120
static UINT TABLE_close(struct tagMSIVIEW *view)
Definition: table.c:1545
static UINT TABLE_fetch_stream(struct tagMSIVIEW *view, UINT row, UINT col, IStream **stm)
Definition: table.c:1134
static MSITABLE * find_cached_table(MSIDATABASE *db, LPCWSTR name)
Definition: table.c:483
static const MSIVIEWOPS transform_view_ops
Definition: table.c:2745
static UINT refresh_record(struct tagMSIVIEW *view, MSIRECORD *rec, UINT row)
Definition: table.c:1820
static UINT TABLE_set_int(MSIVIEW *view, UINT row, UINT col, int val)
Definition: table.c:1216
static UINT TransformView_fetch_stream(MSIVIEW *view, UINT row, UINT col, IStream **stm)
Definition: table.c:2310
static UINT TransformView_get_dimensions(MSIVIEW *view, UINT *rows, UINT *cols)
Definition: table.c:2726
static UINT TABLE_add_ref(struct tagMSIVIEW *view)
Definition: table.c:1929
static UINT int_to_table_storage(const struct table_view *tv, UINT col, int val, UINT *ret)
Definition: table.c:1196
static UINT TABLE_release(struct tagMSIVIEW *view)
Definition: table.c:1988
static UINT table_find_row(struct table_view *, MSIRECORD *, UINT *, UINT *)
Definition: table.c:3149
static UINT table_validate_new(struct table_view *tv, MSIRECORD *rec, UINT *column)
Definition: table.c:1606
static UINT bytes_per_column(MSIDATABASE *db, const struct column_info *col, UINT bytes_per_strref)
Definition: table.c:89
static int mime2utf(int x)
Definition: table.c:167
LPWSTR encode_streamname(BOOL bTable, LPCWSTR in)
Definition: table.c:121
static UINT TransformView_fetch_int(MSIVIEW *view, UINT row, UINT col, UINT *val)
Definition: table.c:2298
static UINT TABLE_remove_column(struct tagMSIVIEW *view, UINT number)
Definition: table.c:1937
static UINT * record_to_row(const struct table_view *tv, MSIRECORD *rec)
Definition: table.c:3076
static WCHAR * create_key_string(struct table_view *tv, MSIRECORD *rec)
Definition: table.c:2233
UINT msi_table_apply_transform(MSIDATABASE *db, IStorage *stg, int err_cond)
Definition: table.c:3368
static UINT get_table(MSIDATABASE *db, LPCWSTR name, MSITABLE **table_ret)
Definition: table.c:575
static UINT TABLE_execute(struct tagMSIVIEW *view, MSIRECORD *record)
Definition: table.c:1534
static UINT read_table_int(BYTE *const *data, UINT row, UINT col, UINT bytes)
Definition: table.c:621
BOOL decode_streamname(LPCWSTR in, LPWSTR out)
Definition: table.c:180
static UINT table_assign(struct tagMSIVIEW *view, MSIRECORD *rec)
Definition: table.c:1805
static int compare_record(struct table_view *tv, UINT row, MSIRECORD *rec)
Definition: table.c:1650
static UINT get_tablecolumns(MSIDATABASE *, const WCHAR *, struct column_info *, UINT *)
Definition: table.c:631
static UINT get_defaulttablecolumns(MSIDATABASE *db, const WCHAR *name, struct column_info *colinfo, UINT *sz)
Definition: table.c:511
static UINT row_matches(struct table_view *tv, UINT row, const UINT *data, UINT *column)
Definition: table.c:3120
static UINT TransformView_execute(MSIVIEW *view, MSIRECORD *record)
Definition: table.c:2716
static UINT table_get_column_info(MSIDATABASE *db, const WCHAR *name, struct column_info **pcols, UINT *pcount)
Definition: table.c:542
static UINT TABLE_set_stream(MSIVIEW *view, UINT row, UINT col, IStream *stream)
Definition: table.c:1342
static UINT TABLE_set_string(MSIVIEW *view, UINT row, UINT col, const WCHAR *val, int len)
Definition: table.c:1243
static const struct column_info _Tables_cols[1]
Definition: table.c:82
static MSIRECORD * get_transform_record(const struct table_view *tv, const string_table *st, IStorage *stg, const BYTE *rawdata, UINT bytes_per_strref)
Definition: table.c:2977
void enum_stream_names(IStorage *stg)
Definition: table.c:206
MSICONDITION MSI_DatabaseIsTablePersistent(MSIDATABASE *db, LPCWSTR table)
Definition: table.c:2921
static UINT TransformView_delete_row(MSIVIEW *view, UINT row)
Definition: table.c:2650
static UINT read_table_from_storage(MSIDATABASE *db, MSITABLE *t, IStorage *stg)
Definition: table.c:394
static const struct column_info _Columns_cols[4]
Definition: table.c:74
static UINT record_stream_name(const struct table_view *tv, MSIRECORD *rec, WCHAR *name, DWORD *len)
Definition: table.c:2265
static UINT TransformView_Create(MSIDATABASE *db, string_table *st, LPCWSTR name, MSIVIEW **view)
Definition: table.c:2768
static UINT TransformView_close(MSIVIEW *view)
Definition: table.c:2721
static UINT TABLE_fetch_int(struct tagMSIVIEW *view, UINT row, UINT col, UINT *val)
Definition: table.c:1007
static void free_colinfo(struct column_info *colinfo, UINT count)
Definition: table.c:358
static UINT table_set_bytes(struct table_view *tv, UINT row, UINT col, UINT val)
Definition: table.c:1159
static UINT table_create_new_row(struct tagMSIVIEW *view, UINT *num, BOOL temporary)
Definition: table.c:1475
UINT read_stream_data(IStorage *stg, LPCWSTR stname, BOOL table, BYTE **pdata, UINT *psz)
Definition: table.c:234
void free_cached_tables(MSIDATABASE *db)
Definition: table.c:472
static UINT TransformView_create_table(struct table_view *tv, MSIRECORD *rec)
Definition: table.c:2468
static UINT add_stream(MSIDATABASE *db, const WCHAR *name, IStream *data)
Definition: table.c:1290
static UINT TransformView_set_row(MSIVIEW *view, UINT row, MSIRECORD *rec, UINT mask)
Definition: table.c:2322
UINT TABLE_CreateView(MSIDATABASE *db, LPCWSTR name, MSIVIEW **view)
Definition: table.c:2191
static UINT table_get_row_size(MSIDATABASE *db, const struct column_info *cols, UINT count, UINT bytes_per_strref)
Definition: table.c:376
static UINT read_raw_int(const BYTE *data, UINT col, UINT bytes)
Definition: table.c:2938
static void update_table_columns(MSIDATABASE *db, const WCHAR *name)
Definition: table.c:935
static UINT TABLE_get_column_info(struct tagMSIVIEW *view, UINT n, LPCWSTR *name, UINT *type, BOOL *temporary, LPCWSTR *table_name)
Definition: table.c:1570
UINT MSI_CommitTables(MSIDATABASE *db)
Definition: table.c:2886
static UINT get_table_value_from_record(struct table_view *tv, MSIRECORD *rec, UINT iField, UINT *pvalue)
Definition: table.c:1358
static void table_calc_column_offsets(MSIDATABASE *db, struct column_info *colinfo, DWORD count)
Definition: table.c:494
static UINT TransformView_drop_table(struct table_view *tv, UINT row)
Definition: table.c:2606
UINT write_stream_data(IStorage *stg, LPCWSTR stname, LPCVOID data, UINT sz, BOOL bTable)
Definition: table.c:298
#define MAX_STREAM_NAME
Definition: table.c:87
struct png_info_def *typedef unsigned char **typedef struct png_info_def *typedef struct png_info_def *typedef struct png_info_def *typedef unsigned char ** row
Definition: typeof.h:78
#define swprintf
Definition: precomp.h:40
#define assert(x)
Definition: debug.h:53
struct nls_table * tables
Definition: nls_base.c:22
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
GLint GLint GLint GLint GLint x
Definition: gl.h:1548
GLuint GLuint GLsizei count
Definition: gl.h:1545
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
GLuint GLuint end
Definition: gl.h:1545
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
GLdouble GLdouble GLdouble r
Definition: gl.h:2055
GLdouble GLdouble t
Definition: gl.h:2047
GLdouble GLdouble GLdouble GLdouble q
Definition: gl.h:2063
GLdouble n
Definition: glext.h:7729
GLuint GLenum GLenum transform
Definition: glext.h:9407
GLsizei const GLchar *const * strings
Definition: glext.h:7622
GLsizeiptr size
Definition: glext.h:5919
GLintptr offset
Definition: glext.h:5920
const GLubyte * c
Definition: glext.h:8905
GLenum GLint GLuint mask
Definition: glext.h:6028
GLboolean GLboolean GLboolean b
Definition: glext.h:6204
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
GLuint in
Definition: glext.h:9616
GLuint GLfloat * val
Definition: glext.h:7180
GLfloat GLfloat p
Definition: glext.h:8902
GLuint GLuint num
Definition: glext.h:9618
GLenum GLsizei len
Definition: glext.h:6722
GLuint id
Definition: glext.h:5910
const GLfloat * m
Definition: glext.h:10848
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint GLint GLint j
Definition: glfuncs.h:250
VOID WINAPI CoTaskMemFree(LPVOID ptr)
Definition: ifs.c:442
_Check_return_ _CRTIMP int __cdecl _wtoi(_In_z_ const wchar_t *_Str)
_CRTIMP size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
#define FAILED(hr)
Definition: intsafe.h:51
uint32_t entry
Definition: isohybrid.c:63
int JSAMPARRAY int int num_rows
Definition: jpegint.h:421
int JSAMPARRAY int int JDIMENSION num_cols
Definition: jpegint.h:421
#define c
Definition: ke_i.h:80
#define b
Definition: ke_i.h:79
#define debugstr_wn
Definition: kernel32.h:33
#define debugstr_w
Definition: kernel32.h:32
#define wine_dbgstr_w
Definition: kernel32.h:34
if(dx< 0)
Definition: linetemp.h:194
LPWSTR WINAPI lstrcatW(LPWSTR lpString1, LPCWSTR lpString2)
Definition: lstring.c:274
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
#define memmove(s1, s2, n)
Definition: mkisofs.h:881
#define MESSAGE
Definition: options.h:86
int _snwprintf(wchar_t *buffer, size_t count, const wchar_t *format,...)
static unsigned int number
Definition: dsound.c:1479
static PROTOCOLDATA * pdata
Definition: protocol.c:158
int k
Definition: mpi.c:3369
int MSI_RecordGetInteger(MSIRECORD *, UINT)
Definition: record.c:213
UINT MSI_ViewExecute(MSIQUERY *, MSIRECORD *)
Definition: msiquery.c:502
void MSI_CloseRecord(MSIOBJECTHDR *)
Definition: record.c:67
UINT MSI_RecordGetIStream(MSIRECORD *, UINT, IStream **)
Definition: record.c:852
void dump_record(MSIRECORD *)
Definition: record.c:1028
UINT msi_record_set_string(MSIRECORD *, UINT, const WCHAR *, int)
Definition: record.c:573
BOOL msi_add_string(string_table *st, const WCHAR *data, int len, BOOL persistent)
Definition: string.c:303
UINT msi_clone_properties(MSIDATABASE *)
Definition: package.c:381
const WCHAR * msi_record_get_string(const MSIRECORD *, UINT, int *)
Definition: record.c:420
#define MSITYPE_VALID
Definition: msipriv.h:48
UINT MSI_RecordSetInteger(MSIRECORD *, UINT, int)
Definition: record.c:280
UINT MSI_RecordSetIStream(MSIRECORD *, UINT, IStream *)
Definition: record.c:836
UINT msi_string2id(const string_table *st, const WCHAR *data, int len, UINT *id)
Definition: string.c:400
#define MSITYPE_IS_BINARY(type)
Definition: msipriv.h:62
#define MSITYPE_TEMPORARY
Definition: msipriv.h:53
#define MSITYPE_STRING
Definition: msipriv.h:50
UINT MSI_ViewClose(MSIQUERY *)
Definition: msiquery.c:454
UINT MSI_DatabaseOpenViewW(MSIDATABASE *, LPCWSTR, MSIQUERY **)
string_table * msi_load_string_table(IStorage *stg, UINT *bytes_per_strref)
Definition: string.c:478
UINT msi_view_get_row(MSIDATABASE *, MSIVIEW *, UINT, MSIRECORD **)
Definition: msiquery.c:353
#define MSITYPE_NULLABLE
Definition: msipriv.h:51
const WCHAR * msi_string_lookup(const string_table *st, UINT id, int *len)
Definition: string.c:343
#define LONG_STR_BYTES
Definition: msipriv.h:57
VOID msi_destroy_stringtable(string_table *st)
Definition: string.c:107
UINT msi_save_string_table(const string_table *st, IStorage *storage, UINT *bytes_per_strref)
Definition: string.c:564
BOOL MSI_RecordIsNull(MSIRECORD *, UINT)
Definition: record.c:321
#define MSI_DATASIZEMASK
Definition: msipriv.h:47
UINT MSI_RecordCopyField(MSIRECORD *, UINT, MSIRECORD *, UINT)
Definition: record.c:166
UINT MSI_ViewFetch(MSIQUERY *, MSIRECORD **)
Definition: msiquery.c:377
#define MSITYPE_KEY
Definition: msipriv.h:52
UINT MSI_RecordSetStringW(MSIRECORD *, UINT, LPCWSTR)
Definition: record.c:597
MSIRECORD * MSI_CreateRecord(UINT)
Definition: record.c:76
UINT msi_get_stream(MSIDATABASE *, const WCHAR *, IStream **)
Definition: streams.c:499
UINT MSI_RecordSetStream(MSIRECORD *, UINT, IStream *)
Definition: record.c:671
UINT MSI_RecordGetFieldCount(const MSIRECORD *rec)
Definition: record.c:108
UINT MSI_RecordGetStringW(MSIRECORD *, UINT, LPWSTR, LPDWORD)
@ MSIMODIFY_DELETE
Definition: msiquery.h:57
@ MSIMODIFY_REPLACE
Definition: msiquery.h:55
@ MSIMODIFY_MERGE
Definition: msiquery.h:56
@ MSIMODIFY_INSERT_TEMPORARY
Definition: msiquery.h:58
@ MSIMODIFY_UPDATE
Definition: msiquery.h:53
@ MSIMODIFY_VALIDATE_DELETE
Definition: msiquery.h:62
@ MSIMODIFY_ASSIGN
Definition: msiquery.h:54
@ MSIMODIFY_VALIDATE_NEW
Definition: msiquery.h:60
@ MSIMODIFY_INSERT
Definition: msiquery.h:52
@ MSIMODIFY_REFRESH
Definition: msiquery.h:51
@ MSIMODIFY_VALIDATE_FIELD
Definition: msiquery.h:61
@ MSIMODIFY_VALIDATE
Definition: msiquery.h:59
@ MSITRANSFORM_ERROR_VIEWTRANSFORM
Definition: msiquery.h:156
@ MSIDBERROR_DUPLICATEKEY
Definition: msiquery.h:110
@ MSICONDITION_FALSE
Definition: msiquery.h:26
@ MSICONDITION_ERROR
Definition: msiquery.h:29
@ MSICONDITION_NONE
Definition: msiquery.h:28
@ MSICONDITION_TRUE
Definition: msiquery.h:27
#define MSI_NULL_INTEGER
Definition: msiquery.h:32
unsigned int UINT
Definition: ndis.h:50
#define L(x)
Definition: ntvdm.h:50
#define STGM_SHARE_EXCLUSIVE
Definition: objbase.h:923
#define STGM_WRITE
Definition: objbase.h:918
#define STGM_READ
Definition: objbase.h:917
static struct query * create_query(void)
Definition: pdh_main.c:154
long LONG
Definition: pedump.c:60
unsigned short USHORT
Definition: pedump.c:61
UINT STREAMS_CreateView(MSIDATABASE *db, MSIVIEW **view)
Definition: streams.c:539
UINT STORAGES_CreateView(MSIDATABASE *db, MSIVIEW **view)
Definition: storages.c:515
static unsigned __int64 next
Definition: rand_nt.c:6
#define err(...)
#define calloc
Definition: rosglue.h:14
const WCHAR * str
_Check_return_ _CRTIMP int __cdecl wcscmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
_Check_return_ _CRTIMP wchar_t *__cdecl wcsdup(_In_z_ const wchar_t *_Str)
#define LIST_FOR_EACH_ENTRY(elem, list, type, field)
Definition: list.h:198
#define memset(x, y, z)
Definition: compat.h:39
HRESULT hr
Definition: shlfolder.c:183
#define TRACE(s)
Definition: solgame.cpp:4
Definition: table.c:44
UINT row
Definition: table.c:47
struct column_hash_entry * next
Definition: table.c:45
UINT value
Definition: table.c:46
LPCWSTR tablename
Definition: table.c:52
UINT number
Definition: table.c:53
UINT offset
Definition: table.c:56
UINT type
Definition: table.c:55
struct column_hash_entry ** hash_table
Definition: table.c:57
LPCWSTR colname
Definition: table.c:54
Definition: copy.c:22
Definition: list.h:15
Definition: name.c:39
WCHAR * name
Definition: name.c:42
Definition: send.c:48
Definition: stat.h:55
Definition: parse.h:23
UINT num_cols
Definition: table.c:1002
MSIDATABASE * db
Definition: table.c:999
UINT row_size
Definition: table.c:1003
MSITABLE * table
Definition: table.c:1000
WCHAR name[1]
Definition: table.c:1004
struct column_info * columns
Definition: table.c:1001
MSIVIEW view
Definition: table.c:998
const WCHAR * name
struct list entry
BYTE * data
UINT bytes_per_strref
Definition: msipriv.h:111
struct list tables
Definition: msipriv.h:118
IStorage * storage
Definition: msipriv.h:109
string_table * strings
Definition: msipriv.h:110
MSIOBJECTHDR hdr
Definition: msipriv.h:151
MSICONDITION persistent
Definition: table.c:68
struct column_info * colinfo
Definition: table.c:66
BYTE ** data
Definition: table.c:62
BOOL * data_persistent
Definition: table.c:63
LONG ref_count
Definition: table.c:69
WCHAR name[1]
Definition: table.c:70
UINT row_count
Definition: table.c:64
struct list entry
Definition: table.c:65
UINT col_count
Definition: table.c:67
UINT(* insert_row)(struct tagMSIVIEW *view, MSIRECORD *record, UINT row, BOOL temporary)
Definition: msipriv.h:283
UINT(* set_row)(struct tagMSIVIEW *view, UINT row, MSIRECORD *rec, UINT mask)
Definition: msipriv.h:278
UINT(* execute)(struct tagMSIVIEW *view, MSIRECORD *record)
Definition: msipriv.h:293
UINT(* delete_row)(struct tagMSIVIEW *view, UINT row)
Definition: msipriv.h:288
UINT(* delete)(struct tagMSIVIEW *)
Definition: msipriv.h:324
MSIDBERROR error
Definition: msipriv.h:356
const WCHAR * error_column
Definition: msipriv.h:357
const MSIVIEWOPS * ops
Definition: msipriv.h:355
struct list entry
Definition: table.c:3171
LPWSTR name
Definition: table.c:3172
#define LIST_ENTRY(type)
Definition: queue.h:175
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:255
int32_t INT
Definition: typedefs.h:58
uint32_t ULONG
Definition: typedefs.h:59
wchar_t tm const _CrtWcstime_Writes_and_advances_ptr_ count wchar_t ** out
Definition: wcsftime.cpp:383
int ret
CONST void * LPCVOID
Definition: windef.h:191
int MSICONDITION
Definition: winemsi.idl:29
int MSIMODIFY
Definition: winemsi.idl:33
#define ERROR_INVALID_TABLE
Definition: winerror.h:986
#define ERROR_BAD_QUERY_SYNTAX
Definition: winerror.h:973
#define ERROR_FUNCTION_FAILED
Definition: winerror.h:985
#define ERROR_INSTALL_TRANSFORM_FAILURE
Definition: winerror.h:982
#define ERROR_INVALID_DATA
Definition: winerror.h:116
#define ERROR_NOT_FOUND
Definition: winerror.h:690
ActualNumberDriverObjects * sizeof(PDRIVER_OBJECT)) PDRIVER_OBJECT *DriverObjectList
__wchar_t WCHAR
Definition: xmlstorage.h:180
WCHAR * LPWSTR
Definition: xmlstorage.h:184
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
unsigned char BYTE
Definition: xxhash.c:193