Extend the parser to deal with the CREATE TABLE query. The query

doesn't do anything as yet.
This commit is contained in:
Mike McCormack 2004-03-16 19:18:22 +00:00 committed by Alexandre Julliard
parent 821f4775a3
commit 14ec526004
7 changed files with 392 additions and 18 deletions

View file

@ -7,6 +7,7 @@ IMPORTS = ole32 user32 advapi32 kernel32
EXTRALIBS = -luuid $(LIBUNICODE)
C_SRCS = \
create.c \
distinct.c \
handle.c \
msi.c \

169
dlls/msi/create.c Normal file
View file

@ -0,0 +1,169 @@
/*
* Implementation of the Microsoft Installer (msi.dll)
*
* Copyright 2002 Mike McCormack for CodeWeavers
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 "winnls.h"
#include "query.h"
WINE_DEFAULT_DEBUG_CHANNEL(msi);
/* below is the query interface to a table */
typedef struct tagMSICREATEVIEW
{
MSIVIEW view;
MSIDATABASE *db;
LPWSTR name;
BOOL bIsTemp;
create_col_info *col_info;
} MSICREATEVIEW;
static UINT CREATE_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val )
{
MSICREATEVIEW *cv = (MSICREATEVIEW*)view;
TRACE("%p %d %d %p\n", cv, row, col, val );
return ERROR_FUNCTION_FAILED;
}
static UINT CREATE_execute( struct tagMSIVIEW *view, MSIHANDLE record )
{
MSICREATEVIEW *cv = (MSICREATEVIEW*)view;
create_col_info *c;
FIXME("%p %ld\n", cv, record);
FIXME("Table %s (%s)\n", debugstr_w(cv->name),
cv->bIsTemp?"temporary":"permanent");
for( c = cv->col_info; c; c = c->next )
{
FIXME("Column %s type %04x\n", debugstr_w(c->colname), c->type );
}
return ERROR_SUCCESS;
return ERROR_FUNCTION_FAILED;
}
static UINT CREATE_close( struct tagMSIVIEW *view )
{
MSICREATEVIEW *cv = (MSICREATEVIEW*)view;
FIXME("%p\n", cv );
return ERROR_SUCCESS;
return ERROR_FUNCTION_FAILED;
}
static UINT CREATE_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols )
{
MSICREATEVIEW *cv = (MSICREATEVIEW*)view;
TRACE("%p %p %p\n", cv, rows, cols );
return ERROR_FUNCTION_FAILED;
}
static UINT CREATE_get_column_info( struct tagMSIVIEW *view,
UINT n, LPWSTR *name, UINT *type )
{
MSICREATEVIEW *cv = (MSICREATEVIEW*)view;
TRACE("%p %d %p %p\n", cv, n, name, type );
return ERROR_FUNCTION_FAILED;
}
static UINT CREATE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, MSIHANDLE hrec)
{
MSICREATEVIEW *cv = (MSICREATEVIEW*)view;
TRACE("%p %d %ld\n", cv, eModifyMode, hrec );
return ERROR_FUNCTION_FAILED;
}
static UINT CREATE_delete( struct tagMSIVIEW *view )
{
MSICREATEVIEW *cv = (MSICREATEVIEW*)view;
create_col_info *col;
TRACE("%p\n", cv );
col = cv->col_info;
while( col )
{
create_col_info *t = col;
col = col->next;
HeapFree( GetProcessHeap(), 0, t->colname );
HeapFree( GetProcessHeap(), 0, t );
}
HeapFree( GetProcessHeap(), 0, cv->name );
HeapFree( GetProcessHeap(), 0, cv );
return ERROR_SUCCESS;
}
MSIVIEWOPS create_ops =
{
CREATE_fetch_int,
CREATE_execute,
CREATE_close,
CREATE_get_dimensions,
CREATE_get_column_info,
CREATE_modify,
CREATE_delete
};
UINT CREATE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table,
create_col_info *col_info, BOOL temp )
{
MSICREATEVIEW *cv = NULL;
TRACE("%p\n", cv );
cv = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof *cv );
if( !cv )
return ERROR_FUNCTION_FAILED;
/* fill the structure */
cv->view.ops = &create_ops;
cv->db = db;
cv->name = table; /* FIXME: strdupW it? */
cv->col_info = col_info;
cv->bIsTemp = temp;
*view = (MSIVIEW*) cv;
return ERROR_SUCCESS;
}

View file

@ -36,6 +36,14 @@
WINE_DEFAULT_DEBUG_CHANNEL(msi);
/*
* The MSVC headers define the MSIDBOPEN_* macros cast to LPCTSTR,
* which is a problem because LPCTSTR isn't defined when compiling wine.
* To work around this problem, we need to define LPCTSTR as LPCWSTR here,
* and make sure to only use it in W functions.
*/
#define LPCTSTR LPCWSTR
const WCHAR szInstaller[] = {
'S','o','f','t','w','a','r','e','\\',
'M','i','c','r','o','s','o','f','t','\\',
@ -179,13 +187,42 @@ UINT WINAPI MsiOpenDatabaseW(
MSIHANDLE handle;
MSIDATABASE *db;
UINT ret;
LPWSTR szMode;
TRACE("%s %s %p\n",debugstr_w(szDBPath),debugstr_w(szPersist), phDB);
if( !phDB )
return ERROR_INVALID_PARAMETER;
r = StgOpenStorage( szDBPath, NULL, STGM_DIRECT|STGM_READ|STGM_SHARE_DENY_WRITE, NULL, 0, &stg);
szMode = (LPWSTR) szPersist;
if( HIWORD( szPersist ) )
{
/* UINT len = lstrlenW( szPerist ) + 1; */
FIXME("don't support persist files yet\b");
return ERROR_INVALID_PARAMETER;
/* szMode = HeapAlloc( GetProcessHeap(), 0, len * sizeof (DWORD) ); */
}
else if( szPersist == MSIDBOPEN_READONLY )
{
r = StgOpenStorage( szDBPath, NULL,
STGM_DIRECT|STGM_READ|STGM_SHARE_DENY_WRITE, NULL, 0, &stg);
}
else if( szPersist == MSIDBOPEN_CREATE )
{
r = StgCreateDocfile( szDBPath,
STGM_DIRECT|STGM_READWRITE|STGM_SHARE_EXCLUSIVE, 0, &stg);
}
else if( szPersist == MSIDBOPEN_TRANSACT )
{
r = StgOpenStorage( szDBPath, NULL,
STGM_DIRECT|STGM_READWRITE|STGM_SHARE_EXCLUSIVE, NULL, 0, &stg);
}
else
{
ERR("unknown flag %p\n",szPersist);
return ERROR_INVALID_PARAMETER;
}
if( FAILED( r ) )
{
FIXME("open failed r = %08lx!\n",r);
@ -208,6 +245,7 @@ UINT WINAPI MsiOpenDatabaseW(
goto end;
}
db->storage = stg;
db->mode = szMode;
ret = load_string_table( db, &db->strings);
if( ret != ERROR_SUCCESS )
goto end;

View file

@ -60,6 +60,7 @@ typedef struct tagMSIDATABASE
{
IStorage *storage;
string_table strings;
LPWSTR mode;
MSITABLE *first_table, *last_table;
} MSIDATABASE;

View file

@ -70,6 +70,12 @@ struct expr
} u;
};
typedef struct _create_col_info
{
LPWSTR colname;
UINT type;
struct _create_col_info *next;
} create_col_info;
UINT MSI_ParseSQL( MSIDATABASE *db, LPCWSTR command, MSIVIEW **phView);
@ -86,6 +92,9 @@ UINT ORDER_AddColumn( MSIVIEW *group, LPWSTR name );
UINT WHERE_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table );
UINT WHERE_AddCondition( MSIVIEW *view, struct expr *condition );
UINT CREATE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table,
create_col_info *col_info, BOOL temp );
int sqliteGetToken(const WCHAR *z, int *tokenType);
#endif /* __WINE_MSI_QUERY_H */

View file

@ -63,6 +63,9 @@ static MSIVIEW *do_one_select( MSIDATABASE *db, MSIVIEW *in,
static MSIVIEW *do_order_by( MSIDATABASE *db, MSIVIEW *in,
struct string_list *columns );
static BOOL SQL_MarkPrimaryKeys( create_col_info *cols,
struct string_list *keys);
static struct expr * EXPR_complex( struct expr *l, UINT op, struct expr *r );
static struct expr * EXPR_column( LPWSTR column );
static struct expr * EXPR_ival( INT ival );
@ -76,34 +79,36 @@ static struct expr * EXPR_sval( LPWSTR string );
{
LPWSTR string;
struct string_list *column_list;
MSIVIEW *table;
MSIVIEW *query;
struct expr *expr;
USHORT column_type;
create_col_info *column_info;
}
%token TK_ABORT TK_AFTER TK_AGG_FUNCTION TK_ALL TK_AND TK_AS TK_ASC
%token TK_BEFORE TK_BEGIN TK_BETWEEN TK_BITAND TK_BITNOT TK_BITOR TK_BY
%token TK_CASCADE TK_CASE TK_CHECK TK_CLUSTER TK_COLLATE TK_COLUMN TK_COMMA
%token TK_COMMENT TK_COMMIT TK_CONCAT TK_CONFLICT
%token TK_CASCADE TK_CASE TK_CHAR TK_CHECK TK_CLUSTER TK_COLLATE TK_COLUMN
%token TK_COMMA TK_COMMENT TK_COMMIT TK_CONCAT TK_CONFLICT
%token TK_CONSTRAINT TK_COPY TK_CREATE
%token TK_DEFAULT TK_DEFERRABLE TK_DEFERRED TK_DELETE TK_DELIMITERS TK_DESC
%token TK_DISTINCT TK_DOT TK_DROP TK_EACH
%token TK_ELSE TK_END TK_END_OF_FILE TK_EQ TK_EXCEPT TK_EXPLAIN
%token TK_FAIL TK_FLOAT TK_FOR TK_FOREIGN TK_FROM TK_FUNCTION
%token TK_GE TK_GLOB TK_GROUP TK_GT
%token TK_HAVING
%token TK_HAVING TK_HOLD
%token TK_IGNORE TK_ILLEGAL TK_IMMEDIATE TK_IN TK_INDEX TK_INITIALLY
%token <string> TK_ID
%token TK_INSERT TK_INSTEAD TK_INTEGER TK_INTERSECT TK_INTO TK_IS TK_ISNULL
%token TK_INSERT TK_INSTEAD TK_INT TK_INTEGER TK_INTERSECT TK_INTO TK_IS TK_ISNULL
%token TK_JOIN TK_JOIN_KW
%token TK_KEY
%token TK_LE TK_LIKE TK_LIMIT TK_LP TK_LSHIFT TK_LT
%token TK_LE TK_LIKE TK_LIMIT TK_LONG TK_LONGCHAR TK_LP TK_LSHIFT TK_LT
%token TK_MATCH TK_MINUS
%token TK_NE TK_NOT TK_NOTNULL TK_NULL
%token TK_OF TK_OFFSET TK_ON TK_OR TK_ORACLE_OUTER_JOIN TK_ORDER
%token TK_OBJECT TK_OF TK_OFFSET TK_ON TK_OR TK_ORACLE_OUTER_JOIN TK_ORDER
%token TK_PLUS TK_PRAGMA TK_PRIMARY
%token TK_RAISE TK_REFERENCES TK_REM TK_REPLACE TK_RESTRICT TK_ROLLBACK
%token TK_ROW TK_RP TK_RSHIFT
%token TK_SELECT TK_SEMI TK_SET TK_SLASH TK_SPACE TK_STAR TK_STATEMENT
%token TK_SELECT TK_SEMI TK_SET TK_SHORT TK_SLASH TK_SPACE TK_STAR TK_STATEMENT
%token <string> TK_STRING
%token TK_TABLE TK_TEMP TK_THEN TK_TRANSACTION TK_TRIGGER
%token TK_UMINUS TK_UNCLOSED_STRING TK_UNION TK_UNIQUE
@ -120,14 +125,139 @@ static struct expr * EXPR_sval( LPWSTR string );
%nonassoc END_OF_FILE ILLEGAL SPACE UNCLOSED_STRING COMMENT FUNCTION
COLUMN AGG_FUNCTION.
%type <query> oneselect
%type <string> column table string_or_id
%type <column_list> selcollist
%type <table> from unorderedsel
%type <query> from unorderedsel oneselect onequery onecreate
%type <expr> expr val column_val
%type <column_type> column_type data_type data_count
%type <column_info> column_def table_def
%%
onequery:
oneselect
{
SQL_input* sql = (SQL_input*) info;
*sql->view = $1;
}
| onecreate
{
SQL_input* sql = (SQL_input*) info;
*sql->view = $1;
}
;
onecreate:
TK_CREATE TK_TABLE table TK_LP table_def TK_RP
{
SQL_input* sql = (SQL_input*) info;
MSIVIEW *create;
if( !$5 )
YYABORT;
CREATE_CreateView( sql->db, &create, $3, $5, FALSE );
$$ = create;
}
| TK_CREATE TK_TABLE table TK_LP table_def TK_RP TK_HOLD
{
SQL_input* sql = (SQL_input*) info;
MSIVIEW *create;
if( !$5 )
YYABORT;
CREATE_CreateView( sql->db, &create, $3, $5, TRUE );
$$ = create;
}
;
table_def:
column_def TK_PRIMARY TK_KEY selcollist
{
if( SQL_MarkPrimaryKeys( $1, $4 ) )
$$ = $1;
else
$$ = NULL;
}
;
column_def:
column_def TK_COMMA column column_type
{
$$ = HeapAlloc( GetProcessHeap(), 0, sizeof *$$ );
if( $$ )
{
$$->colname = $3;
$$->type = $4;
$$->next = $1;
}
else if( $1 )
HeapFree( GetProcessHeap(), 0, $1 );
}
| column column_type
{
$$ = HeapAlloc( GetProcessHeap(), 0, sizeof *$$ );
if( $$ )
{
$$->colname = $1;
$$->type = $2;
$$->next = NULL;
}
}
;
column_type:
data_type
{
$$ |= MSITYPE_NULLABLE;
}
| data_type TK_NOT TK_NULL
{
$$ = $1;
}
;
data_type:
TK_CHAR
{
$$ = MSITYPE_STRING | 1;
}
| TK_CHAR TK_LP data_count TK_RP
{
$$ = MSITYPE_STRING | $3;
}
| TK_LONGCHAR
{
$$ = 2;
}
| TK_SHORT
{
$$ = 2;
}
| TK_INT
{
$$ = 2;
}
| TK_LONG
{
$$ = 4;
}
| TK_OBJECT
{
$$ = 0;
}
;
data_count:
TK_INTEGER
{
SQL_input* sql = (SQL_input*) info;
int val = SQL_getint(sql);
if( ( val > 255 ) || ( val < 0 ) )
YYABORT;
$$ = val;
}
;
oneselect:
unorderedsel TK_ORDER TK_BY selcollist
{
@ -136,16 +266,11 @@ oneselect:
if( !$1 )
YYABORT;
if( $4 )
*sql->view = do_order_by( sql->db, $1, $4 );
$$ = do_order_by( sql->db, $1, $4 );
else
*sql->view = $1;
$$ = $1;
}
| unorderedsel
{
SQL_input* sql = (SQL_input*) info;
*sql->view = $1;
}
;
unorderedsel:
@ -491,6 +616,29 @@ static struct expr * EXPR_sval( LPWSTR string )
return e;
}
static BOOL SQL_MarkPrimaryKeys( create_col_info *cols,
struct string_list *keys )
{
struct string_list *k;
BOOL found = TRUE;
for( k = keys; k && found; k = k->next )
{
create_col_info *c;
found = FALSE;
for( c = cols; c && !found; c = c->next )
{
if( lstrcmpW( k->string, c->colname ) )
continue;
c->type |= MSITYPE_KEY;
found = TRUE;
}
}
return found;
}
UINT MSI_ParseSQL( MSIDATABASE *db, LPCWSTR command, MSIVIEW **phview )
{
SQL_input sql;

View file

@ -55,6 +55,8 @@ static const Keyword aKeywordTable[] = {
{ "BY", TK_BY },
{ "CASCADE", TK_CASCADE },
{ "CASE", TK_CASE },
{ "CHAR", TK_CHAR },
{ "CHARACTER", TK_CHAR },
{ "CHECK", TK_CHECK },
{ "CLUSTER", TK_CLUSTER },
{ "COLLATE", TK_COLLATE },
@ -85,6 +87,7 @@ static const Keyword aKeywordTable[] = {
{ "GLOB", TK_GLOB },
{ "GROUP", TK_GROUP },
{ "HAVING", TK_HAVING },
{ "HOLD", TK_HOLD },
{ "IGNORE", TK_IGNORE },
{ "IMMEDIATE", TK_IMMEDIATE },
{ "IN", TK_IN },
@ -93,6 +96,7 @@ static const Keyword aKeywordTable[] = {
{ "INNER", TK_JOIN_KW },
{ "INSERT", TK_INSERT },
{ "INSTEAD", TK_INSTEAD },
{ "INT", TK_INT },
{ "INTERSECT", TK_INTERSECT },
{ "INTO", TK_INTO },
{ "IS", TK_IS },
@ -102,11 +106,14 @@ static const Keyword aKeywordTable[] = {
{ "LEFT", TK_JOIN_KW },
{ "LIKE", TK_LIKE },
{ "LIMIT", TK_LIMIT },
{ "LONG", TK_LONG },
{ "LONGCHAR", TK_LONGCHAR },
{ "MATCH", TK_MATCH },
{ "NATURAL", TK_JOIN_KW },
{ "NOT", TK_NOT },
{ "NOTNULL", TK_NOTNULL },
{ "NULL", TK_NULL },
{ "OBJECT", TK_OBJECT },
{ "OF", TK_OF },
{ "OFFSET", TK_OFFSET },
{ "ON", TK_ON },
@ -124,6 +131,7 @@ static const Keyword aKeywordTable[] = {
{ "ROW", TK_ROW },
{ "SELECT", TK_SELECT },
{ "SET", TK_SET },
{ "SHORT", TK_SHORT },
{ "STATEMENT", TK_STATEMENT },
{ "TABLE", TK_TABLE },
{ "TEMP", TK_TEMP },