MSI: fix and test inserting records

Mike McCormack mike at codeweavers.com
Thu Jan 20 08:28:04 CST 2005


ChangeLog:
* fix and test inserting records
-------------- next part --------------
Index: dlls/msi/sql.y
===================================================================
RCS file: /home/wine/wine/dlls/msi/sql.y,v
retrieving revision 1.19
diff -u -p -r1.19 sql.y
--- dlls/msi/sql.y	16 Dec 2004 14:33:56 -0000	1.19
+++ dlls/msi/sql.y	20 Jan 2005 14:26:55 -0000
@@ -499,18 +499,17 @@ constlist:
             }
             $$ = vals;
         }
-  | constlist TK_COMMA const_val
+  | const_val TK_COMMA constlist
         {
             value_list *vals;
 
             vals = HeapAlloc( GetProcessHeap(), 0, sizeof *vals );
             if( vals )
             {
-                vals->val = $3;
-                vals->next = NULL;
+                vals->val = $1;
+                vals->next = $3;
             }
-            $1->next = vals;
-            $$ = $1;
+            $$ = vals;
         }
     ;
 
Index: dlls/msi/insert.c
===================================================================
RCS file: /home/wine/wine/dlls/msi/insert.c,v
retrieving revision 1.8
diff -u -p -r1.8 insert.c
--- dlls/msi/insert.c	25 Aug 2004 17:31:39 -0000	1.8
+++ dlls/msi/insert.c	20 Jan 2005 14:26:56 -0000
@@ -44,7 +44,7 @@ typedef struct tagMSIINSERTVIEW
     MSIDATABASE     *db;
     BOOL             bIsTemp;
     MSIVIEW         *sv;
-    value_list      *vals;   /* looks like these may be ignored... */
+    value_list      *vals;
 } MSIINSERTVIEW;
 
 static UINT INSERT_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val )
@@ -56,11 +56,62 @@ static UINT INSERT_fetch_int( struct tag
     return ERROR_FUNCTION_FAILED;
 }
 
+/*
+ * INSERT_merge_record
+ *
+ * Merge a value_list and a record to create a second record.
+ * Replace wildcard entries in the valuelist with values from the record
+ */
+static MSIRECORD *INSERT_merge_record( UINT fields, value_list *vl, MSIRECORD *rec )
+{
+    MSIRECORD *merged;
+    DWORD wildcard_count = 1, i;
+    const WCHAR *str;
+
+    merged = MSI_CreateRecord( fields );
+    for( i=1; i <= fields; i++ )
+    {
+        if( !vl )
+        {
+            TRACE("Not enough elements in the list to insert\n");
+            goto err;
+        }
+        switch( vl->val->type )
+        {
+        case EXPR_SVAL:
+            TRACE("field %ld -> %s\n", i, debugstr_w(vl->val->u.sval));
+            MSI_RecordSetStringW( merged, i, vl->val->u.sval );
+            break;
+        case EXPR_IVAL:
+            MSI_RecordSetInteger( merged, i, vl->val->u.ival );
+            break;
+        case EXPR_WILDCARD:
+            if( !rec )
+                goto err;
+            if( MSI_RecordIsNull( rec, wildcard_count ) )
+                goto err;
+            str = MSI_RecordGetString( rec, wildcard_count );
+            MSI_RecordSetStringW( merged, i, str );
+            wildcard_count++;
+            break;
+        default:
+            ERR("Unknown expression type %d\n", vl->val->type);
+        }
+        vl = vl->next;
+    }
+
+    return merged;
+err:
+    msiobj_release( &merged->hdr );
+    return NULL;
+}
+
 static UINT INSERT_execute( struct tagMSIVIEW *view, MSIRECORD *record )
 {
     MSIINSERTVIEW *iv = (MSIINSERTVIEW*)view;
     UINT n, type, val, r, row, col_count = 0;
     MSIVIEW *sv;
+    MSIRECORD *values = NULL;
 
     TRACE("%p %p\n", iv, record );
 
@@ -77,12 +128,13 @@ static UINT INSERT_execute( struct tagMS
     if( r )
         goto err;
 
-    n = MSI_RecordGetFieldCount( record );
-    if( n != col_count )
-    {
-        ERR("Number of fields do not match\n");
+    /*
+     * Merge the wildcard values into the list of values provided
+     * in the query, and create a record containing both.
+     */
+    values = INSERT_merge_record( col_count, iv->vals, record );
+    if( !values )
         goto err;
-    }
 
     row = -1;
     r = sv->ops->insert_row( sv, &row );
@@ -98,12 +150,12 @@ static UINT INSERT_execute( struct tagMS
 
         if( type & MSITYPE_STRING )
         {
-            const WCHAR *str = MSI_RecordGetString( record, n );
+            const WCHAR *str = MSI_RecordGetString( values, n );
             val = msi_addstringW( iv->db->strings, 0, str, -1, 1 );
         }
         else
         {
-            val = MSI_RecordGetInteger( record, n );
+            val = MSI_RecordGetInteger( values, n );
             val |= 0x8000;
         }
         r = sv->ops->set_int( sv, row, n, val );
@@ -112,6 +164,9 @@ static UINT INSERT_execute( struct tagMS
     }
 
 err:
+    if( values )
+        msiobj_release( &values->hdr );
+
     return ERROR_SUCCESS;
 }
 
Index: dlls/msi/tests/db.c
===================================================================
RCS file: /home/wine/wine/dlls/msi/tests/db.c,v
retrieving revision 1.2
diff -u -p -r1.2 db.c
--- dlls/msi/tests/db.c	10 Jan 2005 13:29:25 -0000	1.2
+++ dlls/msi/tests/db.c	20 Jan 2005 14:26:56 -0000
@@ -24,7 +24,7 @@
 
 #include "wine/test.h"
 
-START_TEST(db)
+static void test_msidatabase(void)
 {
     MSIHANDLE hdb = 0;
     CHAR szName[] = "C:\\mytest.msi";
@@ -41,4 +41,87 @@ START_TEST(db)
 
     res = MsiCloseHandle( hdb );
     ok( res == ERROR_SUCCESS , "Failed to close database" );
+}
+
+void test_msiinsert(void)
+{
+    const char *msifile = "winetest.msi";
+    MSIHANDLE hdb = 0, hview = 0, hrec = 0;
+    UINT r;
+    char *query, buf[80];
+    DWORD sz;
+
+    DeleteFile(msifile);
+
+    /* just MsiOpenDatabase should not create a file */
+    r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb);
+    ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n");
+
+    /* create a table */
+    query = "CREATE TABLE `phone` ( "
+            "`id` INT, `name` CHAR(32), `number` CHAR(32) "
+            "PRIMARY KEY `id`)";
+    r = MsiDatabaseOpenView(hdb, query, &hview);
+    ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
+    r = MsiViewExecute(hview, 0);
+    ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
+    r = MsiViewClose(hview);
+    ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
+    r = MsiCloseHandle(hview);
+    ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
+
+    /* insert a value into it */
+    query = "INSERT INTO `phone` ( `id`, `name`, `number` )"
+        "VALUES('1', 'Abe', '8675309')";
+    r = MsiDatabaseOpenView(hdb, query, &hview);
+    ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
+    r = MsiViewExecute(hview, 0);
+    ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
+    r = MsiViewClose(hview);
+    ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
+    r = MsiCloseHandle(hview);
+    ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
+
+    query = "SELECT * FROM `phone`";
+    r = MsiDatabaseOpenView(hdb, query, &hview);
+    ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n");
+    r = MsiViewExecute(hview, 0);
+    ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
+    r = MsiViewFetch(hview, &hrec);
+    ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n");
+
+    /* check the record contains what we put in it */
+    r = MsiRecordGetFieldCount(hrec);
+    ok(r == 3, "record count wrong\n");
+
+    r = MsiRecordGetInteger(hrec, 1);
+    ok(r == 1, "field 1 contents wrong\n");
+    sz = sizeof buf;
+    r = MsiRecordGetString(hrec, 2, buf, &sz);
+    ok(r == ERROR_SUCCESS, "field 2 content fetch failed\n");
+    ok(!strcmp(buf,"Abe"), "field 2 content incorrect\n");
+    sz = sizeof buf;
+    r = MsiRecordGetString(hrec, 3, buf, &sz);
+    ok(r == ERROR_SUCCESS, "field 3 content fetch failed\n");
+    ok(!strcmp(buf,"8675309"), "field 3 content incorrect\n");
+    
+    r = MsiViewClose(hview);
+    ok(r == ERROR_SUCCESS, "MsiViewClose failed\n");
+    r = MsiCloseHandle(hview);
+    ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
+
+    r = MsiDatabaseCommit(hdb);
+    ok(r == ERROR_SUCCESS, "MsiDatabaseCommit failed\n");
+
+    r = MsiCloseHandle(hdb);
+    ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n");
+
+    r = DeleteFile(msifile);
+    ok(r == TRUE, "file didn't exist after commit\n");
+}
+
+START_TEST(db)
+{
+    test_msidatabase();
+    test_msiinsert();
 }


More information about the wine-patches mailing list