msi [4/4]: Handle adding columns in transforms

James Hawkins truiken at gmail.com
Mon Jul 9 21:34:41 CDT 2007


Hi,

Changelog:
* Handle adding columns in transforms.

 dlls/msi/table.c    |  153 +++++++++++++++++++++++++++++++++++++++------------
 dlls/msi/tests/db.c |   69 +++++------------------
 2 files changed, 131 insertions(+), 91 deletions(-)

-- 
James Hawkins
-------------- next part --------------
diff --git a/dlls/msi/table.c b/dlls/msi/table.c
index 3541c2d..06652fe 100644
--- a/dlls/msi/table.c
+++ b/dlls/msi/table.c
@@ -1944,8 +1944,34 @@ static UINT msi_table_find_row( MSITABLE
     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,
-                                      string_table *st, LPCWSTR name,
+                                      string_table *st, TRANSFORMDATA *transform,
                                       UINT bytes_per_strref )
 {
     UINT rawsize = 0;
@@ -1955,6 +1981,7 @@ static UINT msi_table_load_transform( MS
     MSIRECORD *rec = NULL;
     UINT colcol = 0;
     WCHAR coltable[32];
+    LPWSTR name = transform->name;
 
     coltable[0] = 0;
     TRACE("%p %p %p %s\n", db, stg, st, debugstr_w(name) );
@@ -2038,34 +2065,41 @@ static UINT msi_table_load_transform( MS
         {
             if ( mask & 1 )
             {
+                WCHAR table[32];
+                DWORD sz = 32;
+                UINT number = MSI_NULL_INTEGER;
+
                 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))
                 {
-                    WCHAR table[32];
-                    DWORD sz = 32;
-
                     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;
-                        lstrcpyW( coltable, table );
+                        /* reset the column number on a new table */
+                        if ( lstrcmpW(coltable, table) )
+                        {
+                            colcol = 0;
+                            lstrcpyW( coltable, table );
+                        }
+    
+                        /* fix nul column numbers */
+                        MSI_RecordSetInteger( rec, 2, ++colcol );
                     }
-
-                    /* fix nul column numbers */
-                    MSI_RecordSetInteger( rec, 2, ++colcol );
                 }
 
                 r = TABLE_insert_row( &tv->view, rec, FALSE );
                 if (r != ERROR_SUCCESS)
                     ERR("insert row failed\n");
+
+                if ( number != MSI_NULL_INTEGER && !lstrcmpW(name, szColumns) )
+                    msi_update_table_columns( db, table );
             }
             else
             {
@@ -2108,11 +2142,12 @@ err:
  */
 UINT msi_table_apply_transform( MSIDATABASE *db, IStorage *stg )
 {
+    struct list transforms;
     IEnumSTATSTG *stgenum = NULL;
+    TRANSFORMDATA *transform;
+    TRANSFORMDATA *tables = NULL, *columns = NULL;
     HRESULT r;
     STATSTG stat;
-    ULONG count;
-    WCHAR name[0x40];
     string_table *strings;
     UINT ret = ERROR_FUNCTION_FAILED;
     UINT bytes_per_strref;
@@ -2127,40 +2162,84 @@ UINT msi_table_apply_transform( MSIDATAB
     if( FAILED( r ) )
         goto end;
 
+    list_init(&transforms);
+
+    while ( TRUE )
+    {
+        MSITABLEVIEW *tv = NULL;
+        WCHAR name[0x40];
+        ULONG count = 0;
+
+        r = IEnumSTATSTG_Next( stgenum, 1, &stat, &count );
+        if ( FAILED( r ) || !count )
+            break;
+
+        decode_streamname( stat.pwcsName, name );
+        if ( name[0] != 0x4840 )
+            continue;
+
+        if ( !lstrcmpW( name+1, szStringPool ) ||
+             !lstrcmpW( name+1, szStringData ) )
+            continue;
+
+        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, szTables, bytes_per_strref );
+    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, szColumns, bytes_per_strref );
+    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( r == ERROR_SUCCESS )
+    while ( !list_empty( &transforms ) )
     {
-        count = 0;
-        r = IEnumSTATSTG_Next( stgenum, 1, &stat, &count );
-        if( FAILED( r ) || !count )
-            break;
-
-        decode_streamname( stat.pwcsName, name );
-        if ( name[0] != 0x4840 )
-            continue;
-
-        TRACE("transform contains stream %s\n", debugstr_w(name));
+        transform = LIST_ENTRY( list_head( &transforms ), TRANSFORMDATA, entry );
 
-        if ( !lstrcmpW( name+1, szStringPool ) ||
-             !lstrcmpW( name+1, szStringData ) ||
-             !lstrcmpW( name+1, szColumns ) ||
-             !lstrcmpW( name+1, szTables ) )
-            continue;
+        if ( lstrcmpW( transform->name, szColumns ) &&
+             lstrcmpW( transform->name, szTables ) &&
+             ret == ERROR_SUCCESS )
+        {
+            ret = msi_table_load_transform( db, stg, strings, transform, bytes_per_strref );
+        }
 
-        ret = msi_table_load_transform( db, stg, strings, name+1, bytes_per_strref );
+        list_remove( &transform->entry );
+        msi_free( transform->name );
+        msi_free( transform );
     }
 
     if ( ret == ERROR_SUCCESS )
diff --git a/dlls/msi/tests/db.c b/dlls/msi/tests/db.c
index 2ce58ae..a6fe5e3 100644
--- a/dlls/msi/tests/db.c
+++ b/dlls/msi/tests/db.c
@@ -2049,30 +2049,21 @@ static void test_try_transform(void)
     hrec = 0;
     query = "select `NOO`,`OOO` from `MOO` where `NOO` = 1 AND `OOO` = 'c'";
     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);
 
     /* check unchanged value */
     hrec = 0;
     query = "select `NOO`,`OOO` from `MOO` where `NOO` = 2 AND `OOO` = 'b'";
     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);
 
     /* check deleted value */
     hrec = 0;
     query = "select * from `MOO` where `NOO` = 3";
     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);
 
     /* check added stream */
@@ -2093,67 +2084,40 @@ static void test_try_transform(void)
     hrec = 0;
     query = "select * from `MOO`";
     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);
-    todo_wine
-    {
-        ok(r == ERROR_SUCCESS, "view execute failed\n");
-    }
+    ok(r == ERROR_SUCCESS, "view execute failed\n");
 
     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);
-    todo_wine
-    {
-        ok(r == 1, "Expected 1, got %d\n", r);
-    }
+    ok(r == 1, "Expected 1, got %d\n", r);
 
     sz = sizeof buffer;
     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);
     ok(r == 0x80000000, "Expected 0x80000000, got %d\n", r);
 
     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);
 
     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);
-    todo_wine
-    {
-        ok(r == 2, "Expected 2, got %d\n", r);
-    }
+    ok(r == 2, "Expected 2, got %d\n", r);
 
     sz = sizeof buffer;
     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);
     ok(r == 0x80000000, "Expected 0x80000000, got %d\n", r);
@@ -2164,10 +2128,7 @@ static void test_try_transform(void)
     MsiCloseHandle(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(hview);
-- 
1.4.1


More information about the wine-patches mailing list