MSI: Implement the UPDATE query

Mike McCormack mike at codeweavers.com
Thu Jul 1 10:36:29 CDT 2004


ChangeLog:
* Implement the UPDATE query
-------------- next part --------------
diff -u dlls/msi.old/Makefile.in dlls/msi/Makefile.in
--- dlls/msi.old/Makefile.in	2004-07-01 10:30:47.000000000 -0500
+++ dlls/msi/Makefile.in	2004-07-01 10:31:52.000000000 -0500
@@ -23,6 +23,7 @@
 	suminfo.c \
 	table.c \
 	tokenize.c \
+	update.c \
 	where.c
 
 RC_SRCS = version.rc
diff -u dlls/msi.old/query.h dlls/msi/query.h
--- dlls/msi.old/query.h	2004-07-01 10:30:47.000000000 -0500
+++ dlls/msi/query.h	2004-07-01 10:31:29.000000000 -0500
@@ -98,6 +98,13 @@
     struct _value_list *next;
 } value_list;
 
+typedef struct _column_assignment
+{
+    string_list *col_list;
+    value_list *val_list;
+} column_assignment;
+
+
 UINT MSI_ParseSQL( MSIDATABASE *db, LPCWSTR command, MSIVIEW **phView);
 
 UINT TABLE_CreateView( MSIDATABASE *db, LPCWSTR name, MSIVIEW **view );
@@ -119,6 +126,9 @@
 UINT INSERT_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table,
                         string_list *columns, value_list *values, BOOL temp );
 
+UINT UPDATE_CreateView( MSIDATABASE *db, MSIVIEW **, LPWSTR table,
+                        column_assignment *list, struct expr *expr );
+
 void delete_expr( struct expr *e );
 void delete_string_list( string_list *sl );
 void delete_value_list( value_list *vl );
diff -u dlls/msi.old/sql.y dlls/msi/sql.y
--- dlls/msi.old/sql.y	2004-07-01 10:30:47.000000000 -0500
+++ dlls/msi/sql.y	2004-07-01 10:31:29.000000000 -0500
@@ -80,6 +80,7 @@
     struct expr *expr;
     USHORT column_type;
     create_col_info *column_info;
+    column_assignment update_col_info;
 }
 
 %token TK_ABORT TK_AFTER TK_AGG_FUNCTION TK_ALL TK_AND TK_AS TK_ASC
@@ -128,11 +129,12 @@
 
 %type <string> column table string_or_id
 %type <column_list> selcollist
-%type <query> from unorderedsel oneselect onequery onecreate oneinsert
+%type <query> from unorderedsel oneselect onequery onecreate oneinsert oneupdate
 %type <expr> expr val column_val const_val
 %type <column_type> column_type data_type data_type_l data_count
 %type <column_info> column_def table_def
 %type <val_list> constlist
+%type <update_col_info> column_assignment update_assign_list
 
 %%
 
@@ -152,6 +154,11 @@
         SQL_input* sql = (SQL_input*) info;
         *sql->view = $1;
     }
+  | oneupdate
+    {
+        SQL_input* sql = (SQL_input*) info;
+        *sql->view = $1;
+    }
     ;
 
 oneinsert:
@@ -177,7 +184,7 @@
     TK_CREATE TK_TABLE table TK_LP table_def TK_RP
         {
             SQL_input* sql = (SQL_input*) info;
-            MSIVIEW *create; 
+            MSIVIEW *create = NULL; 
 
             if( !$5 )
                 YYABORT;
@@ -187,7 +194,7 @@
   | TK_CREATE TK_TABLE table TK_LP table_def TK_RP TK_HOLD
         {
             SQL_input* sql = (SQL_input*) info;
-            MSIVIEW *create; 
+            MSIVIEW *create = NULL; 
 
             if( !$5 )
                 YYABORT;
@@ -196,6 +203,17 @@
         }
     ;
 
+oneupdate:
+    TK_UPDATE table TK_SET update_assign_list TK_WHERE expr
+        {
+            SQL_input* sql = (SQL_input*) info;
+            MSIVIEW *update = NULL; 
+
+            UPDATE_CreateView( sql->db, &update, $2, &$4, $6 );
+            $$ = update;
+        }
+    ;
+
 table_def:
     column_def TK_PRIMARY TK_KEY selcollist
         {
@@ -483,7 +501,33 @@
             $1->next = vals;
             $$ = $1;
         }
-        ;
+    ;
+
+update_assign_list:
+    column_assignment
+  | column_assignment TK_COMMA update_assign_list
+        {
+            $1.col_list->next = $3.col_list;
+            $1.val_list->next = $3.val_list;
+            $$ = $1;
+        }
+    ;
+
+column_assignment:
+    column TK_EQ const_val
+        {
+            $$.col_list = HeapAlloc( GetProcessHeap(), 0, sizeof *$$.col_list );
+            if( !$$.col_list )
+                YYABORT;
+            $$.col_list->string = $1;
+            $$.col_list->next = NULL;
+            $$.val_list = HeapAlloc( GetProcessHeap(), 0, sizeof *$$.val_list );
+            if( !$$.val_list )
+                YYABORT;
+            $$.val_list->val = $3;
+            $$.val_list->next = 0;
+        }
+    ;
 
 const_val:
     TK_INTEGER
diff -u dlls/msi.old/where.c dlls/msi/where.c
--- dlls/msi.old/where.c	2004-07-01 10:30:47.000000000 -0500
+++ dlls/msi/where.c	2004-07-01 10:31:29.000000000 -0500
@@ -66,6 +66,23 @@
     return wv->table->ops->fetch_int( wv->table, row, col, val );
 }
 
+static UINT WHERE_set_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT val )
+{
+    MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
+
+    TRACE("%p %d %d %04x\n", wv, row, col, val );
+
+    if( !wv->table )
+         return ERROR_FUNCTION_FAILED;
+    
+    if( row > wv->row_count )
+        return ERROR_NO_MORE_ITEMS;
+    
+    row = wv->reorder[ row ];
+    
+    return wv->table->ops->set_int( wv->table, row, col, val );
+}
+
 static UINT INT_evaluate( UINT lval, UINT op, UINT rval )
 {
     switch( op )
@@ -311,7 +328,7 @@
 MSIVIEWOPS where_ops =
 {
     WHERE_fetch_int,
-    NULL,
+    WHERE_set_int,
     NULL,
     WHERE_execute,
     WHERE_close,
--- /dev/null	1994-07-17 18:46:18.000000000 -0500
+++ dlls/msi/update.c	2004-07-01 10:31:29.000000000 -0500
@@ -0,0 +1,236 @@
+/*
+ * Implementation of the Microsoft Installer (msi.dll)
+ *
+ * Copyright 2004 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 receuved 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 tagMSIUPDATEVIEW
+{
+    MSIVIEW          view;
+    MSIDATABASE     *db;
+    MSIVIEW         *wv;
+    value_list      *vals;
+} MSIUPDATEVIEW;
+
+static UINT UPDATE_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val )
+{
+    MSIUPDATEVIEW *uv = (MSIUPDATEVIEW*)view;
+
+    TRACE("%p %d %d %p\n", uv, row, col, val );
+
+    return ERROR_FUNCTION_FAILED;
+}
+
+static UINT UPDATE_execute( struct tagMSIVIEW *view, MSIHANDLE record )
+{
+    MSIUPDATEVIEW *uv = (MSIUPDATEVIEW*)view;
+    UINT n, type, val, r, row, col_count = 0, row_count = 0;
+    MSIVIEW *wv;
+
+    TRACE("%p %ld\n", uv, record );
+
+    if( !record )
+        return ERROR_FUNCTION_FAILED;
+
+    wv = uv->wv;
+    if( !wv )
+        return ERROR_FUNCTION_FAILED;
+
+    r = wv->ops->execute( wv, 0 );
+    TRACE("tv execute returned %x\n", r);
+    if( r )
+        return r;
+
+    r = wv->ops->get_dimensions( wv, &row_count, &col_count );
+    if( r )
+        goto err;
+
+    for( row = 0; row < row_count; row++ )
+    {
+        for( n = 1; n <= col_count; n++ )
+        {
+            r = wv->ops->get_column_info( wv, n, NULL, &type );
+            if( r )
+                break;
+
+            if( type & MSITYPE_STRING )
+            {
+                const WCHAR *str = MSI_RecordGetString( record, n );
+                val = msi_addstringW( uv->db->strings, 0, str, -1, 1 );
+            }
+            else
+            {
+                val = MsiRecordGetInteger( record, n );
+                val |= 0x8000;
+            }
+            r = wv->ops->set_int( wv, row, n, val );
+            if( r )
+                break;
+        }
+    }
+
+err:
+    return ERROR_SUCCESS;
+}
+
+
+static UINT UPDATE_close( struct tagMSIVIEW *view )
+{
+    MSIUPDATEVIEW *uv = (MSIUPDATEVIEW*)view;
+    MSIVIEW *wv;
+
+    TRACE("%p\n", uv);
+
+    wv = uv->wv;
+    if( !wv )
+        return ERROR_FUNCTION_FAILED;
+
+    return wv->ops->close( wv );
+}
+
+static UINT UPDATE_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols )
+{
+    MSIUPDATEVIEW *uv = (MSIUPDATEVIEW*)view;
+    MSIVIEW *wv;
+
+    TRACE("%p %p %p\n", uv, rows, cols );
+
+    wv = uv->wv;
+    if( !wv )
+        return ERROR_FUNCTION_FAILED;
+
+    return wv->ops->get_dimensions( wv, rows, cols );
+}
+
+static UINT UPDATE_get_column_info( struct tagMSIVIEW *view,
+                UINT n, LPWSTR *name, UINT *type )
+{
+    MSIUPDATEVIEW *uv = (MSIUPDATEVIEW*)view;
+    MSIVIEW *wv;
+
+    TRACE("%p %d %p %p\n", uv, n, name, type );
+
+    wv = uv->wv;
+    if( !wv )
+        return ERROR_FUNCTION_FAILED;
+
+    return wv->ops->get_column_info( wv, n, name, type );
+}
+
+static UINT UPDATE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, MSIHANDLE hrec)
+{
+    MSIUPDATEVIEW *uv = (MSIUPDATEVIEW*)view;
+
+    TRACE("%p %d %ld\n", uv, eModifyMode, hrec );
+
+    return ERROR_FUNCTION_FAILED;
+}
+
+static UINT UPDATE_delete( struct tagMSIVIEW *view )
+{
+    MSIUPDATEVIEW *uv = (MSIUPDATEVIEW*)view;
+    MSIVIEW *wv;
+
+    TRACE("%p\n", uv );
+
+    wv = uv->wv;
+    if( wv )
+        wv->ops->delete( wv );
+    delete_value_list( uv->vals );
+    HeapFree( GetProcessHeap(), 0, uv );
+
+    return ERROR_SUCCESS;
+}
+
+
+static MSIVIEWOPS update_ops =
+{
+    UPDATE_fetch_int,
+    NULL,
+    NULL,
+    UPDATE_execute,
+    UPDATE_close,
+    UPDATE_get_dimensions,
+    UPDATE_get_column_info,
+    UPDATE_modify,
+    UPDATE_delete
+};
+
+UINT UPDATE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table,
+                        column_assignment *list, struct expr *expr )
+{
+    MSIUPDATEVIEW *uv = NULL;
+    UINT r;
+    MSIVIEW *tv = NULL, *sv = NULL, *wv = NULL;
+
+    TRACE("%p\n", uv );
+
+    r = TABLE_CreateView( db, table, &tv );
+    if( r != ERROR_SUCCESS )
+        return r;
+
+    /* add conditions first */
+    r = WHERE_CreateView( db, &wv, tv, expr );
+    if( r != ERROR_SUCCESS )
+    {
+        if( sv )
+            sv->ops->delete( tv );
+        return r;
+    }
+    
+    /* then select the columns we want */
+    r = SELECT_CreateView( db, &sv, wv, list->col_list );
+    if( r != ERROR_SUCCESS )
+    {
+        if( tv )
+            tv->ops->delete( sv );
+        return r;
+    }
+
+    uv = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof *uv );
+    if( !uv )
+        return ERROR_FUNCTION_FAILED;
+
+    /* fill the structure */
+    uv->view.ops = &update_ops;
+    uv->db = db;
+    uv->vals = list->val_list;
+    uv->wv = sv;
+    *view = (MSIVIEW*) uv;
+
+    return ERROR_SUCCESS;
+}


More information about the wine-patches mailing list