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