msi: Implement adding columns using the ALTER command.
This commit is contained in:
parent
52cc727348
commit
0fd733bf90
|
@ -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 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, 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 tagMSIVIEW *view, MSIRECORD *record )
|
|||
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, MSIVIEW **view, LPCWSTR name, int hold )
|
|||
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;
|
||||
|
||||
|
|
|
@ -132,6 +132,7 @@ static const MSIVIEWOPS create_ops =
|
|||
CREATE_delete,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static UINT check_columns( column_info *col_info )
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -255,6 +255,7 @@ static const MSIVIEWOPS join_ops =
|
|||
JOIN_find_matching_rows,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
};
|
||||
|
||||
UINT JOIN_CreateView( MSIDATABASE *db, MSIVIEW **view,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -284,6 +284,7 @@ static const MSIVIEWOPS order_ops =
|
|||
ORDER_find_matching_rows,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static UINT ORDER_AddColumn( MSIORDERVIEW *ov, LPCWSTR name )
|
||||
|
|
|
@ -122,7 +122,7 @@ UINT DELETE_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table );
|
|||
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 );
|
||||
|
||||
|
|
|
@ -277,6 +277,7 @@ static const MSIVIEWOPS select_ops =
|
|||
SELECT_find_matching_rows,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static UINT SELECT_AddColumn( MSISELECTVIEW *sv, LPCWSTR name )
|
||||
|
|
|
@ -83,7 +83,7 @@ static struct expr * EXPR_wildcard( void *info );
|
|||
}
|
||||
|
||||
%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:
|
||||
|
|
|
@ -339,6 +339,7 @@ static const MSIVIEWOPS streams_ops =
|
|||
STREAMS_find_matching_rows,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static UINT add_streams_to_table(MSISTREAMSVIEW *sv)
|
||||
|
|
|
@ -97,8 +97,8 @@ static const WCHAR szType[] = { 'T','y','p','e',0 };
|
|||
* 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( MSIDATABASE *db,
|
|||
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 tagMSIVIEW *view)
|
|||
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( MSITABLEVIEW *tv, MSIRECORD *rec, UINT *row )
|
|||
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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
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";
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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','E','R','E',0 };
|
|||
** These are the keywords
|
||||
*/
|
||||
static const Keyword aKeywordTable[] = {
|
||||
{ ADD_W, TK_ADD },
|
||||
{ ALTER_W, TK_ALTER },
|
||||
{ AND_W, TK_AND },
|
||||
{ BY_W, TK_BY },
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue