diff --git a/dlls/msi/alter.c b/dlls/msi/alter.c index 3e8ffbd245e9..734aaba400da 100644 --- a/dlls/msi/alter.c +++ b/dlls/msi/alter.c @@ -127,7 +127,7 @@ static UINT alter_add_column(MSIALTERVIEW *av) r = columns->ops->add_column(columns, av->colinfo->table, colnum, av->colinfo->column, - av->colinfo->type); + av->colinfo->type, (av->hold == 1)); msiobj_release(&columns->hdr); return r; @@ -143,7 +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 + + if (av->colinfo) return alter_add_column(av); return ERROR_SUCCESS; @@ -223,6 +224,7 @@ static const MSIVIEWOPS alter_ops = NULL, NULL, NULL, + NULL, }; UINT ALTER_CreateView( MSIDATABASE *db, MSIVIEW **view, LPCWSTR name, column_info *colinfo, int hold ) @@ -230,7 +232,7 @@ UINT ALTER_CreateView( MSIDATABASE *db, MSIVIEW **view, LPCWSTR name, column_inf MSIALTERVIEW *av; UINT r; - TRACE("%p %s %d\n", view, debugstr_w(name), hold ); + TRACE("%p %p %s %d\n", view, colinfo, debugstr_w(name), hold ); av = msi_alloc_zero( sizeof *av ); if( !av ) diff --git a/dlls/msi/create.c b/dlls/msi/create.c index f632ef63d912..8f33ec3845f2 100644 --- a/dlls/msi/create.c +++ b/dlls/msi/create.c @@ -133,6 +133,7 @@ static const MSIVIEWOPS create_ops = NULL, NULL, NULL, + NULL, }; static UINT check_columns( column_info *col_info ) diff --git a/dlls/msi/delete.c b/dlls/msi/delete.c index 81d8a450c744..7e004847f3d3 100644 --- a/dlls/msi/delete.c +++ b/dlls/msi/delete.c @@ -196,6 +196,7 @@ static const MSIVIEWOPS delete_ops = NULL, 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 9d8b79041b95..0da3c2e2767c 100644 --- a/dlls/msi/distinct.c +++ b/dlls/msi/distinct.c @@ -285,6 +285,7 @@ static const MSIVIEWOPS distinct_ops = NULL, 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 e7f3ce198798..d122624b8b43 100644 --- a/dlls/msi/insert.c +++ b/dlls/msi/insert.c @@ -236,6 +236,7 @@ static const MSIVIEWOPS insert_ops = NULL, 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 492d0d887ffa..fa31ad3f8ea8 100644 --- a/dlls/msi/join.c +++ b/dlls/msi/join.c @@ -256,6 +256,7 @@ static const MSIVIEWOPS join_ops = NULL, NULL, NULL, + NULL, }; UINT JOIN_CreateView( MSIDATABASE *db, MSIVIEW **view, diff --git a/dlls/msi/msipriv.h b/dlls/msi/msipriv.h index 0dceb753f75e..0036414cbff1 100644 --- a/dlls/msi/msipriv.h +++ b/dlls/msi/msipriv.h @@ -39,6 +39,7 @@ #define MSITYPE_STRING 0x0800 #define MSITYPE_NULLABLE 0x1000 #define MSITYPE_KEY 0x2000 +#define MSITYPE_TEMPORARY 0x4000 /* Word Count masks */ #define MSIWORDCOUNT_SHORTFILENAMES 0x0001 @@ -235,7 +236,12 @@ 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 ); + UINT (*add_column)( struct tagMSIVIEW *view, LPCWSTR table, UINT number, LPCWSTR column, UINT type, BOOL hold ); + + /* + * remove_column - removes the column represented by table name and column number from the table + */ + UINT (*remove_column)( struct tagMSIVIEW *view, LPCWSTR table, UINT number ); } MSIVIEWOPS; struct tagMSIVIEW diff --git a/dlls/msi/order.c b/dlls/msi/order.c index a2a3984d31fa..c745be5cc818 100644 --- a/dlls/msi/order.c +++ b/dlls/msi/order.c @@ -285,6 +285,7 @@ static const MSIVIEWOPS order_ops = NULL, NULL, NULL, + NULL, }; static UINT ORDER_AddColumn( MSIORDERVIEW *ov, LPCWSTR name ) diff --git a/dlls/msi/select.c b/dlls/msi/select.c index 6eaffaa31a90..0643f5008281 100644 --- a/dlls/msi/select.c +++ b/dlls/msi/select.c @@ -278,6 +278,7 @@ static const MSIVIEWOPS select_ops = NULL, NULL, NULL, + NULL, }; static UINT SELECT_AddColumn( MSISELECTVIEW *sv, LPCWSTR name ) diff --git a/dlls/msi/sql.y b/dlls/msi/sql.y index 96801f5d67d5..f5e1cf936eb0 100644 --- a/dlls/msi/sql.y +++ b/dlls/msi/sql.y @@ -40,8 +40,6 @@ static int sql_error(const char *str); WINE_DEFAULT_DEBUG_CHANNEL(msi); -#define MSITYPE_TEMPORARY 0x8000 - typedef struct tag_SQL_input { MSIDATABASE *db; @@ -246,6 +244,16 @@ onealter: YYABORT; $$ = alter; } + | TK_ALTER TK_TABLE table TK_ADD column_and_type TK_HOLD + { + SQL_input *sql = (SQL_input *)info; + MSIVIEW *alter = NULL; + + ALTER_CreateView( sql->db, &alter, $3, $5, 1 ); + if (!alter) + YYABORT; + $$ = alter; + } ; alterop: @@ -290,7 +298,7 @@ column_and_type: column column_type { $$ = $1; - $$->type = ($2 | MSITYPE_VALID) & ~MSITYPE_TEMPORARY; + $$->type = ($2 | MSITYPE_VALID); $$->temporary = $2 & MSITYPE_TEMPORARY ? TRUE : FALSE; } ; diff --git a/dlls/msi/streams.c b/dlls/msi/streams.c index f17fb98044f5..229a34f235b1 100644 --- a/dlls/msi/streams.c +++ b/dlls/msi/streams.c @@ -340,6 +340,7 @@ static const MSIVIEWOPS streams_ops = NULL, NULL, NULL, + NULL, }; static UINT add_streams_to_table(MSISTREAMSVIEW *sv) diff --git a/dlls/msi/table.c b/dlls/msi/table.c index 1dba764b4aa0..b65494aa575b 100644 --- a/dlls/msi/table.c +++ b/dlls/msi/table.c @@ -58,6 +58,7 @@ typedef struct tagMSICOLUMNINFO LPCWSTR colname; UINT type; UINT offset; + INT ref_count; MSICOLUMNHASHENTRY **hash_table; } MSICOLUMNINFO; @@ -660,6 +661,7 @@ UINT msi_create_table( MSIDATABASE *db, LPCWSTR name, column_info *col_info, table->colinfo[ i ].colname = strdupW( col->column ); table->colinfo[ i ].type = col->type; table->colinfo[ i ].offset = 0; + table->colinfo[ i ].ref_count = 0; table->colinfo[ i ].hash_table = NULL; } table_calc_column_offsets( table->colinfo, table->col_count); @@ -1015,6 +1017,7 @@ static UINT get_tablecolumns( MSIDATABASE *db, colinfo[ col - 1 ].colname = msi_makestring( db, id ); colinfo[ col - 1 ].type = read_table_int(table->data, i, _Columns_cols[3].offset, sizeof(USHORT)) - (1<<15); colinfo[ col - 1 ].offset = 0; + colinfo[ col - 1 ].ref_count = 0; colinfo[ col - 1 ].hash_table = NULL; } n++; @@ -1667,19 +1670,77 @@ static UINT TABLE_find_matching_rows( struct tagMSIVIEW *view, UINT col, static UINT TABLE_add_ref(struct tagMSIVIEW *view) { MSITABLEVIEW *tv = (MSITABLEVIEW*)view; + int i; TRACE("%p %d\n", view, tv->table->ref_count); + for (i = 0; i < tv->table->col_count; i++) + { + if (tv->table->colinfo[i].type & MSITYPE_TEMPORARY) + InterlockedIncrement(&tv->table->colinfo[i].ref_count); + } + return InterlockedIncrement(&tv->table->ref_count); } +static UINT TABLE_remove_column(struct tagMSIVIEW *view, LPCWSTR table, UINT number) +{ + MSITABLEVIEW *tv = (MSITABLEVIEW*)view; + MSIRECORD *rec; + MSIVIEW *columns = NULL; + UINT row, r; + + rec = MSI_CreateRecord(2); + if (!rec) + return ERROR_OUTOFMEMORY; + + MSI_RecordSetStringW(rec, 1, table); + MSI_RecordSetInteger(rec, 2, number); + + r = TABLE_CreateView(tv->db, szColumns, &columns); + if (r != ERROR_SUCCESS) + return r; + + r = msi_table_find_row((MSITABLEVIEW *)columns, rec, &row); + if (r != ERROR_SUCCESS) + goto done; + + r = TABLE_delete_row(columns, row); + if (r != ERROR_SUCCESS) + goto done; + + msi_update_table_columns(tv->db, table); + +done: + msiobj_release(&rec->hdr); + if (columns) msiobj_release(&columns->hdr); + return r; +} + static UINT TABLE_release(struct tagMSIVIEW *view) { MSITABLEVIEW *tv = (MSITABLEVIEW*)view; INT ref = tv->table->ref_count; + int i; + UINT r; TRACE("%p %d\n", view, ref); + for (i = 0; i < tv->table->col_count; i++) + { + if (tv->table->colinfo[i].type & MSITYPE_TEMPORARY) + { + ref = InterlockedDecrement(&tv->table->colinfo[i].ref_count); + if (ref == 0) + { + r = TABLE_remove_column(view, tv->table->colinfo[i].tablename, + tv->table->colinfo[i].number); + if (r != ERROR_SUCCESS) + break; + } + } + } + ref = InterlockedDecrement(&tv->table->ref_count); if (ref == 0) { @@ -1694,11 +1755,13 @@ 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) +static UINT TABLE_add_column(struct tagMSIVIEW *view, LPCWSTR table, UINT number, + LPCWSTR column, UINT type, BOOL hold) { MSITABLEVIEW *tv = (MSITABLEVIEW*)view; + MSITABLE *msitable; MSIRECORD *rec; - UINT r; + UINT r, i; rec = MSI_CreateRecord(4); if (!rec) @@ -1715,6 +1778,19 @@ static UINT TABLE_add_column(struct tagMSIVIEW *view, LPCWSTR table, UINT number msi_update_table_columns(tv->db, table); + if (!hold) + goto done; + + msitable = find_cached_table(tv->db, table); + for (i = 0; i < msitable->col_count; i++) + { + if (!lstrcmpW(msitable->colinfo[i].colname, column)) + { + InterlockedIncrement(&msitable->colinfo[i].ref_count); + break; + } + } + done: msiobj_release(&rec->hdr); return r; @@ -1737,6 +1813,7 @@ static const MSIVIEWOPS table_ops = TABLE_add_ref, TABLE_release, TABLE_add_column, + TABLE_remove_column, }; UINT TABLE_CreateView( MSIDATABASE *db, LPCWSTR name, MSIVIEW **view ) diff --git a/dlls/msi/tests/db.c b/dlls/msi/tests/db.c index 317425aaae84..58c3f221ef68 100644 --- a/dlls/msi/tests/db.c +++ b/dlls/msi/tests/db.c @@ -3010,25 +3010,16 @@ 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); - } + 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); - } + 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"; 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); /* up the ref count */ query = "ALTER TABLE `U` HOLD"; @@ -3037,17 +3028,11 @@ static void test_alter(void) query = "INSERT INTO `U` ( `A`, `B`, `C`, `E` ) VALUES ( 13, 14, 15, 16 )"; 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 `E` = 16"; 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); /* drop the ref count */ query = "ALTER TABLE `U` FREE"; @@ -3056,17 +3041,11 @@ static void test_alter(void) query = "INSERT INTO `U` ( `A`, `B`, `C`, `E` ) VALUES ( 17, 18, 19, 20 )"; 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 `E` = 20"; 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); /* drop the ref count */ query = "ALTER TABLE `U` FREE"; diff --git a/dlls/msi/update.c b/dlls/msi/update.c index feb12a997c59..10f7762a61cc 100644 --- a/dlls/msi/update.c +++ b/dlls/msi/update.c @@ -188,6 +188,7 @@ static const MSIVIEWOPS update_ops = NULL, 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 fee7a303c6ac..fddb0e7a2269 100644 --- a/dlls/msi/where.c +++ b/dlls/msi/where.c @@ -450,6 +450,7 @@ static const MSIVIEWOPS where_ops = NULL, NULL, NULL, + NULL, }; static UINT WHERE_VerifyCondition( MSIDATABASE *db, MSIVIEW *table, struct expr *cond,