msi 2: Ref count temporary columns and release them when necessary

James Hawkins truiken at gmail.com
Fri Jul 20 20:41:16 CDT 2007


Hi,

I forgot to mention that the previous patch (msi 1) fixes bug 8895.
http://bugs.winehq.org/show_bug.cgi?id=8895

Changelog:
* Ref count temporary columns and release them when necessary.

 dlls/msi/alter.c    |    8 +++--
 dlls/msi/create.c   |    1 +
 dlls/msi/delete.c   |    1 +
 dlls/msi/distinct.c |    1 +
 dlls/msi/insert.c   |    1 +
 dlls/msi/join.c     |    1 +
 dlls/msi/msipriv.h  |    8 ++++-
 dlls/msi/order.c    |    1 +
 dlls/msi/select.c   |    1 +
 dlls/msi/sql.y      |   14 +++++++--
 dlls/msi/streams.c  |    1 +
 dlls/msi/table.c    |   81 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 dlls/msi/tests/db.c |   35 ++++------------------
 dlls/msi/update.c   |    1 +
 dlls/msi/where.c    |    1 +
 15 files changed, 119 insertions(+), 37 deletions(-)

-- 
James Hawkins
-------------- next part --------------
diff --git a/dlls/msi/alter.c b/dlls/msi/alter.c
index 3e8ffbd..734aaba 100644
--- a/dlls/msi/alter.c
+++ b/dlls/msi/alter.c
@@ -127,7 +127,7 @@ static UINT alter_add_column(MSIALTERVIE
 
     r = columns->ops->add_column(columns, av->colinfo->table,
                                  colnum, av->colinfo->column,
-                                 av->colinfo->type);
+                                 av->colinfo->type, (av->hold == 1));
 
     msiobj_release(&columns->hdr);
     return r;
@@ -143,7 +143,8 @@ static UINT ALTER_execute( struct tagMSI
         av->table->ops->add_ref(av->table);
     else if (av->hold == -1)
         av->table->ops->release(av->table);
-    else
+
+    if (av->colinfo)
         return alter_add_column(av);
 
     return ERROR_SUCCESS;
@@ -223,6 +224,7 @@ static const MSIVIEWOPS alter_ops =
     NULL,
     NULL,
     NULL,
+    NULL,
 };
 
 UINT ALTER_CreateView( MSIDATABASE *db, MSIVIEW **view, LPCWSTR name, column_info *colinfo, int hold )
@@ -230,7 +232,7 @@ UINT ALTER_CreateView( MSIDATABASE *db, 
     MSIALTERVIEW *av;
     UINT r;
 
-    TRACE("%p %s %d\n", view, debugstr_w(name), hold );
+    TRACE("%p %p %s %d\n", view, colinfo, debugstr_w(name), hold );
 
     av = msi_alloc_zero( sizeof *av );
     if( !av )
diff --git a/dlls/msi/create.c b/dlls/msi/create.c
index f632ef6..8f33ec3 100644
--- a/dlls/msi/create.c
+++ b/dlls/msi/create.c
@@ -133,6 +133,7 @@ static const MSIVIEWOPS create_ops =
     NULL,
     NULL,
     NULL,
+    NULL,
 };
 
 static UINT check_columns( column_info *col_info )
diff --git a/dlls/msi/delete.c b/dlls/msi/delete.c
index 81d8a45..7e00484 100644
--- a/dlls/msi/delete.c
+++ b/dlls/msi/delete.c
@@ -196,6 +196,7 @@ static const MSIVIEWOPS delete_ops =
     NULL,
     NULL,
     NULL,
+    NULL,
 };
 
 UINT DELETE_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table )
diff --git a/dlls/msi/distinct.c b/dlls/msi/distinct.c
index 9d8b790..0da3c2e 100644
--- a/dlls/msi/distinct.c
+++ b/dlls/msi/distinct.c
@@ -285,6 +285,7 @@ static const MSIVIEWOPS distinct_ops =
     NULL,
     NULL,
     NULL,
+    NULL,
 };
 
 UINT DISTINCT_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table )
diff --git a/dlls/msi/insert.c b/dlls/msi/insert.c
index e7f3ce1..d122624 100644
--- a/dlls/msi/insert.c
+++ b/dlls/msi/insert.c
@@ -236,6 +236,7 @@ static const MSIVIEWOPS insert_ops =
     NULL,
     NULL,
     NULL,
+    NULL,
 };
 
 static UINT count_column_info( const column_info *ci )
diff --git a/dlls/msi/join.c b/dlls/msi/join.c
index 492d0d8..fa31ad3 100644
--- a/dlls/msi/join.c
+++ b/dlls/msi/join.c
@@ -256,6 +256,7 @@ static const MSIVIEWOPS join_ops =
     NULL,
     NULL,
     NULL,
+    NULL,
 };
 
 UINT JOIN_CreateView( MSIDATABASE *db, MSIVIEW **view,
diff --git a/dlls/msi/msipriv.h b/dlls/msi/msipriv.h
index 0dceb75..0036414 100644
--- a/dlls/msi/msipriv.h
+++ b/dlls/msi/msipriv.h
@@ -39,6 +39,7 @@ #define MSITYPE_LOCALIZABLE 0x200
 #define MSITYPE_STRING   0x0800
 #define MSITYPE_NULLABLE 0x1000
 #define MSITYPE_KEY      0x2000
+#define MSITYPE_TEMPORARY 0x4000
 
 /* Word Count masks */
 #define MSIWORDCOUNT_SHORTFILENAMES     0x0001
@@ -235,7 +236,12 @@ 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 );
+    UINT (*add_column)( struct tagMSIVIEW *view, LPCWSTR table, UINT number, LPCWSTR column, UINT type, BOOL hold );
+
+    /*
+     * remove_column - removes the column represented by table name and column number from the table
+     */
+    UINT (*remove_column)( struct tagMSIVIEW *view, LPCWSTR table, UINT number );
 } MSIVIEWOPS;
 
 struct tagMSIVIEW
diff --git a/dlls/msi/order.c b/dlls/msi/order.c
index a2a3984..c745be5 100644
--- a/dlls/msi/order.c
+++ b/dlls/msi/order.c
@@ -285,6 +285,7 @@ static const MSIVIEWOPS order_ops =
     NULL,
     NULL,
     NULL,
+    NULL,
 };
 
 static UINT ORDER_AddColumn( MSIORDERVIEW *ov, LPCWSTR name )
diff --git a/dlls/msi/select.c b/dlls/msi/select.c
index 6eaffaa..0643f50 100644
--- a/dlls/msi/select.c
+++ b/dlls/msi/select.c
@@ -278,6 +278,7 @@ static const MSIVIEWOPS select_ops =
     NULL,
     NULL,
     NULL,
+    NULL,
 };
 
 static UINT SELECT_AddColumn( MSISELECTVIEW *sv, LPCWSTR name )
diff --git a/dlls/msi/sql.y b/dlls/msi/sql.y
index 96801f5..f5e1cf9 100644
--- a/dlls/msi/sql.y
+++ b/dlls/msi/sql.y
@@ -40,8 +40,6 @@ static int sql_error(const char *str);
 
 WINE_DEFAULT_DEBUG_CHANNEL(msi);
 
-#define MSITYPE_TEMPORARY 0x8000
-
 typedef struct tag_SQL_input
 {
     MSIDATABASE *db;
@@ -246,6 +244,16 @@ onealter:
                 YYABORT;
             $$ = alter;
         }
+  | TK_ALTER TK_TABLE table TK_ADD column_and_type TK_HOLD
+        {
+            SQL_input *sql = (SQL_input *)info;
+            MSIVIEW *alter = NULL;
+
+            ALTER_CreateView( sql->db, &alter, $3, $5, 1 );
+            if (!alter)
+                YYABORT;
+            $$ = alter;
+        }
     ;
 
 alterop:
@@ -290,7 +298,7 @@ column_and_type:
     column column_type
         {
             $$ = $1;
-            $$->type = ($2 | MSITYPE_VALID) & ~MSITYPE_TEMPORARY;
+            $$->type = ($2 | MSITYPE_VALID);
             $$->temporary = $2 & MSITYPE_TEMPORARY ? TRUE : FALSE;
         }
     ;
diff --git a/dlls/msi/streams.c b/dlls/msi/streams.c
index f17fb98..229a34f 100644
--- a/dlls/msi/streams.c
+++ b/dlls/msi/streams.c
@@ -340,6 +340,7 @@ static const MSIVIEWOPS streams_ops =
     NULL,
     NULL,
     NULL,
+    NULL,
 };
 
 static UINT add_streams_to_table(MSISTREAMSVIEW *sv)
diff --git a/dlls/msi/table.c b/dlls/msi/table.c
index 1dba764..d442916 100644
--- a/dlls/msi/table.c
+++ b/dlls/msi/table.c
@@ -58,6 +58,7 @@ typedef struct tagMSICOLUMNINFO
     LPCWSTR colname;
     UINT   type;
     UINT   offset;
+    INT    ref_count;
     MSICOLUMNHASHENTRY **hash_table;
 } MSICOLUMNINFO;
 
@@ -660,6 +661,7 @@ UINT msi_create_table( MSIDATABASE *db, 
         table->colinfo[ i ].colname = strdupW( col->column );
         table->colinfo[ i ].type = col->type;
         table->colinfo[ i ].offset = 0;
+        table->colinfo[ i ].ref_count = 0;
         table->colinfo[ i ].hash_table = NULL;
     }
     table_calc_column_offsets( table->colinfo, table->col_count);
@@ -1015,6 +1017,7 @@ static UINT get_tablecolumns( MSIDATABAS
             colinfo[ col - 1 ].colname = msi_makestring( db, id );
             colinfo[ col - 1 ].type = read_table_int(table->data, i, _Columns_cols[3].offset, sizeof(USHORT)) - (1<<15);
             colinfo[ col - 1 ].offset = 0;
+            colinfo[ col - 1 ].ref_count = 0;
             colinfo[ col - 1 ].hash_table = NULL;
         }
         n++;
@@ -1667,19 +1670,77 @@ static UINT TABLE_find_matching_rows( st
 static UINT TABLE_add_ref(struct tagMSIVIEW *view)
 {
     MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
+    int i;
 
     TRACE("%p %d\n", view, tv->table->ref_count);
 
+    for (i = 0; i < tv->table->col_count; i++)
+    {
+        if (tv->table->colinfo[i].type & MSITYPE_TEMPORARY)
+            InterlockedIncrement(&tv->table->colinfo[i].ref_count);
+    }
+
     return InterlockedIncrement(&tv->table->ref_count);
 }
 
+static UINT TABLE_remove_column(struct tagMSIVIEW *view, LPCWSTR table, UINT number)
+{
+    MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
+    MSIRECORD *rec;
+    MSIVIEW *columns = NULL;
+    UINT row, r;
+
+    rec = MSI_CreateRecord(2);
+    if (!rec)
+        return ERROR_OUTOFMEMORY;
+
+    MSI_RecordSetStringW(rec, 1, table);
+    MSI_RecordSetInteger(rec, 2, number);
+
+    r = TABLE_CreateView(tv->db, szColumns, &columns);
+    if (r != ERROR_SUCCESS)
+        return r;
+    
+    r = msi_table_find_row((MSITABLEVIEW *)columns, rec, &row);
+    if (r != ERROR_SUCCESS)
+        goto done;
+
+    r = TABLE_delete_row(columns, row);
+    if (r != ERROR_SUCCESS)
+        goto done;
+
+    msi_update_table_columns(tv->db, table);
+
+done:
+    msiobj_release(&rec->hdr);
+    if (columns) msiobj_release(&columns->hdr);
+    return r;
+}
+
 static UINT TABLE_release(struct tagMSIVIEW *view)
 {
     MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
     INT ref = tv->table->ref_count;
+    int i;
+    UINT r;
 
     TRACE("%p %d\n", view, ref);
 
+    for (i = 0; i < tv->table->col_count; i++)
+    {
+        if (tv->table->colinfo[i].type & MSITYPE_TEMPORARY)
+        {
+            ref = InterlockedDecrement(&tv->table->colinfo[i].ref_count);
+            if (ref == 0)
+            {
+                r = TABLE_remove_column(view, tv->table->colinfo[i].tablename,
+                                        tv->table->colinfo[i].number);
+                if (r != ERROR_SUCCESS)
+                    break;
+            }
+        }
+    }
+
     ref = InterlockedDecrement(&tv->table->ref_count);
     if (ref == 0)
     {
@@ -1694,11 +1755,13 @@ static UINT TABLE_release(struct tagMSIV
     return ref;
 }
 
-static UINT TABLE_add_column(struct tagMSIVIEW *view, LPCWSTR table, UINT number, LPCWSTR column, UINT type)
+static UINT TABLE_add_column(struct tagMSIVIEW *view, LPCWSTR table, UINT number,
+                             LPCWSTR column, UINT type, BOOL hold)
 {
     MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
+    MSITABLE *msitable;
     MSIRECORD *rec;
-    UINT r;
+    UINT r, i;
 
     rec = MSI_CreateRecord(4);
     if (!rec)
@@ -1715,6 +1778,19 @@ static UINT TABLE_add_column(struct tagM
 
     msi_update_table_columns(tv->db, table);
 
+    if (!hold)
+        goto done;
+
+    msitable = find_cached_table(tv->db, table);
+    for (i = 0; i < msitable->col_count; i++)
+    {
+        if (!lstrcmpW(msitable->colinfo[i].colname, column))
+        {
+            InterlockedIncrement(&msitable->colinfo[i].ref_count);
+            break;
+        }
+    }
+
 done:
     msiobj_release(&rec->hdr);
     return r;
@@ -1737,6 +1813,7 @@ static const MSIVIEWOPS table_ops =
     TABLE_add_ref,
     TABLE_release,
     TABLE_add_column,
+    TABLE_remove_column,
 };
 
 UINT TABLE_CreateView( MSIDATABASE *db, LPCWSTR name, MSIVIEW **view )
diff --git a/dlls/msi/tests/db.c b/dlls/msi/tests/db.c
index 317425a..58c3f22 100755
--- a/dlls/msi/tests/db.c
+++ b/dlls/msi/tests/db.c
@@ -3010,25 +3010,16 @@ static void test_alter(void)
     /* column D is removed */
     query = "SELECT * FROM `U` WHERE `D` = 8";
     r = run_query(hdb, 0, query);
-    todo_wine
-    {
-        ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
-    }
+    ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
 
     query = "INSERT INTO `U` ( `A`, `B`, `C`, `D` ) VALUES ( 9, 10, 11, 12 )";
     r = run_query(hdb, 0, query);
-    todo_wine
-    {
-        ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
-    }
+    ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
 
     /* add the column again */
     query = "ALTER TABLE `U` ADD `E` INTEGER TEMPORARY HOLD";
     r = run_query(hdb, 0, query);
-    todo_wine
-    {
-        ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
-    }
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
 
     /* up the ref count */
     query = "ALTER TABLE `U` HOLD";
@@ -3037,17 +3028,11 @@ static void test_alter(void)
 
     query = "INSERT INTO `U` ( `A`, `B`, `C`, `E` ) VALUES ( 13, 14, 15, 16 )";
     r = run_query(hdb, 0, query);
-    todo_wine
-    {
-        ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
-    }
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
 
     query = "SELECT * FROM `U` WHERE `E` = 16";
     r = run_query(hdb, 0, query);
-    todo_wine
-    {
-        ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
-    }
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
 
     /* drop the ref count */
     query = "ALTER TABLE `U` FREE";
@@ -3056,17 +3041,11 @@ static void test_alter(void)
 
     query = "INSERT INTO `U` ( `A`, `B`, `C`, `E` ) VALUES ( 17, 18, 19, 20 )";
     r = run_query(hdb, 0, query);
-    todo_wine
-    {
-        ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
-    }
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
 
     query = "SELECT * FROM `U` WHERE `E` = 20";
     r = run_query(hdb, 0, query);
-    todo_wine
-    {
-        ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
-    }
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
 
     /* drop the ref count */
     query = "ALTER TABLE `U` FREE";
diff --git a/dlls/msi/update.c b/dlls/msi/update.c
index feb12a9..10f7762 100644
--- a/dlls/msi/update.c
+++ b/dlls/msi/update.c
@@ -188,6 +188,7 @@ static const MSIVIEWOPS update_ops =
     NULL,
     NULL,
     NULL,
+    NULL,
 };
 
 UINT UPDATE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPCWSTR table,
diff --git a/dlls/msi/where.c b/dlls/msi/where.c
index fee7a30..fddb0e7 100644
--- a/dlls/msi/where.c
+++ b/dlls/msi/where.c
@@ -450,6 +450,7 @@ static const MSIVIEWOPS where_ops =
     NULL,
     NULL,
     NULL,
+    NULL,
 };
 
 static UINT WHERE_VerifyCondition( MSIDATABASE *db, MSIVIEW *table, struct expr *cond,
-- 
1.4.1


More information about the wine-patches mailing list