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