ReactOS  0.4.15-dev-5109-g2469ce2
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 
43 typedef struct tagMSICOLUMNHASHENTRY
44 {
49 
50 typedef struct tagMSICOLUMNINFO
51 {
59 
61 {
65  struct list entry;
70  WCHAR name[1];
71 };
72 
73 /* information for default tables */
74 static 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 
81 static 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 
87 static 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 
104 static 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 
165 static 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,
248  STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm);
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;
288  ret = ERROR_SUCCESS;
289 
290 end:
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,
309  STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, &stm);
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 
348  ret = ERROR_SUCCESS;
349 
350 end:
351  IStream_Release( stm );
352 
353  return ret;
354 }
355 
356 static 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 
362 static 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 
374 static 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;
465 err:
466  msi_free( rawdata );
467  return ERROR_FUNCTION_FAILED;
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  {
523  p = _Columns_cols;
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 
538 static 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)
561  return ERROR_FUNCTION_FAILED;
562 
563  r = get_tablecolumns( db, name, columns, &column_count );
564  if (r != ERROR_SUCCESS)
565  {
566  msi_free( columns );
567  return ERROR_FUNCTION_FAILED;
568  }
569  *pcols = columns;
570  return r;
571 }
572 
573 static UINT get_table( MSIDATABASE *db, LPCWSTR name, MSITABLE **table_ret )
574 {
575  MSITABLE *table;
576  UINT r;
577 
578  /* first, see if the table is cached */
579  table = find_cached_table( db, name );
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)
589  return ERROR_FUNCTION_FAILED;
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  }
608  r = read_table_from_storage( db, table, db->storage );
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 
619 static UINT read_table_int( BYTE *const *data, UINT row, UINT col, UINT bytes )
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 
629 static UINT get_tablecolumns( MSIDATABASE *db, LPCWSTR szTableName, MSICOLUMNINFO *colinfo, UINT *sz )
630 {
631  UINT r, i, n = 0, table_id, count, maxcount = *sz;
632  MSITABLE *table = NULL;
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");
645  return ERROR_FUNCTION_FAILED;
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 );
698  return ERROR_FUNCTION_FAILED;
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;
712  MSITABLE *table;
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));
719  return ERROR_BAD_QUERY_SYNTAX;
720  }
721 
722  table = msi_alloc( sizeof (MSITABLE) + lstrlenW(name)*sizeof (WCHAR) );
723  if( !table )
724  return ERROR_FUNCTION_FAILED;
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 );
745  return ERROR_FUNCTION_FAILED;
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 )
840  r = ERROR_SUCCESS;
841  }
842 
843 err:
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 
858 static 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 
928 err:
929  msi_free( rawdata );
930  return r;
931 }
932 
934 {
935  MSITABLE *table;
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  {
953  table->data[n] = msi_realloc( table->data[n], size );
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;
963  MSITABLE *table;
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 
994 typedef struct tagMSITABLEVIEW
995 {
1003 } MSITABLEVIEW;
1004 
1006 {
1007  MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
1008  UINT offset, n;
1009 
1010  if( !tv->table )
1011  return ERROR_INVALID_PARAMETER;
1012 
1013  if( (col==0) || (col>tv->num_cols) )
1014  return ERROR_INVALID_PARAMETER;
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 
1042 static 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  {
1056  r = ERROR_OUTOFMEMORY;
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  {
1106  r = ERROR_OUTOFMEMORY;
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 
1121 err:
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  */
1132 static UINT TABLE_fetch_stream( struct tagMSIVIEW *view, UINT row, UINT col, IStream **stm )
1133 {
1134  MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
1135  UINT r;
1136  WCHAR *name;
1137 
1138  if( !view->ops->fetch_int )
1139  return ERROR_INVALID_PARAMETER;
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 )
1162  return ERROR_INVALID_PARAMETER;
1163 
1164  if( (col==0) || (col>tv->num_cols) )
1165  return ERROR_INVALID_PARAMETER;
1166 
1167  if( row >= tv->table->row_count )
1168  return ERROR_INVALID_PARAMETER;
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 
1194 static 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 {
1216  MSITABLEVIEW *tv = (MSITABLEVIEW *)view;
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 
1241 static UINT TABLE_set_string( MSIVIEW *view, UINT row, UINT col, const WCHAR *val, int len )
1242 {
1243  MSITABLEVIEW *tv = (MSITABLEVIEW *)view;
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 {
1280  MSITABLEVIEW *tv = (MSITABLEVIEW *)view;
1281 
1282  if (!tv->table)
1283  return ERROR_INVALID_PARAMETER;
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 
1335 done:
1336  msiobj_release( &rec->hdr );
1337  return r;
1338 }
1339 
1341 {
1342  MSITABLEVIEW *tv = (MSITABLEVIEW *)view;
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 
1356 static UINT get_table_value_from_record( MSITABLEVIEW *tv, MSIRECORD *rec, UINT iField, UINT *pvalue )
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 {
1390  MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
1391  UINT i, val, r = ERROR_SUCCESS;
1392 
1393  if ( !tv->table )
1394  return ERROR_INVALID_PARAMETER;
1395 
1396  /* test if any of the mask bits are invalid */
1397  if ( mask >= (1<<tv->num_cols) )
1398  return ERROR_INVALID_PARAMETER;
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 
1473 static UINT table_create_new_row( struct tagMSIVIEW *view, UINT *num, BOOL temporary )
1474 {
1475  MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
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 )
1486  return ERROR_INVALID_PARAMETER;
1487 
1488  row = msi_alloc_zero( tv->row_size );
1489  if( !row )
1490  return ERROR_NOT_ENOUGH_MEMORY;
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 );
1506  return ERROR_NOT_ENOUGH_MEMORY;
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 );
1518  return ERROR_NOT_ENOUGH_MEMORY;
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 {
1534  MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
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 
1543 static UINT TABLE_close( struct tagMSIVIEW *view )
1544 {
1545  TRACE("%p\n", view );
1546 
1547  return ERROR_SUCCESS;
1548 }
1549 
1550 static UINT TABLE_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols)
1551 {
1552  MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
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 )
1561  return ERROR_INVALID_PARAMETER;
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 {
1572  MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
1573 
1574  TRACE("%p %d %p %p\n", tv, n, name, type );
1575 
1576  if( ( n == 0 ) || ( n > tv->num_cols ) )
1577  return ERROR_INVALID_PARAMETER;
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 
1706 static UINT TABLE_insert_row( struct tagMSIVIEW *view, MSIRECORD *rec, UINT row, BOOL temporary )
1707 {
1708  MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
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 {
1741  MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
1742  UINT r, num_rows, num_cols, i;
1743 
1744  TRACE("%p %d\n", tv, row);
1745 
1746  if ( !tv->table )
1747  return ERROR_INVALID_PARAMETER;
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 {
1779  MSITABLEVIEW *tv = (MSITABLEVIEW *)view;
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)
1787  return ERROR_INVALID_PARAMETER;
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 {
1805  MSITABLEVIEW *tv = (MSITABLEVIEW *)view;
1806  UINT r, row;
1807 
1808  if (!tv->table)
1809  return ERROR_INVALID_PARAMETER;
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 
1838 static UINT TABLE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode,
1839  MSIRECORD *rec, UINT row)
1840 {
1841  MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
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  {
1856  tv->view.error_column = tv->columns[column].colname;
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 {
1915  MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
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 {
1929  MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
1930 
1931  TRACE( "%p, %ld\n", view, tv->table->ref_count );
1932  return InterlockedIncrement(&tv->table->ref_count);
1933 }
1934 
1936 {
1937  MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
1938  MSIRECORD *rec = NULL;
1939  MSIVIEW *columns = NULL;
1940  UINT row, r;
1941 
1942  if (tv->table->col_count != number)
1943  return ERROR_BAD_QUERY_SYNTAX;
1944 
1945  if (tv->table->colinfo[number-1].type & MSITYPE_TEMPORARY)
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);
1961  MSI_RecordSetInteger(rec, 2, number);
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 
1978  msi_update_table_columns(tv->db, tv->name);
1979 
1980 done:
1981  msiobj_release(&rec->hdr);
1982  columns->ops->delete(columns);
1983  return r;
1984 }
1985 
1987 {
1988  MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
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);
2016  TABLE_delete(view);
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;
2028  MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
2029  MSICOLUMNINFO *colinfo;
2030 
2031  if (temporary && !hold && !tv->table->ref_count)
2032  return ERROR_SUCCESS;
2033 
2034  if (!temporary && tv->table->col_count &&
2036  return ERROR_BAD_QUERY_SYNTAX;
2037 
2038  for (i = 0; i < tv->table->col_count; i++)
2039  {
2040  if (!wcscmp(tv->table->colinfo[i].colname, column))
2041  return ERROR_BAD_QUERY_SYNTAX;
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);
2093  MSI_RecordSetStringW(rec, 3, column);
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 {
2120  MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
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 
2159 done:
2160  msiobj_release(&rec->hdr);
2161  tables->ops->delete(tables);
2162 
2163  return r;
2164 }
2165 
2166 static const MSIVIEWOPS table_ops =
2167 {
2170  TABLE_set_int,
2173  TABLE_set_row,
2176  TABLE_execute,
2177  TABLE_close,
2180  TABLE_modify,
2181  TABLE_delete,
2182  TABLE_add_ref,
2183  TABLE_release,
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 {
2298  MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
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 {
2310  MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
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 
2325  MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
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 
2560  MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
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 
2654  MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
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 {
2737  MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
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 );
2781  if (r == ERROR_INVALID_PARAMETER)
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 
2802  tv->view.ops = &transform_view_ops;
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 
2939 static UINT read_raw_int(const BYTE *data, UINT col, UINT bytes)
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 
3066 static 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 
3077 static UINT* msi_record_to_row( const MSITABLEVIEW *tv, MSIRECORD *rec )
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 ) &&
3091  ! MSITYPE_IS_BINARY(tv->columns[i].type) )
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;
3145  ret = ERROR_SUCCESS;
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 
3170 typedef struct
3171 {
3172  struct list entry;
3174 } TRANSFORMDATA;
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) &&
3239  ! MSITYPE_IS_BINARY(tv->columns[i].type) )
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) &&
3262  !MSITYPE_IS_BINARY(tv->columns[i].type))
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 
3357 err:
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 
3416  transform = msi_alloc_zero( sizeof(TRANSFORMDATA) );
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 
3460  r = MSI_ViewExecute( query, NULL );
3461  if (r == ERROR_SUCCESS)
3462  MSI_ViewClose( query );
3463  msiobj_release( &query->hdr );
3464  if (r != ERROR_BAD_QUERY_SYNTAX && r != ERROR_SUCCESS)
3465  goto end;
3466 
3467  if (TABLE_CreateView(db, L"_TransformView", &transform_view) != ERROR_SUCCESS)
3468  goto end;
3469 
3470  if (r == ERROR_BAD_QUERY_SYNTAX)
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 
3491  ret = ERROR_SUCCESS;
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 );
3506  msi_free( transform );
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 
3515 end:
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 }
static int mime2utf(int x)
Definition: table.c:165
UINT(* delete_row)(struct tagMSIVIEW *view, UINT row)
Definition: msipriv.h:288
const WCHAR * msi_string_lookup(const string_table *st, UINT id, int *len) DECLSPEC_HIDDEN
Definition: string.c:343
#define ERROR_INVALID_PARAMETER
Definition: compat.h:101
static UINT TABLE_execute(struct tagMSIVIEW *view, MSIRECORD *record)
Definition: table.c:1532
static UINT TABLE_get_row(struct tagMSIVIEW *view, UINT row, MSIRECORD **rec)
Definition: table.c:1278
UINT TransformView_Create(MSIDATABASE *db, string_table *st, LPCWSTR name, MSIVIEW **view)
Definition: table.c:2766
LPCWSTR tablename
Definition: table.c:52
#define memmove(s1, s2, n)
Definition: mkisofs.h:881
UINT msi_get_stream(MSIDATABASE *, const WCHAR *, IStream **) DECLSPEC_HIDDEN
Definition: streams.c:499
static UINT msi_record_stream_name(const MSITABLEVIEW *tv, MSIRECORD *rec, LPWSTR name, DWORD *len)
Definition: table.c:2263
static UINT TransformView_execute(MSIVIEW *view, MSIRECORD *record)
Definition: table.c:2714
UINT number
Definition: table.c:53
MSICOLUMNINFO * colinfo
Definition: table.c:66
void MSI_CloseRecord(MSIOBJECTHDR *) DECLSPEC_HIDDEN
Definition: record.c:67
UINT MSI_RecordSetStringW(MSIRECORD *, UINT, LPCWSTR) DECLSPEC_HIDDEN
Definition: record.c:597
static UINT get_tablecolumns(MSIDATABASE *db, LPCWSTR szTableName, MSICOLUMNINFO *colinfo, UINT *sz)
Definition: table.c:629
static UINT * msi_record_to_row(const MSITABLEVIEW *tv, MSIRECORD *rec)
Definition: table.c:3077
static UINT TransformView_create_table(MSITABLEVIEW *tv, MSIRECORD *rec)
Definition: table.c:2466
VOID WINAPI CoTaskMemFree(LPVOID ptr)
Definition: ifs.c:442
UINT MSI_RecordCopyField(MSIRECORD *, UINT, MSIRECORD *, UINT) DECLSPEC_HIDDEN
Definition: record.c:166
static UINT TABLE_insert_row(struct tagMSIVIEW *view, MSIRECORD *rec, UINT row, BOOL temporary)
Definition: table.c:1706
#define ERROR_SUCCESS
Definition: deptool.c:10
const WCHAR * name
HRESULT hr
Definition: shlfolder.c:183
#define MESSAGE
Definition: options.h:86
ActualNumberDriverObjects * sizeof(PDRIVER_OBJECT)) PDRIVER_OBJECT *DriverObjectList
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
UINT MSI_CommitTables(MSIDATABASE *db)
Definition: table.c:2887
#define ERROR_NO_MORE_ITEMS
Definition: compat.h:105
#define STGM_SHARE_EXCLUSIVE
Definition: objbase.h:923
struct tagMSICOLUMNHASHENTRY * next
Definition: table.c:45
static UINT get_stream_name(const MSITABLEVIEW *tv, UINT row, WCHAR **pstname)
Definition: table.c:1042
#define TRUE
Definition: types.h:120
static WCHAR * strdupW(const WCHAR *src)
Definition: main.c:92
static UINT msi_table_get_row_size(MSIDATABASE *db, const MSICOLUMNINFO *cols, UINT count, UINT bytes_per_strref)
Definition: table.c:374
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
MSIOBJECTHDR hdr
Definition: msipriv.h:151
GLdouble GLdouble GLdouble r
Definition: gl.h:2055
char * wine_dbgstr_w(const wchar_t *wstr)
Definition: atltest.h:87
LPWSTR name
Definition: table.c:3173
GLuint GLuint GLsizei count
Definition: gl.h:1545
static void transform_view(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id)
Definition: state.c:3964
_Check_return_ _CRTIMP int __cdecl _wtoi(_In_z_ const wchar_t *_Str)
#define WARN(fmt,...)
Definition: debug.h:112
UINT MSI_RecordGetStringW(MSIRECORD *, UINT, LPWSTR, LPDWORD) DECLSPEC_HIDDEN
static UINT msi_refresh_record(struct tagMSIVIEW *view, MSIRECORD *rec, UINT row)
Definition: table.c:1818
UINT MSI_ViewExecute(MSIQUERY *, MSIRECORD *) DECLSPEC_HIDDEN
Definition: msiquery.c:502
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_table_apply_transform(MSIDATABASE *db, IStorage *stg, int err_cond)
Definition: table.c:3371
__WINE_SERVER_LIST_INLINE void list_add_head(struct list *list, struct list *elem)
Definition: list.h:96
static UINT read_table_from_storage(MSIDATABASE *db, MSITABLE *t, IStorage *stg)
Definition: table.c:392
UINT MSI_RecordGetIStream(MSIRECORD *, UINT, IStream **) DECLSPEC_HIDDEN
Definition: record.c:852
GLdouble n
Definition: glext.h:7729
static const MSICOLUMNINFO _Columns_cols[4]
Definition: table.c:74
GLdouble GLdouble t
Definition: gl.h:2047
int MSICONDITION
Definition: winemsi.idl:29
struct nls_table * tables
Definition: nls_base.c:22
static const MSICOLUMNINFO _Tables_cols[1]
Definition: table.c:81
#define ERROR_NOT_ENOUGH_MEMORY
Definition: dderror.h:7
#define assert(x)
Definition: debug.h:53
UINT msi_create_table(MSIDATABASE *db, LPCWSTR name, column_info *col_info, MSICONDITION persistent, BOOL hold)
Definition: table.c:705
#define MSITYPE_IS_BINARY(type)
Definition: msipriv.h:62
GLenum GLsizei GLenum GLenum const GLvoid * table
Definition: glext.h:5644
#define LONG_STR_BYTES
Definition: msipriv.h:57
GLint GLint GLint GLint GLint x
Definition: gl.h:1548
MSIDATABASE * db
Definition: table.c:997
static UINT TransformView_add_column(MSITABLEVIEW *tv, MSIRECORD *rec)
Definition: table.c:2501
struct tagMSICOLUMNHASHENTRY MSICOLUMNHASHENTRY
static UINT TABLE_delete(struct tagMSIVIEW *view)
Definition: table.c:1913
MSITABLE * table
Definition: table.c:998
#define MSI_NULL_INTEGER
Definition: msiquery.h:32
struct _column_info * next
Definition: msipriv.h:226
UINT col_count
Definition: table.c:67
static void msi_free(void *mem)
Definition: msipriv.h:1159
static UINT msi_row_matches(MSITABLEVIEW *tv, UINT row, const UINT *data, UINT *column)
Definition: table.c:3121
string_table * msi_load_string_table(IStorage *stg, UINT *bytes_per_strref) DECLSPEC_HIDDEN
Definition: string.c:478
UINT(* execute)(struct tagMSIVIEW *view, MSIRECORD *record)
Definition: msipriv.h:293
#define MSITYPE_STRING
Definition: msipriv.h:50
static UINT int_to_table_storage(const MSITABLEVIEW *tv, UINT col, int val, UINT *ret)
Definition: table.c:1194
if(dx==0 &&dy==0)
Definition: linetemp.h:174
struct tagMSITABLEVIEW MSITABLEVIEW
static UINT get_defaulttablecolumns(MSIDATABASE *db, LPCWSTR name, MSICOLUMNINFO *colinfo, UINT *sz)
Definition: table.c:509
#define lstrlenW
Definition: compat.h:609
int32_t INT
Definition: typedefs.h:58
static void * msi_realloc(void *mem, size_t len) __WINE_ALLOC_SIZE(2)
Definition: msipriv.h:1154
Definition: send.c:48
#define MAX_STREAM_NAME
Definition: table.c:85
const GLfloat * m
Definition: glext.h:10848
static UINT TABLE_get_dimensions(struct tagMSIVIEW *view, UINT *rows, UINT *cols)
Definition: table.c:1550
static UINT table_set_bytes(MSITABLEVIEW *tv, UINT row, UINT col, UINT val)
Definition: table.c:1157
static void * msi_alloc_zero(size_t len) __WINE_ALLOC_SIZE(1)
Definition: msipriv.h:1148
static UINT get_table_value_from_record(MSITABLEVIEW *tv, MSIRECORD *rec, UINT iField, UINT *pvalue)
Definition: table.c:1356
static UINT msi_table_find_row(MSITABLEVIEW *tv, MSIRECORD *rec, UINT *row, UINT *column)
Definition: table.c:3150
__WINE_SERVER_LIST_INLINE struct list * list_head(const struct list *list)
Definition: list.h:131
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
__WINE_SERVER_LIST_INLINE void list_add_tail(struct list *list, struct list *elem)
Definition: list.h:102
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
BYTE ** data
Definition: table.c:62
#define LIST_FOR_EACH_ENTRY(elem, list, type, field)
Definition: list.h:198
#define L(x)
Definition: ntvdm.h:50
UINT MSI_RecordSetInteger(MSIRECORD *, UINT, int) DECLSPEC_HIDDEN
Definition: record.c:280
VOID msi_destroy_stringtable(string_table *st) DECLSPEC_HIDDEN
Definition: string.c:107
GLenum GLint GLuint mask
Definition: glext.h:6028
#define ERROR_FUNCTION_FAILED
Definition: winerror.h:985
UINT STORAGES_CreateView(MSIDATABASE *db, MSIVIEW **view) DECLSPEC_HIDDEN
Definition: storages.c:515
static unsigned char bytes[4]
Definition: adnsresfilter.c:74
UINT MSI_ViewFetch(MSIQUERY *, MSIRECORD **) DECLSPEC_HIDDEN
Definition: msiquery.c:377
#define FALSE
Definition: types.h:117
BOOL * data_persistent
Definition: table.c:63
void free_cached_tables(MSIDATABASE *db)
Definition: table.c:470
unsigned int BOOL
Definition: ntddk_ex.h:94
string_table * strings
Definition: msipriv.h:110
long LONG
Definition: pedump.c:60
BOOL MSI_RecordIsNull(MSIRECORD *, UINT) DECLSPEC_HIDDEN
Definition: record.c:321
static size_t double number
Definition: printf.c:71
static UINT table_get_column_info(MSIDATABASE *db, LPCWSTR name, MSICOLUMNINFO **pcols, UINT *pcount)
Definition: table.c:540
UINT read_stream_data(IStorage *stg, LPCWSTR stname, BOOL table, BYTE **pdata, UINT *psz)
Definition: table.c:232
static void dump_table(const string_table *st, const USHORT *rawdata, UINT rawsize)
Definition: table.c:3066
#define debugstr_w
Definition: kernel32.h:32
GLenum GLint ref
Definition: glext.h:6028
#define FIXME(fmt,...)
Definition: debug.h:111
#define ERROR_INSTALL_TRANSFORM_FAILURE
Definition: winerror.h:982
struct list entry
unsigned int idx
Definition: utils.c:41
const WCHAR * str
static UINT bytes_per_column(MSIDATABASE *db, const MSICOLUMNINFO *col, UINT bytes_per_strref)
Definition: table.c:87
struct list tables
Definition: msipriv.h:118
UINT msi_clone_properties(MSIDATABASE *) DECLSPEC_HIDDEN
Definition: package.c:382
int _snwprintf(wchar_t *buffer, size_t count, const wchar_t *format,...)
#define STGM_WRITE
Definition: objbase.h:918
UINT row_count
Definition: table.c:64
static UINT TransformView_set_row(MSIVIEW *view, UINT row, MSIRECORD *rec, UINT mask)
Definition: table.c:2320
#define MSITYPE_NULLABLE
Definition: msipriv.h:51
static UINT table_create_new_row(struct tagMSIVIEW *view, UINT *num, BOOL temporary)
Definition: table.c:1473
int MSIMODIFY
Definition: winemsi.idl:33
static const MSIVIEWOPS table_ops
Definition: table.c:2166
MSIVIEW view
Definition: table.c:996
static PROTOCOLDATA * pdata
Definition: protocol.c:158
#define b
Definition: ke_i.h:79
static UINT TransformView_insert_row(MSIVIEW *view, MSIRECORD *rec, UINT row, BOOL temporary)
Definition: table.c:2555
LONG ref_count
Definition: table.c:69
GLuint GLfloat * val
Definition: glext.h:7180
UINT MSI_ViewClose(MSIQUERY *) DECLSPEC_HIDDEN
Definition: msiquery.c:454
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 append_storage_to_db(MSIDATABASE *db, IStorage *stg)
Definition: database.c:76
r l[0]
Definition: byte_order.h:167
#define STGM_READ
Definition: objbase.h:917
static UINT msi_record_encoded_stream_name(const MSITABLEVIEW *tv, MSIRECORD *rec, LPWSTR *pstname)
Definition: table.c:2949
static UINT TABLE_set_row(struct tagMSIVIEW *view, UINT row, MSIRECORD *rec, UINT mask)
Definition: table.c:1388
MSICOLUMNINFO * columns
Definition: table.c:999
__WINE_SERVER_LIST_INLINE void list_remove(struct list *elem)
Definition: list.h:108
void dump_record(MSIRECORD *) DECLSPEC_HIDDEN
Definition: record.c:1028
GLboolean GLboolean GLboolean b
Definition: glext.h:6204
#define TRACE(s)
Definition: solgame.cpp:4
static WCHAR * create_key_string(MSITABLEVIEW *tv, MSIRECORD *rec)
Definition: table.c:2231
struct list entry
Definition: table.c:65
static UINT TABLE_drop(struct tagMSIVIEW *view)
Definition: table.c:2118
UINT bytes_per_strref
Definition: msipriv.h:111
GLsizeiptr size
Definition: glext.h:5919
WCHAR name[1]
Definition: table.c:1002
static UINT read_raw_int(const BYTE *data, UINT col, UINT bytes)
Definition: table.c:2939
__wchar_t WCHAR
Definition: xmlstorage.h:180
static UINT TransformView_close(MSIVIEW *view)
Definition: table.c:2719
const MSIVIEWOPS * ops
Definition: msipriv.h:355
LONG HRESULT
Definition: typedefs.h:79
GLintptr offset
Definition: glext.h:5920
static UINT TABLE_fetch_stream(struct tagMSIVIEW *view, UINT row, UINT col, IStream **stm)
Definition: table.c:1132
UINT msi_string2id(const string_table *st, const WCHAR *data, int len, UINT *id) DECLSPEC_HIDDEN
Definition: string.c:400
LPWSTR encode_streamname(BOOL bTable, LPCWSTR in)
Definition: table.c:119
static UINT msi_table_update(struct tagMSIVIEW *view, MSIRECORD *rec, UINT row)
Definition: table.c:1777
static const MSIVIEWOPS transform_view_ops
Definition: table.c:2743
const GLubyte * c
Definition: glext.h:8905
UINT TABLE_CreateView(MSIDATABASE *db, LPCWSTR name, MSIVIEW **view)
Definition: table.c:2189
int JSAMPARRAY int int num_rows
Definition: jpegint.h:419
static FILE * out
Definition: regtests2xml.c:44
unsigned long DWORD
Definition: ntddk_ex.h:95
static int find_insert_index(MSITABLEVIEW *tv, MSIRECORD *rec)
Definition: table.c:1681
GLuint GLuint num
Definition: glext.h:9618
static UINT TransformView_get_column_info(MSIVIEW *view, UINT n, LPCWSTR *name, UINT *type, BOOL *temporary, LPCWSTR *table_name)
Definition: table.c:2729
UINT write_stream_data(IStorage *stg, LPCWSTR stname, LPCVOID data, UINT sz, BOOL bTable)
Definition: table.c:296
int JSAMPARRAY int int JDIMENSION num_cols
Definition: jpegint.h:419
static int utf2mime(int x)
Definition: table.c:104
#define MSITYPE_KEY
Definition: msipriv.h:52
GLdouble GLdouble GLdouble GLdouble q
Definition: gl.h:2063
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
int msiobj_release(MSIOBJECTHDR *info)
Definition: handle.c:241
static void table_calc_column_offsets(MSIDATABASE *db, MSICOLUMNINFO *colinfo, DWORD count)
Definition: table.c:492
GLuint GLuint end
Definition: gl.h:1545
static UINT TABLE_add_ref(struct tagMSIVIEW *view)
Definition: table.c:1927
static UINT TransformView_fetch_int(MSIVIEW *view, UINT row, UINT col, UINT *val)
Definition: table.c:2296
int ret
void enum_stream_names(IStorage *stg)
Definition: table.c:204
MSIRECORD * MSI_CreateRecord(UINT) DECLSPEC_HIDDEN
Definition: record.c:76
GLsizei const GLchar *const * strings
Definition: glext.h:7622
UINT MSI_RecordSetStream(MSIRECORD *, UINT, IStream *) DECLSPEC_HIDDEN
Definition: record.c:671
#define InterlockedDecrement
Definition: armddk.h:52
Definition: parse.h:22
static UINT add_stream(MSIDATABASE *db, const WCHAR *name, IStream *data)
Definition: table.c:1288
static UINT read_table_int(BYTE *const *data, UINT row, UINT col, UINT bytes)
Definition: table.c:619
static UINT get_table(MSIDATABASE *db, LPCWSTR name, MSITABLE **table_ret)
Definition: table.c:573
HKEY key
Definition: reg.c:28
WCHAR name[1]
Definition: table.c:70
Definition: stat.h:55
uint32_t entry
Definition: isohybrid.c:63
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
GLenum GLsizei len
Definition: glext.h:6722
static UINT TABLE_set_string(MSIVIEW *view, UINT row, UINT col, const WCHAR *val, int len)
Definition: table.c:1241
Definition: _list.h:228
UINT row_size
Definition: table.c:1001
#define err(...)
int _cdecl swprintf(const WCHAR *,...)
static UINT TABLE_remove_column(struct tagMSIVIEW *view, UINT number)
Definition: table.c:1935
UINT msi_save_string_table(const string_table *st, IStorage *storage, UINT *bytes_per_strref) DECLSPEC_HIDDEN
Definition: string.c:564
#define debugstr_wn
Definition: kernel32.h:33
unsigned char BYTE
Definition: xxhash.c:193
static UINT TABLE_modify(struct tagMSIVIEW *view, MSIMODIFY eModifyMode, MSIRECORD *rec, UINT row)
Definition: table.c:1838
static UINT msi_table_assign(struct tagMSIVIEW *view, MSIRECORD *rec)
Definition: table.c:1803
UINT MSI_RecordSetIStream(MSIRECORD *, UINT, IStream *) DECLSPEC_HIDDEN
Definition: record.c:836
MSICONDITION persistent
Definition: table.c:68
#define ERROR_INVALID_DATA
Definition: winerror.h:116
static void msi_free_colinfo(MSICOLUMNINFO *colinfo, UINT count)
Definition: table.c:356
int MSI_RecordGetInteger(MSIRECORD *, UINT) DECLSPEC_HIDDEN
Definition: record.c:213
const WCHAR * msi_record_get_string(const MSIRECORD *, UINT, int *) DECLSPEC_HIDDEN
Definition: record.c:420
#define ERR(fmt,...)
Definition: debug.h:110
#define ERROR_INVALID_TABLE
Definition: winerror.h:986
static void free_table(MSITABLE *table)
Definition: table.c:362
_Check_return_ _CRTIMP int __cdecl wcscmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
UINT(* set_row)(struct tagMSIVIEW *view, UINT row, MSIRECORD *rec, UINT mask)
Definition: msipriv.h:278
UINT(* delete)(struct tagMSIVIEW *)
Definition: msipriv.h:324
__WINE_SERVER_LIST_INLINE int list_empty(const struct list *list)
Definition: list.h:143
_CRTIMP int __cdecl stat(const char *_Filename, struct stat *_Stat)
Definition: stat.h:345
UINT offset
Definition: table.c:56
static unsigned __int64 next
Definition: rand_nt.c:6
#define InterlockedIncrement
Definition: armddk.h:53
static UINT TABLE_delete_row(struct tagMSIVIEW *view, UINT row)
Definition: table.c:1739
static UINT TABLE_close(struct tagMSIVIEW *view)
Definition: table.c:1543
#define lstrcpyW
Definition: compat.h:608
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
GLuint in
Definition: glext.h:9616
const WCHAR * error_column
Definition: msipriv.h:357
#define MSITYPE_TEMPORARY
Definition: msipriv.h:53
unsigned short USHORT
Definition: pedump.c:61
BYTE * data
#define ARRAY_SIZE(a)
Definition: main.h:24
MSICOLUMNHASHENTRY ** hash_table
Definition: table.c:57
UINT STREAMS_CreateView(MSIDATABASE *db, MSIVIEW **view) DECLSPEC_HIDDEN
Definition: streams.c:539
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:255
BOOL decode_streamname(LPCWSTR in, LPWSTR out)
Definition: table.c:178
static UINT TransformView_drop_table(MSITABLEVIEW *tv, UINT row)
Definition: table.c:2604
unsigned int UINT
Definition: ndis.h:50
UINT msi_record_set_string(MSIRECORD *, UINT, const WCHAR *, int) DECLSPEC_HIDDEN
Definition: record.c:573
#define NULL
Definition: types.h:112
#define MSITYPE_VALID
Definition: msipriv.h:48
UINT msi_view_get_row(MSIDATABASE *, MSIVIEW *, UINT, MSIRECORD **) DECLSPEC_HIDDEN
Definition: msiquery.c:353
#define ERROR_NOT_FOUND
Definition: winerror.h:690
_CRTIMP size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
static UINT TABLE_release(struct tagMSIVIEW *view)
Definition: table.c:1986
static struct query * create_query(void)
Definition: pdh_main.c:152
static UINT TABLE_set_stream(MSIVIEW *view, UINT row, UINT col, IStream *stream)
Definition: table.c:1340
CONST void * LPCVOID
Definition: windef.h:191
Definition: name.c:38
static UINT TABLE_fetch_int(struct tagMSIVIEW *view, UINT row, UINT col, UINT *val)
Definition: table.c:1005
__WINE_SERVER_LIST_INLINE void list_init(struct list *list)
Definition: list.h:149
#define c
Definition: ke_i.h:80
static void * msi_alloc(size_t len) __WINE_ALLOC_SIZE(1)
Definition: msipriv.h:1142
unsigned int ULONG
Definition: retypes.h:1
GLenum GLuint id
Definition: glext.h:5579
#define ERROR_CALL_NOT_IMPLEMENTED
Definition: compat.h:102
GLuint GLenum GLenum transform
Definition: glext.h:9407
static UINT save_table(MSIDATABASE *db, const MSITABLE *t, UINT bytes_per_strref)
Definition: table.c:858
static UINT table_validate_new(MSITABLEVIEW *tv, MSIRECORD *rec, UINT *column)
Definition: table.c:1604
static UINT TransformView_get_dimensions(MSIVIEW *view, UINT *rows, UINT *cols)
Definition: table.c:2724
LPCWSTR colname
Definition: table.c:54
static UINT TransformView_delete(MSIVIEW *view)
Definition: table.c:2735
IStorage * storage
Definition: msipriv.h:109
LPWSTR WINAPI lstrcatW(LPWSTR lpString1, LPCWSTR lpString2)
Definition: lstring.c:274
GLenum GLenum GLvoid GLvoid * column
Definition: glext.h:5664
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
static UINT TABLE_add_column(struct tagMSIVIEW *view, LPCWSTR column, INT type, BOOL hold)
Definition: table.c:2023
BOOL msi_add_string(string_table *st, const WCHAR *data, int len, BOOL persistent) DECLSPEC_HIDDEN
Definition: string.c:303
GLfloat GLfloat p
Definition: glext.h:8902
WCHAR * LPWSTR
Definition: xmlstorage.h:184
UINT num_cols
Definition: table.c:1000
#define LIST_ENTRY(type)
Definition: queue.h:175
struct tagMSICOLUMNINFO MSICOLUMNINFO
static UINT TransformView_fetch_stream(MSIVIEW *view, UINT row, UINT col, IStream **stm)
Definition: table.c:2308
#define memset(x, y, z)
Definition: compat.h:39
#define TRACE_ON(x)
Definition: compat.h:75
WINE_DEFAULT_DEBUG_CHANNEL(msidb)
static UINT TABLE_set_int(MSIVIEW *view, UINT row, UINT col, int val)
Definition: table.c:1214
int k
Definition: mpi.c:3369
GLenum query
Definition: glext.h:7781
#define MSI_DATASIZEMASK
Definition: msipriv.h:47
#define ERROR_BAD_QUERY_SYNTAX
Definition: winerror.h:973
static MSITABLE * find_cached_table(MSIDATABASE *db, LPCWSTR name)
Definition: table.c:481
BOOL TABLE_Exists(MSIDATABASE *db, LPCWSTR name)
Definition: table.c:960
MSIDBERROR error
Definition: msipriv.h:356
UINT MSI_RecordGetFieldCount(const MSIRECORD *rec) DECLSPEC_HIDDEN
Definition: record.c:108
#define ERROR_OUTOFMEMORY
Definition: deptool.c:13
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
WCHAR * name
Definition: name.c:42
Definition: copy.c:22
UINT(* insert_row)(struct tagMSIVIEW *view, MSIRECORD *record, UINT row, BOOL temporary)
Definition: msipriv.h:283
static void msi_update_table_columns(MSIDATABASE *db, LPCWSTR name)
Definition: table.c:933
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
UINT MSI_DatabaseOpenViewW(MSIDATABASE *, LPCWSTR, MSIQUERY **) DECLSPEC_HIDDEN
GLuint const GLchar * name
Definition: glext.h:6031