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