msi: Handle adding columns in transforms.
This commit is contained in:
parent
9285351ad3
commit
17ba74195b
159
dlls/msi/table.c
159
dlls/msi/table.c
|
@ -1944,8 +1944,34 @@ static UINT msi_table_find_row( MSITABLEVIEW *tv, MSIRECORD *rec, UINT *row )
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void msi_update_table_columns( MSIDATABASE *db, LPWSTR name )
|
||||||
|
{
|
||||||
|
MSITABLE *table;
|
||||||
|
UINT size, offset;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
table = find_cached_table( db, name );
|
||||||
|
msi_free( table->colinfo );
|
||||||
|
table_get_column_info( db, name, &table->colinfo, &table->col_count );
|
||||||
|
|
||||||
|
size = msi_table_get_row_size( table->colinfo, table->col_count );
|
||||||
|
offset = table->colinfo[table->col_count - 1].offset;
|
||||||
|
|
||||||
|
for ( n = 0; n < table->row_count; n++ )
|
||||||
|
{
|
||||||
|
table->data[n] = msi_realloc( table->data[n], size );
|
||||||
|
table->data[n][offset] = (BYTE)MSI_NULL_INTEGER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
struct list entry;
|
||||||
|
LPWSTR name;
|
||||||
|
} TRANSFORMDATA;
|
||||||
|
|
||||||
static UINT msi_table_load_transform( MSIDATABASE *db, IStorage *stg,
|
static UINT msi_table_load_transform( MSIDATABASE *db, IStorage *stg,
|
||||||
string_table *st, LPCWSTR name,
|
string_table *st, TRANSFORMDATA *transform,
|
||||||
UINT bytes_per_strref )
|
UINT bytes_per_strref )
|
||||||
{
|
{
|
||||||
UINT rawsize = 0;
|
UINT rawsize = 0;
|
||||||
|
@ -1955,6 +1981,7 @@ static UINT msi_table_load_transform( MSIDATABASE *db, IStorage *stg,
|
||||||
MSIRECORD *rec = NULL;
|
MSIRECORD *rec = NULL;
|
||||||
UINT colcol = 0;
|
UINT colcol = 0;
|
||||||
WCHAR coltable[32];
|
WCHAR coltable[32];
|
||||||
|
LPWSTR name = transform->name;
|
||||||
|
|
||||||
coltable[0] = 0;
|
coltable[0] = 0;
|
||||||
TRACE("%p %p %p %s\n", db, stg, st, debugstr_w(name) );
|
TRACE("%p %p %p %s\n", db, stg, st, debugstr_w(name) );
|
||||||
|
@ -2038,34 +2065,41 @@ static UINT msi_table_load_transform( MSIDATABASE *db, IStorage *stg,
|
||||||
{
|
{
|
||||||
if ( mask & 1 )
|
if ( mask & 1 )
|
||||||
{
|
{
|
||||||
|
WCHAR table[32];
|
||||||
|
DWORD sz = 32;
|
||||||
|
UINT number = MSI_NULL_INTEGER;
|
||||||
|
|
||||||
TRACE("inserting record\n");
|
TRACE("inserting record\n");
|
||||||
|
|
||||||
/*
|
|
||||||
* Native msi seems writes nul into the
|
|
||||||
* Number (2nd) column of the _Columns table.
|
|
||||||
* Not sure that it's deliberate...
|
|
||||||
*/
|
|
||||||
if (!lstrcmpW(name, szColumns))
|
if (!lstrcmpW(name, szColumns))
|
||||||
{
|
{
|
||||||
WCHAR table[32];
|
|
||||||
DWORD sz = 32;
|
|
||||||
|
|
||||||
MSI_RecordGetStringW( rec, 1, table, &sz );
|
MSI_RecordGetStringW( rec, 1, table, &sz );
|
||||||
|
number = MSI_RecordGetInteger( rec, 2 );
|
||||||
|
|
||||||
/* reset the column number on a new table */
|
/*
|
||||||
if ( lstrcmpW(coltable, table) )
|
* Native msi seems writes nul into the Number (2nd) column of
|
||||||
|
* the _Columns table, only when the columns are from a new table
|
||||||
|
*/
|
||||||
|
if ( number == MSI_NULL_INTEGER )
|
||||||
{
|
{
|
||||||
colcol = 0;
|
/* reset the column number on a new table */
|
||||||
lstrcpyW( coltable, table );
|
if ( lstrcmpW(coltable, table) )
|
||||||
}
|
{
|
||||||
|
colcol = 0;
|
||||||
|
lstrcpyW( coltable, table );
|
||||||
|
}
|
||||||
|
|
||||||
/* fix nul column numbers */
|
/* fix nul column numbers */
|
||||||
MSI_RecordSetInteger( rec, 2, ++colcol );
|
MSI_RecordSetInteger( rec, 2, ++colcol );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
r = TABLE_insert_row( &tv->view, rec, FALSE );
|
r = TABLE_insert_row( &tv->view, rec, FALSE );
|
||||||
if (r != ERROR_SUCCESS)
|
if (r != ERROR_SUCCESS)
|
||||||
ERR("insert row failed\n");
|
ERR("insert row failed\n");
|
||||||
|
|
||||||
|
if ( number != MSI_NULL_INTEGER && !lstrcmpW(name, szColumns) )
|
||||||
|
msi_update_table_columns( db, table );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -2108,11 +2142,12 @@ err:
|
||||||
*/
|
*/
|
||||||
UINT msi_table_apply_transform( MSIDATABASE *db, IStorage *stg )
|
UINT msi_table_apply_transform( MSIDATABASE *db, IStorage *stg )
|
||||||
{
|
{
|
||||||
|
struct list transforms;
|
||||||
IEnumSTATSTG *stgenum = NULL;
|
IEnumSTATSTG *stgenum = NULL;
|
||||||
|
TRANSFORMDATA *transform;
|
||||||
|
TRANSFORMDATA *tables = NULL, *columns = NULL;
|
||||||
HRESULT r;
|
HRESULT r;
|
||||||
STATSTG stat;
|
STATSTG stat;
|
||||||
ULONG count;
|
|
||||||
WCHAR name[0x40];
|
|
||||||
string_table *strings;
|
string_table *strings;
|
||||||
UINT ret = ERROR_FUNCTION_FAILED;
|
UINT ret = ERROR_FUNCTION_FAILED;
|
||||||
UINT bytes_per_strref;
|
UINT bytes_per_strref;
|
||||||
|
@ -2127,40 +2162,84 @@ UINT msi_table_apply_transform( MSIDATABASE *db, IStorage *stg )
|
||||||
if( FAILED( r ) )
|
if( FAILED( r ) )
|
||||||
goto end;
|
goto end;
|
||||||
|
|
||||||
/*
|
list_init(&transforms);
|
||||||
* Apply _Tables and _Columns transforms first so that
|
|
||||||
* the table metadata is correct, and empty tables exist.
|
|
||||||
*/
|
|
||||||
ret = msi_table_load_transform( db, stg, strings, szTables, bytes_per_strref );
|
|
||||||
if (ret != ERROR_SUCCESS && ret != ERROR_INVALID_TABLE)
|
|
||||||
goto end;
|
|
||||||
|
|
||||||
ret = msi_table_load_transform( db, stg, strings, szColumns, bytes_per_strref );
|
while ( TRUE )
|
||||||
if (ret != ERROR_SUCCESS && ret != ERROR_INVALID_TABLE)
|
|
||||||
goto end;
|
|
||||||
|
|
||||||
ret = ERROR_SUCCESS;
|
|
||||||
|
|
||||||
while( r == ERROR_SUCCESS )
|
|
||||||
{
|
{
|
||||||
count = 0;
|
MSITABLEVIEW *tv = NULL;
|
||||||
|
WCHAR name[0x40];
|
||||||
|
ULONG count = 0;
|
||||||
|
|
||||||
r = IEnumSTATSTG_Next( stgenum, 1, &stat, &count );
|
r = IEnumSTATSTG_Next( stgenum, 1, &stat, &count );
|
||||||
if( FAILED( r ) || !count )
|
if ( FAILED( r ) || !count )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
decode_streamname( stat.pwcsName, name );
|
decode_streamname( stat.pwcsName, name );
|
||||||
if ( name[0] != 0x4840 )
|
if ( name[0] != 0x4840 )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
TRACE("transform contains stream %s\n", debugstr_w(name));
|
|
||||||
|
|
||||||
if ( !lstrcmpW( name+1, szStringPool ) ||
|
if ( !lstrcmpW( name+1, szStringPool ) ||
|
||||||
!lstrcmpW( name+1, szStringData ) ||
|
!lstrcmpW( name+1, szStringData ) )
|
||||||
!lstrcmpW( name+1, szColumns ) ||
|
|
||||||
!lstrcmpW( name+1, szTables ) )
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
ret = msi_table_load_transform( db, stg, strings, name+1, bytes_per_strref );
|
transform = msi_alloc_zero( sizeof(TRANSFORMDATA) );
|
||||||
|
if ( !transform )
|
||||||
|
break;
|
||||||
|
|
||||||
|
list_add_tail( &transforms, &transform->entry );
|
||||||
|
|
||||||
|
transform->name = strdupW( name + 1 );
|
||||||
|
|
||||||
|
if ( !lstrcmpW( transform->name, szTables ) )
|
||||||
|
tables = transform;
|
||||||
|
else if (!lstrcmpW( transform->name, szColumns ) )
|
||||||
|
columns = transform;
|
||||||
|
|
||||||
|
TRACE("transform contains stream %s\n", debugstr_w(name));
|
||||||
|
|
||||||
|
/* load the table */
|
||||||
|
r = TABLE_CreateView( db, transform->name, (MSIVIEW**) &tv );
|
||||||
|
if( r != ERROR_SUCCESS )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
r = tv->view.ops->execute( &tv->view, NULL );
|
||||||
|
if( r != ERROR_SUCCESS )
|
||||||
|
{
|
||||||
|
tv->view.ops->delete( &tv->view );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
tv->view.ops->delete( &tv->view );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Apply _Tables and _Columns transforms first so that
|
||||||
|
* the table metadata is correct, and empty tables exist.
|
||||||
|
*/
|
||||||
|
ret = msi_table_load_transform( db, stg, strings, tables, bytes_per_strref );
|
||||||
|
if (ret != ERROR_SUCCESS && ret != ERROR_INVALID_TABLE)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
ret = msi_table_load_transform( db, stg, strings, columns, bytes_per_strref );
|
||||||
|
if (ret != ERROR_SUCCESS && ret != ERROR_INVALID_TABLE)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
while ( !list_empty( &transforms ) )
|
||||||
|
{
|
||||||
|
transform = LIST_ENTRY( list_head( &transforms ), TRANSFORMDATA, entry );
|
||||||
|
|
||||||
|
if ( lstrcmpW( transform->name, szColumns ) &&
|
||||||
|
lstrcmpW( transform->name, szTables ) &&
|
||||||
|
ret == ERROR_SUCCESS )
|
||||||
|
{
|
||||||
|
ret = msi_table_load_transform( db, stg, strings, transform, bytes_per_strref );
|
||||||
|
}
|
||||||
|
|
||||||
|
list_remove( &transform->entry );
|
||||||
|
msi_free( transform->name );
|
||||||
|
msi_free( transform );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ret == ERROR_SUCCESS )
|
if ( ret == ERROR_SUCCESS )
|
||||||
|
|
|
@ -2049,30 +2049,21 @@ static void test_try_transform(void)
|
||||||
hrec = 0;
|
hrec = 0;
|
||||||
query = "select `NOO`,`OOO` from `MOO` where `NOO` = 1 AND `OOO` = 'c'";
|
query = "select `NOO`,`OOO` from `MOO` where `NOO` = 1 AND `OOO` = 'c'";
|
||||||
r = do_query(hdb, query, &hrec);
|
r = do_query(hdb, query, &hrec);
|
||||||
todo_wine
|
ok(r == ERROR_SUCCESS, "select query failed\n");
|
||||||
{
|
|
||||||
ok(r == ERROR_SUCCESS, "select query failed\n");
|
|
||||||
}
|
|
||||||
MsiCloseHandle(hrec);
|
MsiCloseHandle(hrec);
|
||||||
|
|
||||||
/* check unchanged value */
|
/* check unchanged value */
|
||||||
hrec = 0;
|
hrec = 0;
|
||||||
query = "select `NOO`,`OOO` from `MOO` where `NOO` = 2 AND `OOO` = 'b'";
|
query = "select `NOO`,`OOO` from `MOO` where `NOO` = 2 AND `OOO` = 'b'";
|
||||||
r = do_query(hdb, query, &hrec);
|
r = do_query(hdb, query, &hrec);
|
||||||
todo_wine
|
ok(r == ERROR_SUCCESS, "select query failed\n");
|
||||||
{
|
|
||||||
ok(r == ERROR_SUCCESS, "select query failed\n");
|
|
||||||
}
|
|
||||||
MsiCloseHandle(hrec);
|
MsiCloseHandle(hrec);
|
||||||
|
|
||||||
/* check deleted value */
|
/* check deleted value */
|
||||||
hrec = 0;
|
hrec = 0;
|
||||||
query = "select * from `MOO` where `NOO` = 3";
|
query = "select * from `MOO` where `NOO` = 3";
|
||||||
r = do_query(hdb, query, &hrec);
|
r = do_query(hdb, query, &hrec);
|
||||||
todo_wine
|
ok(r == ERROR_NO_MORE_ITEMS, "select query failed\n");
|
||||||
{
|
|
||||||
ok(r == ERROR_NO_MORE_ITEMS, "select query failed\n");
|
|
||||||
}
|
|
||||||
if (hrec) MsiCloseHandle(hrec);
|
if (hrec) MsiCloseHandle(hrec);
|
||||||
|
|
||||||
/* check added stream */
|
/* check added stream */
|
||||||
|
@ -2093,67 +2084,40 @@ static void test_try_transform(void)
|
||||||
hrec = 0;
|
hrec = 0;
|
||||||
query = "select * from `MOO`";
|
query = "select * from `MOO`";
|
||||||
r = MsiDatabaseOpenView(hdb, query, &hview);
|
r = MsiDatabaseOpenView(hdb, query, &hview);
|
||||||
todo_wine
|
ok(r == ERROR_SUCCESS, "open view failed\n");
|
||||||
{
|
|
||||||
ok(r == ERROR_SUCCESS, "open view failed\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
r = MsiViewExecute(hview, 0);
|
r = MsiViewExecute(hview, 0);
|
||||||
todo_wine
|
ok(r == ERROR_SUCCESS, "view execute failed\n");
|
||||||
{
|
|
||||||
ok(r == ERROR_SUCCESS, "view execute failed\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
r = MsiViewFetch(hview, &hrec);
|
r = MsiViewFetch(hview, &hrec);
|
||||||
todo_wine
|
ok(r == ERROR_SUCCESS, "view fetch failed\n");
|
||||||
{
|
|
||||||
ok(r == ERROR_SUCCESS, "view fetch failed\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
r = MsiRecordGetInteger(hrec, 1);
|
r = MsiRecordGetInteger(hrec, 1);
|
||||||
todo_wine
|
ok(r == 1, "Expected 1, got %d\n", r);
|
||||||
{
|
|
||||||
ok(r == 1, "Expected 1, got %d\n", r);
|
|
||||||
}
|
|
||||||
|
|
||||||
sz = sizeof buffer;
|
sz = sizeof buffer;
|
||||||
r = MsiRecordGetString(hrec, 2, buffer, &sz);
|
r = MsiRecordGetString(hrec, 2, buffer, &sz);
|
||||||
todo_wine
|
ok(r == ERROR_SUCCESS, "record get string failed\n");
|
||||||
{
|
ok(!lstrcmpA(buffer, "c"), "Expected c, got %s\n", buffer);
|
||||||
ok(r == ERROR_SUCCESS, "record get string failed\n");
|
|
||||||
ok(!lstrcmpA(buffer, "c"), "Expected c, got %s\n", buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
r = MsiRecordGetInteger(hrec, 3);
|
r = MsiRecordGetInteger(hrec, 3);
|
||||||
ok(r == 0x80000000, "Expected 0x80000000, got %d\n", r);
|
ok(r == 0x80000000, "Expected 0x80000000, got %d\n", r);
|
||||||
|
|
||||||
r = MsiRecordGetInteger(hrec, 4);
|
r = MsiRecordGetInteger(hrec, 4);
|
||||||
todo_wine
|
ok(r == 5, "Expected 5, got %d\n", r);
|
||||||
{
|
|
||||||
ok(r == 5, "Expected 5, got %d\n", r);
|
|
||||||
}
|
|
||||||
|
|
||||||
MsiCloseHandle(hrec);
|
MsiCloseHandle(hrec);
|
||||||
|
|
||||||
r = MsiViewFetch(hview, &hrec);
|
r = MsiViewFetch(hview, &hrec);
|
||||||
todo_wine
|
ok(r == ERROR_SUCCESS, "view fetch failed\n");
|
||||||
{
|
|
||||||
ok(r == ERROR_SUCCESS, "view fetch failed\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
r = MsiRecordGetInteger(hrec, 1);
|
r = MsiRecordGetInteger(hrec, 1);
|
||||||
todo_wine
|
ok(r == 2, "Expected 2, got %d\n", r);
|
||||||
{
|
|
||||||
ok(r == 2, "Expected 2, got %d\n", r);
|
|
||||||
}
|
|
||||||
|
|
||||||
sz = sizeof buffer;
|
sz = sizeof buffer;
|
||||||
r = MsiRecordGetString(hrec, 2, buffer, &sz);
|
r = MsiRecordGetString(hrec, 2, buffer, &sz);
|
||||||
todo_wine
|
ok(r == ERROR_SUCCESS, "record get string failed\n");
|
||||||
{
|
ok(!lstrcmpA(buffer, "b"), "Expected b, got %s\n", buffer);
|
||||||
ok(r == ERROR_SUCCESS, "record get string failed\n");
|
|
||||||
ok(!lstrcmpA(buffer, "b"), "Expected b, got %s\n", buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
r = MsiRecordGetInteger(hrec, 3);
|
r = MsiRecordGetInteger(hrec, 3);
|
||||||
ok(r == 0x80000000, "Expected 0x80000000, got %d\n", r);
|
ok(r == 0x80000000, "Expected 0x80000000, got %d\n", r);
|
||||||
|
@ -2164,10 +2128,7 @@ static void test_try_transform(void)
|
||||||
MsiCloseHandle(hrec);
|
MsiCloseHandle(hrec);
|
||||||
|
|
||||||
r = MsiViewFetch(hview, &hrec);
|
r = MsiViewFetch(hview, &hrec);
|
||||||
todo_wine
|
ok(r == ERROR_NO_MORE_ITEMS, "view fetch succeeded\n");
|
||||||
{
|
|
||||||
ok(r == ERROR_NO_MORE_ITEMS, "view fetch succeeded\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
MsiCloseHandle(hrec);
|
MsiCloseHandle(hrec);
|
||||||
MsiCloseHandle(hview);
|
MsiCloseHandle(hview);
|
||||||
|
|
Loading…
Reference in New Issue