1 /* 2 * Implementation of the Microsoft Installer (msi.dll) 3 * 4 * Copyright 2002-2005 Mike McCormack for CodeWeavers 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21 #include <stdarg.h> 22 #include <assert.h> 23 24 #define COBJMACROS 25 26 #include "windef.h" 27 #include "winbase.h" 28 #include "winerror.h" 29 #include "msi.h" 30 #include "msiquery.h" 31 #include "objbase.h" 32 #include "objidl.h" 33 #include "winnls.h" 34 #include "msipriv.h" 35 #include "query.h" 36 37 #include "wine/debug.h" 38 39 WINE_DEFAULT_DEBUG_CHANNEL(msidb); 40 41 #define MSITABLE_HASH_TABLE_SIZE 37 42 43 typedef struct tagMSICOLUMNHASHENTRY 44 { 45 struct tagMSICOLUMNHASHENTRY *next; 46 UINT value; 47 UINT row; 48 } MSICOLUMNHASHENTRY; 49 50 typedef struct tagMSICOLUMNINFO 51 { 52 LPCWSTR tablename; 53 UINT number; 54 LPCWSTR colname; 55 UINT type; 56 UINT offset; 57 MSICOLUMNHASHENTRY **hash_table; 58 } MSICOLUMNINFO; 59 60 struct tagMSITABLE 61 { 62 BYTE **data; 63 BOOL *data_persistent; 64 UINT row_count; 65 struct list entry; 66 MSICOLUMNINFO *colinfo; 67 UINT col_count; 68 MSICONDITION persistent; 69 LONG ref_count; 70 WCHAR name[1]; 71 }; 72 73 /* information for default tables */ 74 static const 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 119 LPWSTR encode_streamname(BOOL bTable, LPCWSTR in) 120 { 121 DWORD count = MAX_STREAM_NAME; 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 178 BOOL decode_streamname(LPCWSTR in, LPWSTR out) 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 204 void enum_stream_names( IStorage *stg ) 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 232 UINT read_stream_data( IStorage *stg, LPCWSTR stname, BOOL table, 233 BYTE **pdata, UINT *psz ) 234 { 235 HRESULT r; 236 UINT ret = ERROR_FUNCTION_FAILED; 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 ); 274 ret = ERROR_NOT_ENOUGH_MEMORY; 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 296 UINT write_stream_data( IStorage *stg, LPCWSTR stname, 297 LPCVOID data, UINT sz, BOOL bTable ) 298 { 299 HRESULT r; 300 UINT ret = ERROR_FUNCTION_FAILED; 301 ULONG count; 302 IStream *stm = NULL; 303 ULARGE_INTEGER size; 304 LARGE_INTEGER pos; 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 */ 392 static UINT read_table_from_storage( MSIDATABASE *db, MSITABLE *t, IStorage *stg ) 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 470 void free_cached_tables( MSIDATABASE *db ) 471 { 472 while( !list_empty( &db->tables ) ) 473 { 474 MSITABLE *t = LIST_ENTRY( list_head( &db->tables ), MSITABLE, entry ); 475 476 list_remove( &t->entry ); 477 free_table( t ); 478 } 479 } 480 481 static MSITABLE *find_cached_table( MSIDATABASE *db, LPCWSTR name ) 482 { 483 MSITABLE *t; 484 485 LIST_FOR_EACH_ENTRY( t, &db->tables, MSITABLE, entry ) 486 if( !wcscmp( name, t->name ) ) 487 return t; 488 489 return NULL; 490 } 491 492 static void table_calc_column_offsets( MSIDATABASE *db, MSICOLUMNINFO *colinfo, DWORD count ) 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 509 static UINT get_defaulttablecolumns( MSIDATABASE *db, LPCWSTR name, MSICOLUMNINFO *colinfo, UINT *sz ) 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 540 static UINT table_get_column_info( MSIDATABASE *db, LPCWSTR name, MSICOLUMNINFO **pcols, UINT *pcount ) 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) 555 return ERROR_INVALID_PARAMETER; 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 705 UINT msi_create_table( MSIDATABASE *db, LPCWSTR name, column_info *col_info, 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; 862 UINT r = ERROR_FUNCTION_FAILED; 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 { 884 r = ERROR_NOT_ENOUGH_MEMORY; 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 933 static void msi_update_table_columns( MSIDATABASE *db, LPCWSTR name ) 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 */ 960 BOOL TABLE_Exists( MSIDATABASE *db, LPCWSTR name ) 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 { 996 MSIVIEW view; 997 MSIDATABASE *db; 998 MSITABLE *table; 999 MSICOLUMNINFO *columns; 1000 UINT num_cols; 1001 UINT row_size; 1002 WCHAR name[1]; 1003 } MSITABLEVIEW; 1004 1005 static UINT TABLE_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val ) 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 { 1078 r = ERROR_INVALID_PARAMETER; 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 ); 1096 r = ERROR_FUNCTION_FAILED; 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. */ 1157 static UINT table_set_bytes( MSITABLEVIEW *tv, UINT row, UINT col, UINT val ) 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 1214 static UINT TABLE_set_int( MSIVIEW *view, UINT row, UINT col, int val ) 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 1278 static UINT TABLE_get_row( struct tagMSIVIEW *view, UINT row, MSIRECORD **rec ) 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 1288 static UINT add_stream( MSIDATABASE *db, const WCHAR *name, IStream *data ) 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 1340 static UINT TABLE_set_stream( MSIVIEW *view, UINT row, UINT col, IStream *stream ) 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 { 1358 MSICOLUMNINFO columninfo; 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 1388 static UINT TABLE_set_row( struct tagMSIVIEW *view, UINT row, MSIRECORD *rec, UINT mask ) 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 1532 static UINT TABLE_execute( struct tagMSIVIEW *view, MSIRECORD *record ) 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 1568 static UINT TABLE_get_column_info( struct tagMSIVIEW *view, 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 1602 static UINT msi_table_find_row( MSITABLEVIEW *tv, MSIRECORD *rec, UINT *row, UINT *column ); 1603 1604 static UINT table_validate_new( MSITABLEVIEW *tv, MSIRECORD *rec, UINT *column ) 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 1648 static int compare_record( MSITABLEVIEW *tv, UINT row, MSIRECORD *rec ) 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 1681 static int find_insert_index( MSITABLEVIEW *tv, MSIRECORD *rec ) 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 1739 static UINT TABLE_delete_row( struct tagMSIVIEW *view, UINT row ) 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 1749 r = TABLE_get_dimensions( view, &num_rows, &num_cols ); 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 1777 static UINT msi_table_update(struct tagMSIVIEW *view, MSIRECORD *rec, UINT row) 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 1803 static UINT msi_table_assign(struct tagMSIVIEW *view, MSIRECORD *rec) 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 1818 static UINT msi_refresh_record( struct tagMSIVIEW *view, MSIRECORD *rec, UINT row ) 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 1830 count = MSI_RecordGetFieldCount(rec); 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; 1851 case MSIMODIFY_VALIDATE_NEW: 1852 r = table_validate_new( tv, rec, &column ); 1853 if (r != ERROR_SUCCESS) 1854 { 1855 tv->view.error = MSIDBERROR_DUPLICATEKEY; 1856 tv->view.error_column = tv->columns[column].colname; 1857 r = ERROR_INVALID_DATA; 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 1868 case MSIMODIFY_INSERT_TEMPORARY: 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: 1900 case MSIMODIFY_VALIDATE_FIELD: 1901 case MSIMODIFY_VALIDATE_DELETE: 1902 FIXME("%p %d %p - mode not implemented\n", view, eModifyMode, rec ); 1903 r = ERROR_CALL_NOT_IMPLEMENTED; 1904 break; 1905 1906 default: 1907 r = ERROR_INVALID_DATA; 1908 } 1909 1910 return r; 1911 } 1912 1913 static UINT TABLE_delete( struct tagMSIVIEW *view ) 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 1927 static UINT TABLE_add_ref(struct tagMSIVIEW *view) 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 1935 static UINT TABLE_remove_column(struct tagMSIVIEW *view, UINT number) 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 1986 static UINT TABLE_release(struct tagMSIVIEW *view) 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 1995 ref = InterlockedDecrement(&tv->table->ref_count); 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 { 2002 r = TABLE_remove_column(view, tv->table->colinfo[i].number); 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 2023 static UINT TABLE_add_column(struct tagMSIVIEW *view, LPCWSTR column, 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 && 2035 tv->table->colinfo[tv->table->col_count-1].type & MSITYPE_TEMPORARY) 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 2062 table_calc_column_offsets( tv->db, tv->table->colinfo, tv->table->col_count); 2063 2064 size = msi_table_get_row_size( tv->db, tv->table->colinfo, tv->table->col_count, LONG_STR_BYTES ); 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) 2114 TABLE_add_ref(view); 2115 return ERROR_SUCCESS; 2116 } 2117 2118 static UINT TABLE_drop(struct tagMSIVIEW *view) 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 { 2130 r = TABLE_remove_column(view, tv->table->colinfo[i].number); 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 2148 r = msi_table_find_row((MSITABLEVIEW *)tables, rec, &row, NULL); 2149 if (r != ERROR_SUCCESS) 2150 goto done; 2151 2152 r = TABLE_delete_row(tables, row); 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 { 2168 TABLE_fetch_int, 2169 TABLE_fetch_stream, 2170 TABLE_set_int, 2171 TABLE_set_string, 2172 TABLE_set_stream, 2173 TABLE_set_row, 2174 TABLE_insert_row, 2175 TABLE_delete_row, 2176 TABLE_execute, 2177 TABLE_close, 2178 TABLE_get_dimensions, 2179 TABLE_get_column_info, 2180 TABLE_modify, 2181 TABLE_delete, 2182 TABLE_add_ref, 2183 TABLE_release, 2184 TABLE_add_column, 2185 NULL, 2186 TABLE_drop, 2187 }; 2188 2189 UINT TABLE_CreateView( MSIDATABASE *db, LPCWSTR name, MSIVIEW **view ) 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; 2221 tv->row_size = msi_table_get_row_size( db, tv->table->colinfo, tv->table->col_count, LONG_STR_BYTES ); 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 2231 static WCHAR* create_key_string(MSITABLEVIEW *tv, MSIRECORD *rec) 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 2263 static UINT msi_record_stream_name( const MSITABLEVIEW *tv, MSIRECORD *rec, LPWSTR name, DWORD *len ) 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 2296 static UINT TransformView_fetch_int( MSIVIEW *view, UINT row, UINT col, UINT *val ) 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 2308 static UINT TransformView_fetch_stream( MSIVIEW *view, UINT row, UINT col, IStream **stm ) 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 2320 static UINT TransformView_set_row( MSIVIEW *view, UINT row, MSIRECORD *rec, UINT mask ) 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" ); 2336 return ERROR_INSTALL_TRANSFORM_FAILURE; 2337 } 2338 2339 if (!wcscmp( tv->name, L"_Tables" )) 2340 { 2341 ERR( "trying to modify existing table\n" ); 2342 return ERROR_INSTALL_TRANSFORM_FAILURE; 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 2466 static UINT TransformView_create_table( MSITABLEVIEW *tv, MSIRECORD *rec ) 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) 2479 return ERROR_INSTALL_TRANSFORM_FAILURE; 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 2501 static UINT TransformView_add_column( MSITABLEVIEW *tv, MSIRECORD *rec ) 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 2555 static UINT TransformView_insert_row( MSIVIEW *view, MSIRECORD *rec, UINT row, BOOL temporary ) 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 2604 static UINT TransformView_drop_table( MSITABLEVIEW *tv, UINT row ) 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) 2621 return ERROR_INSTALL_TRANSFORM_FAILURE; 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 2648 static UINT TransformView_delete_row( MSIVIEW *view, UINT row ) 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"); 2663 return ERROR_INSTALL_TRANSFORM_FAILURE; 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 2714 static UINT TransformView_execute( MSIVIEW *view, MSIRECORD *record ) 2715 { 2716 return ERROR_SUCCESS; 2717 } 2718 2719 static UINT TransformView_close( MSIVIEW *view ) 2720 { 2721 return ERROR_SUCCESS; 2722 } 2723 2724 static UINT TransformView_get_dimensions( MSIVIEW *view, UINT *rows, UINT *cols ) 2725 { 2726 return TABLE_get_dimensions( view, rows, cols ); 2727 } 2728 2729 static UINT TransformView_get_column_info( MSIVIEW *view, UINT n, LPCWSTR *name, UINT *type, 2730 BOOL *temporary, LPCWSTR *table_name ) 2731 { 2732 return TABLE_get_column_info( view, n, name, type, temporary, table_name ); 2733 } 2734 2735 static UINT TransformView_delete( MSIVIEW *view ) 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 2743 static const MSIVIEWOPS transform_view_ops = 2744 { 2745 TransformView_fetch_int, 2746 TransformView_fetch_stream, 2747 NULL, 2748 NULL, 2749 NULL, 2750 TransformView_set_row, 2751 TransformView_insert_row, 2752 TransformView_delete_row, 2753 TransformView_execute, 2754 TransformView_close, 2755 TransformView_get_dimensions, 2756 TransformView_get_column_info, 2757 NULL, 2758 TransformView_delete, 2759 NULL, 2760 NULL, 2761 NULL, 2762 NULL, 2763 NULL 2764 }; 2765 2766 UINT TransformView_Create( MSIDATABASE *db, string_table *st, LPCWSTR name, MSIVIEW **view ) 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 2887 UINT MSI_CommitTables( MSIDATABASE *db ) 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 2902 LIST_FOR_EACH_ENTRY( table, &db->tables, MSITABLE, entry ) 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 ); 2917 r = ERROR_FUNCTION_FAILED; 2918 } 2919 return r; 2920 } 2921 2922 MSICONDITION MSI_DatabaseIsTablePersistent( MSIDATABASE *db, LPCWSTR table ) 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 2949 static UINT msi_record_encoded_stream_name( const MSITABLEVIEW *tv, MSIRECORD *rec, LPWSTR *pstname ) 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 2978 static MSIRECORD *msi_get_transform_record( const MSITABLEVIEW *tv, const string_table *st, 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 3121 static UINT msi_row_matches( MSITABLEVIEW *tv, UINT row, const UINT *data, UINT *column ) 3122 { 3123 UINT i, r, x, ret = ERROR_FUNCTION_FAILED; 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 { 3141 ret = ERROR_FUNCTION_FAILED; 3142 break; 3143 } 3144 if (column) *column = i; 3145 ret = ERROR_SUCCESS; 3146 } 3147 return ret; 3148 } 3149 3150 static UINT msi_table_find_row( MSITABLEVIEW *tv, MSIRECORD *rec, UINT *row, UINT *column ) 3151 { 3152 UINT i, r = ERROR_FUNCTION_FAILED, *data; 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; 3173 LPWSTR name; 3174 } TRANSFORMDATA; 3175 3176 static UINT msi_table_load_transform( MSIDATABASE *db, IStorage *stg, 3177 string_table *st, TRANSFORMDATA *transform, 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; 3283 UINT number = MSI_NULL_INTEGER; 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 3314 r = ERROR_FUNCTION_FAILED; 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" )) 3349 msi_update_table_columns( db, table ); 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 */ 3371 UINT msi_table_apply_transform( MSIDATABASE *db, IStorage *stg, int err_cond ) 3372 { 3373 struct list transforms; 3374 IEnumSTATSTG *stgenum = NULL; 3375 TRANSFORMDATA *transform; 3376 TRANSFORMDATA *tables = NULL, *columns = NULL; 3377 HRESULT hr; 3378 STATSTG stat; 3379 string_table *strings; 3380 UINT ret = ERROR_FUNCTION_FAILED; 3381 UINT bytes_per_strref; 3382 BOOL property_update = FALSE; 3383 MSIVIEW *transform_view = NULL; 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 3456 r = MSI_DatabaseOpenViewW( db, create_query, &query ); 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 ); 3484 if (ret != ERROR_SUCCESS && ret != ERROR_INVALID_TABLE) 3485 goto end; 3486 3487 ret = msi_table_load_transform( db, stg, strings, columns, bytes_per_strref, err_cond ); 3488 if (ret != ERROR_SUCCESS && ret != ERROR_INVALID_TABLE) 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 ) 3519 msi_destroy_stringtable( 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 } 3534