msi: Implement the DROP TABLE sql command.
This commit is contained in:
parent
68525652a1
commit
62c544cf4f
|
@ -19,6 +19,7 @@ C_SRCS = \
|
|||
delete.c \
|
||||
dialog.c \
|
||||
distinct.c \
|
||||
drop.c \
|
||||
events.c \
|
||||
files.c \
|
||||
font.c \
|
||||
|
|
|
@ -242,6 +242,7 @@ static const MSIVIEWOPS alter_ops =
|
|||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
};
|
||||
|
||||
UINT ALTER_CreateView( MSIDATABASE *db, MSIVIEW **view, LPCWSTR name, column_info *colinfo, int hold )
|
||||
|
|
|
@ -137,6 +137,7 @@ static const MSIVIEWOPS create_ops =
|
|||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static UINT check_columns( column_info *col_info )
|
||||
|
@ -157,7 +158,7 @@ UINT CREATE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table,
|
|||
{
|
||||
MSICREATEVIEW *cv = NULL;
|
||||
UINT r;
|
||||
const column_info *col;
|
||||
column_info *col;
|
||||
BOOL temp = TRUE;
|
||||
|
||||
TRACE("%p\n", cv );
|
||||
|
@ -171,11 +172,16 @@ UINT CREATE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table,
|
|||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
for( col = col_info; col; col = col->next )
|
||||
{
|
||||
if (!col->table)
|
||||
col->table = strdupW(table);
|
||||
|
||||
if( !col->temporary )
|
||||
{
|
||||
temp = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* fill the structure */
|
||||
cv->view.ops = &create_ops;
|
||||
|
|
|
@ -191,7 +191,8 @@ static const MSIVIEWOPS delete_ops =
|
|||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
NULL,
|
||||
NULL,
|
||||
};
|
||||
|
||||
UINT DELETE_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table )
|
||||
|
|
|
@ -296,6 +296,7 @@ static const MSIVIEWOPS distinct_ops =
|
|||
NULL,
|
||||
NULL,
|
||||
DISTINCT_sort,
|
||||
NULL,
|
||||
};
|
||||
|
||||
UINT DISTINCT_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table )
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
* Implementation of the Microsoft Installer (msi.dll)
|
||||
*
|
||||
* Copyright 2008 James Hawkins
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winerror.h"
|
||||
#include "wine/debug.h"
|
||||
#include "msi.h"
|
||||
#include "msiquery.h"
|
||||
#include "objbase.h"
|
||||
#include "objidl.h"
|
||||
#include "msipriv.h"
|
||||
|
||||
#include "query.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msidb);
|
||||
|
||||
typedef struct tagMSIDROPVIEW
|
||||
{
|
||||
MSIVIEW view;
|
||||
MSIDATABASE *db;
|
||||
MSIVIEW *table;
|
||||
column_info *colinfo;
|
||||
INT hold;
|
||||
} MSIDROPVIEW;
|
||||
|
||||
static UINT DROP_execute(struct tagMSIVIEW *view, MSIRECORD *record)
|
||||
{
|
||||
MSIDROPVIEW *dv = (MSIDROPVIEW*)view;
|
||||
UINT r;
|
||||
|
||||
TRACE("%p %p\n", dv, record);
|
||||
|
||||
if( !dv->table )
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
r = dv->table->ops->execute(dv->table, record);
|
||||
if (r != ERROR_SUCCESS)
|
||||
return r;
|
||||
|
||||
return dv->table->ops->drop(dv->table);
|
||||
}
|
||||
|
||||
static UINT DROP_close(struct tagMSIVIEW *view)
|
||||
{
|
||||
MSIDROPVIEW *dv = (MSIDROPVIEW*)view;
|
||||
|
||||
TRACE("%p\n", dv);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static UINT DROP_get_dimensions(struct tagMSIVIEW *view, UINT *rows, UINT *cols)
|
||||
{
|
||||
MSIDROPVIEW *dv = (MSIDROPVIEW*)view;
|
||||
|
||||
TRACE("%p %p %p\n", dv, rows, cols);
|
||||
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
static const MSIVIEWOPS drop_ops =
|
||||
{
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
DROP_execute,
|
||||
DROP_close,
|
||||
DROP_get_dimensions,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
};
|
||||
|
||||
UINT DROP_CreateView(MSIDATABASE *db, MSIVIEW **view, LPCWSTR name)
|
||||
{
|
||||
MSIDROPVIEW *dv;
|
||||
UINT r;
|
||||
|
||||
TRACE("%p %s\n", view, debugstr_w(name));
|
||||
|
||||
dv = msi_alloc_zero(sizeof *dv);
|
||||
if(!dv)
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
r = TABLE_CreateView(db, name, &dv->table);
|
||||
if (r != ERROR_SUCCESS || !dv->table)
|
||||
return r;
|
||||
|
||||
dv->view.ops = &drop_ops;
|
||||
dv->db = db;
|
||||
|
||||
*view = (MSIVIEW *)dv;
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
|
@ -239,6 +239,7 @@ static const MSIVIEWOPS insert_ops =
|
|||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static UINT count_column_info( const column_info *ci )
|
||||
|
|
|
@ -306,6 +306,7 @@ static const MSIVIEWOPS join_ops =
|
|||
NULL,
|
||||
NULL,
|
||||
JOIN_sort,
|
||||
NULL,
|
||||
};
|
||||
|
||||
UINT JOIN_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR tables )
|
||||
|
|
|
@ -274,6 +274,11 @@ typedef struct tagMSIVIEWOPS
|
|||
* sort - orders the table by columns
|
||||
*/
|
||||
UINT (*sort)( struct tagMSIVIEW *view, column_info *columns );
|
||||
|
||||
/*
|
||||
* drop - drops the table from the database
|
||||
*/
|
||||
UINT (*drop)( struct tagMSIVIEW *view );
|
||||
} MSIVIEWOPS;
|
||||
|
||||
struct tagMSIVIEW
|
||||
|
|
|
@ -117,6 +117,8 @@ UINT STREAMS_CreateView( MSIDATABASE *db, MSIVIEW **view );
|
|||
|
||||
UINT STORAGES_CreateView( MSIDATABASE *db, MSIVIEW **view );
|
||||
|
||||
UINT DROP_CreateView( MSIDATABASE *db, MSIVIEW **view, LPCWSTR name );
|
||||
|
||||
int sqliteGetToken(const WCHAR *z, int *tokenType);
|
||||
|
||||
MSIRECORD *msi_query_merge_record( UINT fields, const column_info *vl, MSIRECORD *rec );
|
||||
|
|
|
@ -363,6 +363,7 @@ static const MSIVIEWOPS select_ops =
|
|||
NULL,
|
||||
NULL,
|
||||
SELECT_sort,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static UINT SELECT_AddColumn( MSISELECTVIEW *sv, LPCWSTR name )
|
||||
|
|
|
@ -81,7 +81,7 @@ static struct expr * EXPR_wildcard( void *info );
|
|||
int integer;
|
||||
}
|
||||
|
||||
%token TK_ALTER TK_AND TK_BY TK_CHAR TK_COMMA TK_CREATE TK_DELETE
|
||||
%token TK_ALTER TK_AND TK_BY TK_CHAR TK_COMMA TK_CREATE TK_DELETE TK_DROP
|
||||
%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
|
||||
|
@ -106,7 +106,7 @@ static struct expr * EXPR_wildcard( void *info );
|
|||
%type <column_list> selcollist column column_and_type column_def table_def
|
||||
%type <column_list> column_assignment update_assign_list constlist
|
||||
%type <query> query from fromtable selectfrom unorderedsel
|
||||
%type <query> oneupdate onedelete oneselect onequery onecreate oneinsert onealter
|
||||
%type <query> oneupdate onedelete oneselect onequery onecreate oneinsert onealter onedrop
|
||||
%type <expr> expr val column_val const_val
|
||||
%type <column_type> column_type data_type data_type_l data_count
|
||||
%type <integer> number alterop
|
||||
|
@ -135,6 +135,7 @@ onequery:
|
|||
| oneupdate
|
||||
| onedelete
|
||||
| onealter
|
||||
| onedrop
|
||||
;
|
||||
|
||||
oneinsert:
|
||||
|
@ -267,6 +268,19 @@ alterop:
|
|||
}
|
||||
;
|
||||
|
||||
onedrop:
|
||||
TK_DROP TK_TABLE table
|
||||
{
|
||||
SQL_input* sql = (SQL_input*) info;
|
||||
UINT r;
|
||||
|
||||
$$ = NULL;
|
||||
r = DROP_CreateView( sql->db, &$$, $3 );
|
||||
if( r != ERROR_SUCCESS || !$$ )
|
||||
YYABORT;
|
||||
}
|
||||
;
|
||||
|
||||
table_def:
|
||||
column_def TK_PRIMARY TK_KEY selcollist
|
||||
{
|
||||
|
|
|
@ -474,6 +474,7 @@ static const MSIVIEWOPS storages_ops =
|
|||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static INT add_storages_to_table(MSISTORAGESVIEW *sv)
|
||||
|
|
|
@ -438,6 +438,7 @@ static const MSIVIEWOPS streams_ops =
|
|||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static INT add_streams_to_table(MSISTREAMSVIEW *sv)
|
||||
|
|
|
@ -109,7 +109,7 @@ static const MSICOLUMNINFO _Columns_cols[4] = {
|
|||
};
|
||||
|
||||
static const MSICOLUMNINFO _Tables_cols[1] = {
|
||||
{ szTables, 1, szName, MSITYPE_VALID | MSITYPE_STRING | 64, 0, 0, NULL },
|
||||
{ szTables, 1, szName, MSITYPE_VALID | MSITYPE_STRING | MSITYPE_KEY | 64, 0, 0, NULL },
|
||||
};
|
||||
|
||||
#define MAX_STREAM_NAME 0x1f
|
||||
|
@ -1073,20 +1073,12 @@ BOOL TABLE_Exists( MSIDATABASE *db, LPCWSTR name )
|
|||
count = table->row_count;
|
||||
for( i=0; i<count; i++ )
|
||||
if( table->data[ i ][ 0 ] == table_id )
|
||||
break;
|
||||
|
||||
if (i!=count)
|
||||
return TRUE;
|
||||
return TRUE;
|
||||
|
||||
count = table->nonpersistent_row_count;
|
||||
for( i=0; i<count; i++ )
|
||||
if( table->nonpersistent_data[ i ][ 0 ] == table_id )
|
||||
break;
|
||||
|
||||
if (i!=count)
|
||||
return TRUE;
|
||||
|
||||
TRACE("Searched %d tables, but %d was not found\n", count, table_id );
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
@ -2058,6 +2050,52 @@ static UINT TABLE_sort(struct tagMSIVIEW *view, column_info *columns)
|
|||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static UINT TABLE_drop(struct tagMSIVIEW *view)
|
||||
{
|
||||
MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
|
||||
MSIVIEW *tables = NULL;
|
||||
MSIRECORD *rec = NULL;
|
||||
UINT i, r, row;
|
||||
|
||||
TRACE("dropping table %s\n", debugstr_w(tv->name));
|
||||
|
||||
for (i = 0; i < tv->table->col_count; i++)
|
||||
{
|
||||
r = TABLE_remove_column(view, tv->table->colinfo[i].tablename,
|
||||
tv->table->colinfo[i].number);
|
||||
if (r != ERROR_SUCCESS)
|
||||
return r;
|
||||
}
|
||||
|
||||
rec = MSI_CreateRecord(1);
|
||||
if (!rec)
|
||||
return ERROR_OUTOFMEMORY;
|
||||
|
||||
MSI_RecordSetStringW(rec, 1, tv->name);
|
||||
|
||||
r = TABLE_CreateView(tv->db, szTables, &tables);
|
||||
if (r != ERROR_SUCCESS)
|
||||
return r;
|
||||
|
||||
r = msi_table_find_row((MSITABLEVIEW *)tables, rec, &row);
|
||||
if (r != ERROR_SUCCESS)
|
||||
goto done;
|
||||
|
||||
r = TABLE_delete_row(tables, row);
|
||||
if (r != ERROR_SUCCESS)
|
||||
goto done;
|
||||
|
||||
list_remove(&tv->table->entry);
|
||||
free_table(tv->table);
|
||||
TABLE_delete(view);
|
||||
|
||||
done:
|
||||
msiobj_release(&rec->hdr);
|
||||
tables->ops->delete(tables);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static const MSIVIEWOPS table_ops =
|
||||
{
|
||||
TABLE_fetch_int,
|
||||
|
@ -2078,6 +2116,7 @@ static const MSIVIEWOPS table_ops =
|
|||
TABLE_add_column,
|
||||
TABLE_remove_column,
|
||||
TABLE_sort,
|
||||
TABLE_drop,
|
||||
};
|
||||
|
||||
UINT TABLE_CreateView( MSIDATABASE *db, LPCWSTR name, MSIVIEW **view )
|
||||
|
|
|
@ -6313,6 +6313,94 @@ static void test_dbtopackage(void)
|
|||
DeleteFileA(msifile);
|
||||
}
|
||||
|
||||
static void test_droptable(void)
|
||||
{
|
||||
MSIHANDLE hdb, hview, hrec;
|
||||
LPCSTR query;
|
||||
UINT r;
|
||||
|
||||
r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
|
||||
ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
|
||||
|
||||
query = "CREATE TABLE `One` ( `A` INT PRIMARY KEY `A` )";
|
||||
r = run_query(hdb, 0, query);
|
||||
ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
|
||||
|
||||
query = "SELECT * FROM `One`";
|
||||
r = do_query(hdb, query, &hrec);
|
||||
ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
|
||||
|
||||
query = "SELECT * FROM `_Tables` WHERE `Name` = 'One'";
|
||||
r = do_query(hdb, query, &hrec);
|
||||
ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
|
||||
|
||||
MsiCloseHandle(hrec);
|
||||
|
||||
query = "SELECT * FROM `_Columns` WHERE `Table` = 'One'";
|
||||
r = do_query(hdb, query, &hrec);
|
||||
ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
|
||||
|
||||
MsiCloseHandle(hrec);
|
||||
|
||||
query = "DROP `One`";
|
||||
r = run_query(hdb, 0, query);
|
||||
ok(r == ERROR_BAD_QUERY_SYNTAX,
|
||||
"Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
|
||||
|
||||
query = "DROP TABLE";
|
||||
r = run_query(hdb, 0, query);
|
||||
ok(r == ERROR_BAD_QUERY_SYNTAX,
|
||||
"Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
|
||||
|
||||
query = "DROP TABLE `One`";
|
||||
hview = 0;
|
||||
r = MsiDatabaseOpenViewA(hdb, query, &hview);
|
||||
ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
|
||||
r = MsiViewExecute(hview, 0);
|
||||
ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
|
||||
|
||||
r = MsiViewFetch(hview, &hrec);
|
||||
ok(r == ERROR_FUNCTION_FAILED,
|
||||
"Expected ERROR_FUNCTION_FAILED, got %d\n", r);
|
||||
|
||||
MsiViewClose(hview);
|
||||
MsiCloseHandle(hview);
|
||||
|
||||
query = "SELECT * FROM `IDontExist`";
|
||||
r = do_query(hdb, query, &hrec);
|
||||
ok(r == ERROR_BAD_QUERY_SYNTAX,
|
||||
"Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
|
||||
|
||||
query = "SELECT * FROM `One`";
|
||||
r = do_query(hdb, query, &hrec);
|
||||
ok(r == ERROR_BAD_QUERY_SYNTAX,
|
||||
"Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
|
||||
|
||||
query = "CREATE TABLE `One` ( `A` INT PRIMARY KEY `A` )";
|
||||
r = run_query(hdb, 0, query);
|
||||
ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
|
||||
|
||||
query = "DROP TABLE One";
|
||||
r = run_query(hdb, 0, query);
|
||||
ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
|
||||
|
||||
query = "SELECT * FROM `One`";
|
||||
r = do_query(hdb, query, &hrec);
|
||||
ok(r == ERROR_BAD_QUERY_SYNTAX,
|
||||
"Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r);
|
||||
|
||||
query = "SELECT * FROM `_Tables` WHERE `Name` = 'One'";
|
||||
r = do_query(hdb, query, &hrec);
|
||||
ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
|
||||
|
||||
query = "SELECT * FROM `_Columns` WHERE `Table` = 'One'";
|
||||
r = do_query(hdb, query, &hrec);
|
||||
ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
|
||||
|
||||
MsiCloseHandle(hdb);
|
||||
DeleteFileA(msifile);
|
||||
}
|
||||
|
||||
START_TEST(db)
|
||||
{
|
||||
test_msidatabase();
|
||||
|
@ -6352,4 +6440,5 @@ START_TEST(db)
|
|||
test_where_viewmodify();
|
||||
test_storages_table();
|
||||
test_dbtopackage();
|
||||
test_droptable();
|
||||
}
|
||||
|
|
|
@ -47,6 +47,7 @@ static const WCHAR CHARACTER_W[] = { 'C','H','A','R','A','C','T','E','R',0 };
|
|||
static const WCHAR CREATE_W[] = { 'C','R','E','A','T','E',0 };
|
||||
static const WCHAR DELETE_W[] = { 'D','E','L','E','T','E',0 };
|
||||
static const WCHAR DISTINCT_W[] = { 'D','I','S','T','I','N','C','T',0 };
|
||||
static const WCHAR DROP_W[] = { 'D','R','O','P',0 };
|
||||
static const WCHAR FREE_W[] = { 'F','R','E','E',0 };
|
||||
static const WCHAR FROM_W[] = { 'F','R','O','M',0 };
|
||||
static const WCHAR HOLD_W[] = { 'H','O','L','D',0 };
|
||||
|
@ -89,6 +90,7 @@ static const Keyword aKeywordTable[] = {
|
|||
{ CREATE_W, TK_CREATE },
|
||||
{ DELETE_W, TK_DELETE },
|
||||
{ DISTINCT_W, TK_DISTINCT },
|
||||
{ DROP_W, TK_DROP },
|
||||
{ FREE_W, TK_FREE },
|
||||
{ FROM_W, TK_FROM },
|
||||
{ HOLD_W, TK_HOLD },
|
||||
|
|
|
@ -222,6 +222,7 @@ static const MSIVIEWOPS update_ops =
|
|||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
};
|
||||
|
||||
UINT UPDATE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPCWSTR table,
|
||||
|
|
|
@ -585,6 +585,7 @@ static const MSIVIEWOPS where_ops =
|
|||
NULL,
|
||||
NULL,
|
||||
WHERE_sort,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static UINT WHERE_VerifyCondition( MSIDATABASE *db, MSIVIEW *table, struct expr *cond,
|
||||
|
|
Loading…
Reference in New Issue