MSI: Extend the SQL parser to deal with the CREATE TABLE query.
Mike McCormack
mike at codeweavers.com
Mon Mar 15 22:43:13 CST 2004
ChangeLog:
* Extend the parser to deal with the CREATE TABLE query.
The query doesn't do anything as yet.
-------------- next part --------------
? dlls/msi/create.c
Index: dlls/msi/Makefile.in
===================================================================
RCS file: /home/wine/wine/dlls/msi/Makefile.in,v
retrieving revision 1.5
diff -u -r1.5 Makefile.in
--- dlls/msi/Makefile.in 16 Mar 2004 03:23:43 -0000 1.5
+++ dlls/msi/Makefile.in 16 Mar 2004 03:55:59 -0000
@@ -7,6 +7,7 @@
EXTRALIBS = -luuid $(LIBUNICODE)
C_SRCS = \
+ create.c \
distinct.c \
handle.c \
msi.c \
Index: dlls/msi/msi.c
===================================================================
RCS file: /home/wine/wine/dlls/msi/msi.c,v
retrieving revision 1.10
diff -u -r1.10 msi.c
--- dlls/msi/msi.c 17 Feb 2004 21:05:44 -0000 1.10
+++ dlls/msi/msi.c 16 Mar 2004 03:56:00 -0000
@@ -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 @@
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 @@
goto end;
}
db->storage = stg;
+ db->mode = szMode;
ret = load_string_table( db, &db->strings);
if( ret != ERROR_SUCCESS )
goto end;
Index: dlls/msi/msipriv.h
===================================================================
RCS file: /home/wine/wine/dlls/msi/msipriv.h,v
retrieving revision 1.4
diff -u -r1.4 msipriv.h
--- dlls/msi/msipriv.h 27 Sep 2003 02:24:32 -0000 1.4
+++ dlls/msi/msipriv.h 16 Mar 2004 03:56:00 -0000
@@ -60,6 +60,7 @@
{
IStorage *storage;
string_table strings;
+ LPWSTR mode;
MSITABLE *first_table, *last_table;
} MSIDATABASE;
Index: dlls/msi/query.h
===================================================================
RCS file: /home/wine/wine/dlls/msi/query.h,v
retrieving revision 1.3
diff -u -r1.3 query.h
--- dlls/msi/query.h 8 Sep 2003 19:38:46 -0000 1.3
+++ dlls/msi/query.h 16 Mar 2004 03:56:00 -0000
@@ -70,6 +70,12 @@
} 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);
@@ -85,6 +91,9 @@
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);
Index: dlls/msi/sql.y
===================================================================
RCS file: /home/wine/wine/dlls/msi/sql.y,v
retrieving revision 1.5
diff -u -r1.5 sql.y
--- dlls/msi/sql.y 16 Mar 2004 03:23:43 -0000 1.5
+++ dlls/msi/sql.y 16 Mar 2004 03:56:00 -0000
@@ -63,6 +63,9 @@
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 @@
{
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 @@
%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 @@
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:
@@ -489,6 +614,29 @@
e->u.sval = 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 )
Index: dlls/msi/tokenize.c
===================================================================
RCS file: /home/wine/wine/dlls/msi/tokenize.c,v
retrieving revision 1.4
diff -u -r1.4 tokenize.c
--- dlls/msi/tokenize.c 16 Mar 2004 03:23:43 -0000 1.4
+++ dlls/msi/tokenize.c 16 Mar 2004 03:56:00 -0000
@@ -55,6 +55,8 @@
{ "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 @@
{ "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 @@
{ "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 @@
{ "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 @@
{ "ROW", TK_ROW },
{ "SELECT", TK_SELECT },
{ "SET", TK_SET },
+ { "SHORT", TK_SHORT },
{ "STATEMENT", TK_STATEMENT },
{ "TABLE", TK_TABLE },
{ "TEMP", TK_TEMP },
--- /dev/null 1994-07-18 08:46:18.000000000 +0900
+++ dlls/msi/create.c 2004-03-16 13:37:32.000000000 +0900
@@ -0,0 +1,170 @@
+/*
+ * 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;
+}
+
More information about the wine-patches
mailing list