msi: Fix adding temporary columns.

Signed-off-by: Piotr Caban <piotr@codeweavers.com>
Signed-off-by: Hans Leidekker <hans@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Piotr Caban 2020-06-30 05:40:41 +02:00 committed by Alexandre Julliard
parent cb9cb83cda
commit 15b47513a1
4 changed files with 95 additions and 104 deletions

View File

@ -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);

View File

@ -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

View File

@ -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)
if (temporary && !hold && !tv->table->ref_count)
return ERROR_SUCCESS;
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;
}
colinfo = msi_realloc(tv->table->colinfo, sizeof(*tv->table->colinfo) * (tv->table->col_count + 1));
if (!colinfo)
return ERROR_OUTOFMEMORY;
tv->table->colinfo = colinfo;
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, -1, FALSE);
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)

View File

@ -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);