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