Piotr Caban : msi: Fix adding temporary columns.

Alexandre Julliard julliard at winehq.org
Tue Jun 30 14:55:06 CDT 2020


Module: wine
Branch: master
Commit: 15b47513a1926a103492e0774396119f57d2e8d5
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=15b47513a1926a103492e0774396119f57d2e8d5

Author: Piotr Caban <piotr at codeweavers.com>
Date:   Tue Jun 30 05:40:41 2020 +0200

msi: Fix adding temporary columns.

Signed-off-by: Piotr Caban <piotr at codeweavers.com>
Signed-off-by: Hans Leidekker <hans at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/msi/alter.c    |  82 +---------------------------------------
 dlls/msi/msipriv.h  |   2 +-
 dlls/msi/table.c    | 105 +++++++++++++++++++++++++++++++++++++++++-----------
 dlls/msi/tests/db.c |  10 ++++-
 4 files changed, 95 insertions(+), 104 deletions(-)

diff --git a/dlls/msi/alter.c b/dlls/msi/alter.c
index 7922171ae2..78f1a3930c 100644
--- a/dlls/msi/alter.c
+++ b/dlls/msi/alter.c
@@ -61,85 +61,6 @@ static UINT ALTER_fetch_stream( struct tagMSIVIEW *view, UINT row, UINT col, ISt
     return ERROR_FUNCTION_FAILED;
 }
 
-static UINT ITERATE_columns(MSIRECORD *row, LPVOID param)
-{
-    (*(UINT *)param)++;
-    return ERROR_SUCCESS;
-}
-
-static BOOL check_column_exists(MSIDATABASE *db, LPCWSTR table, LPCWSTR column)
-{
-    MSIQUERY *view;
-    MSIRECORD *rec;
-    UINT r;
-
-    static const WCHAR query[] = {
-        'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
-        '`','_','C','o','l','u','m','n','s','`',' ','W','H','E','R','E',' ',
-        '`','T','a','b','l','e','`','=','\'','%','s','\'',' ','A','N','D',' ',
-        '`','N','a','m','e','`','=','\'','%','s','\'',0
-    };
-
-    r = MSI_OpenQuery(db, &view, query, table, column);
-    if (r != ERROR_SUCCESS)
-        return FALSE;
-
-    r = MSI_ViewExecute(view, NULL);
-    if (r != ERROR_SUCCESS)
-        goto done;
-
-    r = MSI_ViewFetch(view, &rec);
-    if (r == ERROR_SUCCESS)
-        msiobj_release(&rec->hdr);
-
-done:
-    msiobj_release(&view->hdr);
-    return (r == ERROR_SUCCESS);
-}
-
-static UINT alter_add_column(MSIALTERVIEW *av)
-{
-    UINT r, colnum = 1;
-    MSIQUERY *view;
-    MSIVIEW *columns;
-
-    static const WCHAR szColumns[] = {'_','C','o','l','u','m','n','s',0};
-    static const WCHAR query[] = {
-        'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
-        '`','_','C','o','l','u','m','n','s','`',' ','W','H','E','R','E',' ',
-        '`','T','a','b','l','e','`','=','\'','%','s','\'',' ','O','R','D','E','R',' ',
-        'B','Y',' ','`','N','u','m','b','e','r','`',0
-    };
-
-    r = TABLE_CreateView(av->db, szColumns, &columns);
-    if (r != ERROR_SUCCESS)
-        return r;
-
-    if (check_column_exists(av->db, av->colinfo->table, av->colinfo->column))
-    {
-        columns->ops->delete(columns);
-        return ERROR_BAD_QUERY_SYNTAX;
-    }
-
-    r = MSI_OpenQuery(av->db, &view, query, av->colinfo->table, av->colinfo->column);
-    if (r == ERROR_SUCCESS)
-    {
-        r = MSI_IterateRecords(view, NULL, ITERATE_columns, &colnum);
-        msiobj_release(&view->hdr);
-        if (r != ERROR_SUCCESS)
-        {
-            columns->ops->delete(columns);
-            return r;
-        }
-    }
-    r = columns->ops->add_column(columns, av->colinfo->table,
-                                 colnum, av->colinfo->column,
-                                 av->colinfo->type, (av->hold == 1));
-
-    columns->ops->delete(columns);
-    return r;
-}
-
 static UINT ALTER_execute( struct tagMSIVIEW *view, MSIRECORD *record )
 {
     MSIALTERVIEW *av = (MSIALTERVIEW*)view;
@@ -148,7 +69,8 @@ static UINT ALTER_execute( struct tagMSIVIEW *view, MSIRECORD *record )
     TRACE("%p %p\n", av, record);
 
     if (av->colinfo)
-        return alter_add_column(av);
+        return av->table->ops->add_column(av->table, av->colinfo->column,
+                av->colinfo->type, av->colinfo->temporary, av->hold == 1);
 
     if (av->hold == 1)
         av->table->ops->add_ref(av->table);
diff --git a/dlls/msi/msipriv.h b/dlls/msi/msipriv.h
index 71c6565080..6797ebe4bc 100644
--- a/dlls/msi/msipriv.h
+++ b/dlls/msi/msipriv.h
@@ -337,7 +337,7 @@ typedef struct tagMSIVIEWOPS
     /*
      * add_column - adds a column to the table
      */
-    UINT (*add_column)( struct tagMSIVIEW *view, LPCWSTR table, UINT number, LPCWSTR column, UINT type, BOOL hold );
+    UINT (*add_column)( struct tagMSIVIEW *view, LPCWSTR column, INT type, BOOL temporary, BOOL hold );
 
     /*
      * sort - orders the table by columns
diff --git a/dlls/msi/table.c b/dlls/msi/table.c
index c617110604..5a1466592f 100644
--- a/dlls/msi/table.c
+++ b/dlls/msi/table.c
@@ -2040,38 +2040,99 @@ static UINT TABLE_release(struct tagMSIVIEW *view)
     return ref;
 }
 
-static UINT TABLE_add_column(struct tagMSIVIEW *view, LPCWSTR table, UINT number,
-                             LPCWSTR column, UINT type, BOOL hold)
+static UINT TABLE_add_column(struct tagMSIVIEW *view, LPCWSTR column,
+                             INT type, BOOL temporary, BOOL hold)
 {
+    UINT i, r, table_id, col_id, size, offset;
     MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
-    MSITABLE *msitable;
-    MSIRECORD *rec;
-    UINT r;
+    MSICOLUMNINFO *colinfo;
 
-    rec = MSI_CreateRecord(4);
-    if (!rec)
-        return ERROR_OUTOFMEMORY;
+    if (temporary && !hold && !tv->table->ref_count)
+        return ERROR_SUCCESS;
 
-    MSI_RecordSetStringW(rec, 1, table);
-    MSI_RecordSetInteger(rec, 2, number);
-    MSI_RecordSetStringW(rec, 3, column);
-    MSI_RecordSetInteger(rec, 4, type);
+    if (!temporary && tv->table->col_count &&
+            tv->table->colinfo[tv->table->col_count-1].temporary)
+        return ERROR_BAD_QUERY_SYNTAX;
+
+    for (i = 0; i < tv->table->col_count; i++)
+    {
+        if (!wcscmp(tv->table->colinfo[i].colname, column))
+            return ERROR_BAD_QUERY_SYNTAX;
+    }
 
-    r = TABLE_insert_row(&tv->view, rec, -1, FALSE);
+    colinfo = msi_realloc(tv->table->colinfo, sizeof(*tv->table->colinfo) * (tv->table->col_count + 1));
+    if (!colinfo)
+        return ERROR_OUTOFMEMORY;
+    tv->table->colinfo = colinfo;
+
+    r = msi_string2id( tv->db->strings, tv->name, -1, &table_id );
     if (r != ERROR_SUCCESS)
-        goto done;
+        return r;
+    col_id = msi_add_string( tv->db->strings, column, -1, !temporary );
 
-    msi_update_table_columns(tv->db, table);
+    colinfo[tv->table->col_count].tablename = msi_string_lookup( tv->db->strings, table_id, NULL );
+    colinfo[tv->table->col_count].number = tv->table->col_count + 1;
+    colinfo[tv->table->col_count].colname = msi_string_lookup( tv->db->strings, col_id, NULL );
+    colinfo[tv->table->col_count].type = type;
+    colinfo[tv->table->col_count].offset = 0;
+    colinfo[tv->table->col_count].hash_table = NULL;
+    colinfo[tv->table->col_count].temporary = temporary;
+    tv->table->col_count++;
 
-    if (!hold)
-        goto done;
+    table_calc_column_offsets( tv->db, tv->table->colinfo, tv->table->col_count);
 
-    msitable = find_cached_table(tv->db, table);
-    InterlockedIncrement(&msitable->ref_count);
+    size = msi_table_get_row_size( tv->db, tv->table->colinfo, tv->table->col_count, LONG_STR_BYTES );
+    offset = tv->table->colinfo[tv->table->col_count - 1].offset;
+    for (i = 0; i < tv->table->row_count; i++)
+    {
+        BYTE *data = msi_realloc( tv->table->data[i], size );
+        if (!data)
+        {
+            tv->table->col_count--;
+            return ERROR_OUTOFMEMORY;
+        }
 
-done:
-    msiobj_release(&rec->hdr);
-    return r;
+        tv->table->data[i] = data;
+        memset(data + offset, 0, size - offset);
+    }
+
+    if (!temporary)
+    {
+        MSIVIEW *columns;
+        MSIRECORD *rec;
+
+        rec = MSI_CreateRecord(4);
+        if (!rec)
+        {
+            tv->table->col_count--;
+            return ERROR_OUTOFMEMORY;
+        }
+
+        MSI_RecordSetStringW(rec, 1, tv->name);
+        MSI_RecordSetInteger(rec, 2, tv->table->col_count);
+        MSI_RecordSetStringW(rec, 3, column);
+        MSI_RecordSetInteger(rec, 4, type);
+
+        r = TABLE_CreateView(tv->db, szColumns, &columns);
+        if (r != ERROR_SUCCESS)
+        {
+            tv->table->col_count--;
+            msiobj_release(&rec->hdr);
+            return r;
+        }
+
+        r = TABLE_insert_row(columns, rec, -1, FALSE);
+        columns->ops->delete(columns);
+        msiobj_release(&rec->hdr);
+        if (r != ERROR_SUCCESS)
+        {
+            tv->table->col_count--;
+            return r;
+        }
+    }
+    if (hold)
+        TABLE_add_ref(view);
+    return ERROR_SUCCESS;
 }
 
 static UINT TABLE_drop(struct tagMSIVIEW *view)
diff --git a/dlls/msi/tests/db.c b/dlls/msi/tests/db.c
index 22466548b1..3e1c551d38 100644
--- a/dlls/msi/tests/db.c
+++ b/dlls/msi/tests/db.c
@@ -3950,7 +3950,7 @@ static void test_temporary_table(void)
 static void test_alter(void)
 {
     MSICONDITION cond;
-    MSIHANDLE hdb = 0;
+    MSIHANDLE hdb = 0, rec;
     const char *query;
     UINT r;
 
@@ -4020,6 +4020,10 @@ static void test_alter(void)
     r = run_query(hdb, 0, query);
     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
 
+    query = "SELECT * FROM `_Columns` WHERE `Table` = 'U' AND `Name` = 'C'";
+    r = do_query(hdb, query, &rec);
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
+
     /* add column C again */
     query = "ALTER TABLE `U` ADD `C` INTEGER";
     r = run_query(hdb, 0, query);
@@ -4037,6 +4041,10 @@ static void test_alter(void)
     r = run_query(hdb, 0, query);
     ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
 
+    query = "SELECT * FROM `_Columns` WHERE `Table` = 'U' AND `Name` = 'D'";
+    r = do_query(hdb, query, &rec);
+    ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
+
     query = "INSERT INTO `U` ( `A`, `B`, `C`, `D` ) VALUES ( 5, 6, 7, 8 )";
     r = run_query(hdb, 0, query);
     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);




More information about the wine-cvs mailing list