msi 1: Implement adding columns using the ALTER command

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


Hi,

Changelog:
* Implement adding columns using the ALTER command.

 dlls/msi/alter.c         |   82 +++++++++++++++++++++++++++++++++++++++++++++-
 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       |    5 +++
 dlls/msi/order.c         |    1 +
 dlls/msi/query.h         |    2 +
 dlls/msi/select.c        |    1 +
 dlls/msi/sql.y           |   14 +++++++-
 dlls/msi/streams.c       |    1 +
 dlls/msi/table.c         |   71 +++++++++++++++++++++++++++-------------
 dlls/msi/tests/db.c      |   35 +++++++-------------
 dlls/msi/tests/package.c |    2 +
 dlls/msi/tokenize.c      |    2 +
 dlls/msi/update.c        |    1 +
 dlls/msi/where.c         |    1 +
 18 files changed, 174 insertions(+), 49 deletions(-)

-- 
James Hawkins
-------------- next part --------------
diff --git a/dlls/msi/alter.c b/dlls/msi/alter.c
index 2815f11..3e8ffbd 100644
--- a/dlls/msi/alter.c
+++ b/dlls/msi/alter.c
@@ -39,6 +39,7 @@ typedef struct tagMSIALTERVIEW
     MSIVIEW        view;
     MSIDATABASE   *db;
     MSIVIEW       *table;
+    column_info   *colinfo;
     INT hold;
 } MSIALTERVIEW;
 
@@ -60,6 +61,78 @@ static UINT ALTER_fetch_stream( struct t
     return ERROR_FUNCTION_FAILED;
 }
 
+static UINT ITERATE_columns(MSIRECORD *row, LPVOID param)
+{
+    (*(UINT *)param)++;
+    return ERROR_SUCCESS;
+}
+
+static BOOL check_column_exists(MSIDATABASE *db, MSIVIEW *columns, 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, columns, av->colinfo->table, av->colinfo->column))
+        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);
+    }
+
+    r = columns->ops->add_column(columns, av->colinfo->table,
+                                 colnum, av->colinfo->column,
+                                 av->colinfo->type);
+
+    msiobj_release(&columns->hdr);
+    return r;
+}
+
 static UINT ALTER_execute( struct tagMSIVIEW *view, MSIRECORD *record )
 {
     MSIALTERVIEW *av = (MSIALTERVIEW*)view;
@@ -70,6 +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
+        return alter_add_column(av);
 
     return ERROR_SUCCESS;
 }
@@ -147,9 +222,10 @@ static const MSIVIEWOPS alter_ops =
     ALTER_find_matching_rows,
     NULL,
     NULL,
+    NULL,
 };
 
-UINT ALTER_CreateView( MSIDATABASE *db, MSIVIEW **view, LPCWSTR name, int hold )
+UINT ALTER_CreateView( MSIDATABASE *db, MSIVIEW **view, LPCWSTR name, column_info *colinfo, int hold )
 {
     MSIALTERVIEW *av;
     UINT r;
@@ -164,10 +240,14 @@ UINT ALTER_CreateView( MSIDATABASE *db, 
     if (r != ERROR_SUCCESS || !av->table)
         return r;
 
+    if (colinfo)
+        colinfo->table = name;
+
     /* fill the structure */
     av->view.ops = &alter_ops;
     av->db = db;
     av->hold = hold;
+    av->colinfo = colinfo;
 
     *view = &av->view;
 
diff --git a/dlls/msi/create.c b/dlls/msi/create.c
index 65a066f..f632ef6 100644
--- a/dlls/msi/create.c
+++ b/dlls/msi/create.c
@@ -132,6 +132,7 @@ static const MSIVIEWOPS create_ops =
     CREATE_delete,
     NULL,
     NULL,
+    NULL,
 };
 
 static UINT check_columns( column_info *col_info )
diff --git a/dlls/msi/delete.c b/dlls/msi/delete.c
index 8d668c4..81d8a45 100644
--- a/dlls/msi/delete.c
+++ b/dlls/msi/delete.c
@@ -195,6 +195,7 @@ static const MSIVIEWOPS delete_ops =
     DELETE_find_matching_rows,
     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 6d737d9..9d8b790 100644
--- a/dlls/msi/distinct.c
+++ b/dlls/msi/distinct.c
@@ -284,6 +284,7 @@ static const MSIVIEWOPS distinct_ops =
     DISTINCT_find_matching_rows,
     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 207f153..e7f3ce1 100644
--- a/dlls/msi/insert.c
+++ b/dlls/msi/insert.c
@@ -235,6 +235,7 @@ static const MSIVIEWOPS insert_ops =
     INSERT_find_matching_rows,
     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 7ff2b91..492d0d8 100644
--- a/dlls/msi/join.c
+++ b/dlls/msi/join.c
@@ -255,6 +255,7 @@ static const MSIVIEWOPS join_ops =
     JOIN_find_matching_rows,
     NULL,
     NULL,
+    NULL,
 };
 
 UINT JOIN_CreateView( MSIDATABASE *db, MSIVIEW **view,
diff --git a/dlls/msi/msipriv.h b/dlls/msi/msipriv.h
index 39719d5..0dceb75 100644
--- a/dlls/msi/msipriv.h
+++ b/dlls/msi/msipriv.h
@@ -231,6 +231,11 @@ typedef struct tagMSIVIEWOPS
      * release - decreases the reference count of the table
      */
     UINT (*release)( struct tagMSIVIEW *view );
+
+    /*
+     * add_column - adds a column to the table
+     */
+    UINT (*add_column)( struct tagMSIVIEW *view, LPCWSTR table, UINT number, LPCWSTR column, UINT type );
 } MSIVIEWOPS;
 
 struct tagMSIVIEW
diff --git a/dlls/msi/order.c b/dlls/msi/order.c
index feb9a31..a2a3984 100644
--- a/dlls/msi/order.c
+++ b/dlls/msi/order.c
@@ -284,6 +284,7 @@ static const MSIVIEWOPS order_ops =
     ORDER_find_matching_rows,
     NULL,
     NULL,
+    NULL,
 };
 
 static UINT ORDER_AddColumn( MSIORDERVIEW *ov, LPCWSTR name )
diff --git a/dlls/msi/query.h b/dlls/msi/query.h
index ef2e8a6..268989d 100644
--- a/dlls/msi/query.h
+++ b/dlls/msi/query.h
@@ -122,7 +122,7 @@ UINT DELETE_CreateView( MSIDATABASE *db,
 UINT JOIN_CreateView( MSIDATABASE *db, MSIVIEW **view,
                       LPCWSTR left, LPCWSTR right );
 
-UINT ALTER_CreateView( MSIDATABASE *db, MSIVIEW **view, LPCWSTR name, int hold );
+UINT ALTER_CreateView( MSIDATABASE *db, MSIVIEW **view, LPCWSTR name, column_info *colinfo, int hold );
 
 UINT STREAMS_CreateView( MSIDATABASE *db, MSIVIEW **view );
 
diff --git a/dlls/msi/select.c b/dlls/msi/select.c
index fc2f7be..6eaffaa 100644
--- a/dlls/msi/select.c
+++ b/dlls/msi/select.c
@@ -277,6 +277,7 @@ static const MSIVIEWOPS select_ops =
     SELECT_find_matching_rows,
     NULL,
     NULL,
+    NULL,
 };
 
 static UINT SELECT_AddColumn( MSISELECTVIEW *sv, LPCWSTR name )
diff --git a/dlls/msi/sql.y b/dlls/msi/sql.y
index 902b08b..96801f5 100644
--- a/dlls/msi/sql.y
+++ b/dlls/msi/sql.y
@@ -83,7 +83,7 @@ static struct expr * EXPR_wildcard( void
 }
 
 %token TK_ALTER TK_AND TK_BY TK_CHAR TK_COMMA TK_CREATE TK_DELETE
-%token TK_DISTINCT TK_DOT TK_EQ TK_FREE TK_FROM TK_GE TK_GT TK_HOLD
+%token TK_DISTINCT TK_DOT TK_EQ TK_FREE TK_FROM TK_GE TK_GT TK_HOLD TK_ADD
 %token <str> TK_ID
 %token TK_ILLEGAL TK_INSERT TK_INT
 %token <str> TK_INTEGER
@@ -231,11 +231,21 @@ onealter:
             SQL_input* sql = (SQL_input*) info;
             MSIVIEW *alter = NULL;
 
-            ALTER_CreateView( sql->db, &alter, $3, $4 );
+            ALTER_CreateView( sql->db, &alter, $3, NULL, $4 );
             if( !alter )
                 YYABORT;
             $$ = alter;
         }
+  | TK_ALTER TK_TABLE table TK_ADD column_and_type
+        {
+            SQL_input *sql = (SQL_input *)info;
+            MSIVIEW *alter = NULL;
+
+            ALTER_CreateView( sql->db, &alter, $3, $5, 0 );
+            if (!alter)
+                YYABORT;
+            $$ = alter;
+        }
     ;
 
 alterop:
diff --git a/dlls/msi/streams.c b/dlls/msi/streams.c
index 6828277..f17fb98 100644
--- a/dlls/msi/streams.c
+++ b/dlls/msi/streams.c
@@ -339,6 +339,7 @@ static const MSIVIEWOPS streams_ops =
     STREAMS_find_matching_rows,
     NULL,
     NULL,
+    NULL,
 };
 
 static UINT add_streams_to_table(MSISTREAMSVIEW *sv)
diff --git a/dlls/msi/table.c b/dlls/msi/table.c
index 33d6aa5..1dba764 100644
--- a/dlls/msi/table.c
+++ b/dlls/msi/table.c
@@ -97,8 +97,8 @@ static const WCHAR szType[]    = { 'T','
  * Do not mark them const.
  */
 static MSICOLUMNINFO _Columns_cols[4] = {
-    { szColumns, 1, szTable,  MSITYPE_VALID | MSITYPE_STRING | 64, 0 },
-    { szColumns, 2, szNumber, MSITYPE_VALID | 2,                   2 },
+    { szColumns, 1, szTable,  MSITYPE_VALID | MSITYPE_STRING | MSITYPE_KEY | 64, 0 },
+    { szColumns, 2, szNumber, MSITYPE_VALID | MSITYPE_KEY | 2,     2 },
     { szColumns, 3, szName,   MSITYPE_VALID | MSITYPE_STRING | 64, 4 },
     { szColumns, 4, szType,   MSITYPE_VALID | 2,                   6 },
 };
@@ -1035,6 +1035,26 @@ static UINT get_tablecolumns( MSIDATABAS
     return ERROR_SUCCESS;
 }
 
+static void msi_update_table_columns( MSIDATABASE *db, LPCWSTR 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;
+    }
+}
+
 /* try to find the table name in the _Tables table */
 BOOL TABLE_Exists( MSIDATABASE *db, LPCWSTR name )
 {
@@ -1674,6 +1694,32 @@ static UINT TABLE_release(struct tagMSIV
     return ref;
 }
 
+static UINT TABLE_add_column(struct tagMSIVIEW *view, LPCWSTR table, UINT number, LPCWSTR column, UINT type)
+{
+    MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
+    MSIRECORD *rec;
+    UINT r;
+
+    rec = MSI_CreateRecord(4);
+    if (!rec)
+        return ERROR_OUTOFMEMORY;
+
+    MSI_RecordSetStringW(rec, 1, table);
+    MSI_RecordSetInteger(rec, 2, number);
+    MSI_RecordSetStringW(rec, 3, column);
+    MSI_RecordSetInteger(rec, 4, type);
+
+    r = TABLE_insert_row(&tv->view, rec, FALSE);
+    if (r != ERROR_SUCCESS)
+        goto done;
+
+    msi_update_table_columns(tv->db, table);
+
+done:
+    msiobj_release(&rec->hdr);
+    return r;
+}
+
 static const MSIVIEWOPS table_ops =
 {
     TABLE_fetch_int,
@@ -1690,6 +1736,7 @@ static const MSIVIEWOPS table_ops =
     TABLE_find_matching_rows,
     TABLE_add_ref,
     TABLE_release,
+    TABLE_add_column,
 };
 
 UINT TABLE_CreateView( MSIDATABASE *db, LPCWSTR name, MSIVIEW **view )
@@ -1977,26 +2024,6 @@ 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;
diff --git a/dlls/msi/tests/db.c b/dlls/msi/tests/db.c
old mode 100644
new mode 100755
index 4b54e8a..317425a
--- a/dlls/msi/tests/db.c
+++ b/dlls/msi/tests/db.c
@@ -2962,10 +2962,7 @@ static void test_alter(void)
 
     query = "ALTER TABLE `U` ADD `C` INTEGER";
     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);
 
     /* add column C again */
     query = "ALTER TABLE `U` ADD `C` INTEGER";
@@ -2974,17 +2971,11 @@ static void test_alter(void)
 
     query = "ALTER TABLE `U` ADD `D` INTEGER TEMPORARY";
     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 = "INSERT INTO `U` ( `A`, `B`, `C`, `D` ) VALUES ( 1, 2, 3, 4 )";
     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 = "ALTER TABLE `U` ADD `D` INTEGER TEMPORARY HOLD";
     r = run_query(hdb, 0, query);
@@ -2992,17 +2983,11 @@ static void test_alter(void)
 
     query = "INSERT INTO `U` ( `A`, `B`, `C`, `D` ) VALUES ( 5, 6, 7, 8 )";
     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 `D` = 8";
     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 = "ALTER TABLE `U` ADD `D` INTEGER TEMPORARY FREE";
     r = run_query(hdb, 0, query);
@@ -3025,11 +3010,17 @@ static void test_alter(void)
     /* column D is removed */
     query = "SELECT * FROM `U` WHERE `D` = 8";
     r = run_query(hdb, 0, query);
-    ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
+    todo_wine
+    {
+        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);
-    ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
+    todo_wine
+    {
+        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";
diff --git a/dlls/msi/tests/package.c b/dlls/msi/tests/package.c
index e30a0db..78bf3b6 100644
--- a/dlls/msi/tests/package.c
+++ b/dlls/msi/tests/package.c
@@ -1701,7 +1701,7 @@ static void test_property_table(void)
 
     query = "ALTER TABLE `_Property` ADD `extra` INTEGER";
     r = run_query(hdb, query);
-    todo_wine ok(r == ERROR_SUCCESS, "failed to add column\n");
+    ok(r == ERROR_SUCCESS, "failed to add column\n");
 
     hpkg = package_from_db(hdb);
     todo_wine
diff --git a/dlls/msi/tokenize.c b/dlls/msi/tokenize.c
index 14bcaf2..d05d244 100644
--- a/dlls/msi/tokenize.c
+++ b/dlls/msi/tokenize.c
@@ -38,6 +38,7 @@ struct Keyword {
 
 #define MAX_TOKEN_LEN 11
 
+static const WCHAR ADD_W[] = { 'A','D','D',0 };
 static const WCHAR ALTER_W[] = { 'A','L','T','E','R',0 };
 static const WCHAR AND_W[] = { 'A','N','D',0 };
 static const WCHAR BY_W[] = { 'B','Y',0 };
@@ -78,6 +79,7 @@ static const WCHAR WHERE_W[] = { 'W','H'
 ** These are the keywords
 */
 static const Keyword aKeywordTable[] = {
+  { ADD_W, TK_ADD },
   { ALTER_W, TK_ALTER },
   { AND_W, TK_AND },
   { BY_W, TK_BY },
diff --git a/dlls/msi/update.c b/dlls/msi/update.c
index 037c282..feb12a9 100644
--- a/dlls/msi/update.c
+++ b/dlls/msi/update.c
@@ -187,6 +187,7 @@ static const MSIVIEWOPS update_ops =
     UPDATE_find_matching_rows,
     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 5b5d867..fee7a30 100644
--- a/dlls/msi/where.c
+++ b/dlls/msi/where.c
@@ -449,6 +449,7 @@ static const MSIVIEWOPS where_ops =
     WHERE_find_matching_rows,
     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