Commit 14ec5260 authored by Mike McCormack's avatar Mike McCormack Committed by Alexandre Julliard

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

doesn't do anything as yet.
parent 821f4775
......@@ -7,6 +7,7 @@ IMPORTS = ole32 user32 advapi32 kernel32
EXTRALIBS = -luuid $(LIBUNICODE)
C_SRCS = \
create.c \
distinct.c \
handle.c \
msi.c \
......
/*
* 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;
}
......@@ -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;
......
......@@ -60,6 +60,7 @@ typedef struct tagMSIDATABASE
{
IStorage *storage;
string_table strings;
LPWSTR mode;
MSITABLE *first_table, *last_table;
} MSIDATABASE;
......
......@@ -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 */
......@@ -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;
......
......@@ -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 },
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment