[06/10] msi: Add support for returning validation errors.

Hans Leidekker hans at codeweavers.com
Tue Jun 7 03:34:49 CDT 2011


Fixes http://bugs.winehq.org/show_bug.cgi?id=27338
---
 dlls/msi/msipriv.h  |    2 +
 dlls/msi/msiquery.c |   58 +++++++++++++++++++++++++-------------------------
 dlls/msi/table.c    |   49 ++++++++++++++++++++++++++----------------
 dlls/msi/tests/db.c |   34 +++++++++++++++++++++++++++++
 4 files changed, 95 insertions(+), 48 deletions(-)

diff --git a/dlls/msi/msipriv.h b/dlls/msi/msipriv.h
index ab53113..6e9c959 100644
--- a/dlls/msi/msipriv.h
+++ b/dlls/msi/msipriv.h
@@ -325,6 +325,8 @@ struct tagMSIVIEW
 {
     MSIOBJECTHDR hdr;
     const MSIVIEWOPS *ops;
+    MSIDBERROR error;
+    const WCHAR *error_column;
 };
 
 struct msi_dialog_tag;
diff --git a/dlls/msi/msiquery.c b/dlls/msi/msiquery.c
index 4ccf5f6..9154c98 100644
--- a/dlls/msi/msiquery.c
+++ b/dlls/msi/msiquery.c
@@ -650,66 +650,66 @@ UINT WINAPI MsiViewModify( MSIHANDLE hView, MSIMODIFY eModifyMode,
     return r;
 }
 
-MSIDBERROR WINAPI MsiViewGetErrorW( MSIHANDLE handle, LPWSTR szColumnNameBuffer,
-                              LPDWORD pcchBuf )
+MSIDBERROR WINAPI MsiViewGetErrorW( MSIHANDLE handle, LPWSTR buffer, LPDWORD buflen )
 {
-    MSIQUERY *query = NULL;
-    static const WCHAR szError[] = { 0 };
-    MSIDBERROR r = MSIDBERROR_NOERROR;
+    MSIQUERY *query;
+    const WCHAR *column;
+    MSIDBERROR r;
     DWORD len;
 
-    FIXME("%d %p %p - returns empty error string\n",
-          handle, szColumnNameBuffer, pcchBuf );
+    TRACE("%u %p %p\n", handle, buffer, buflen);
 
-    if( !pcchBuf )
+    if (!buflen)
         return MSIDBERROR_INVALIDARG;
 
     query = msihandle2msiinfo( handle, MSIHANDLETYPE_VIEW );
     if( !query )
         return MSIDBERROR_INVALIDARG;
 
-    len = strlenW( szError );
-    if( szColumnNameBuffer )
+    if ((r = query->view->error)) column = query->view->error_column;
+    else column = szEmpty;
+
+    len = strlenW( column );
+    if (buffer)
     {
-        if( *pcchBuf > len )
-            lstrcpyW( szColumnNameBuffer, szError );
+        if (*buflen > len)
+            strcpyW( buffer, column );
         else
             r = MSIDBERROR_MOREDATA;
     }
-    *pcchBuf = len;
-
+    *buflen = len;
     msiobj_release( &query->hdr );
     return r;
 }
 
-MSIDBERROR WINAPI MsiViewGetErrorA( MSIHANDLE handle, LPSTR szColumnNameBuffer,
-                              LPDWORD pcchBuf )
+MSIDBERROR WINAPI MsiViewGetErrorA( MSIHANDLE handle, LPSTR buffer, LPDWORD buflen )
 {
-    static const CHAR szError[] = { 0 };
-    MSIQUERY *query = NULL;
-    MSIDBERROR r = MSIDBERROR_NOERROR;
+    MSIQUERY *query;
+    const WCHAR *column;
+    MSIDBERROR r;
     DWORD len;
 
-    FIXME("%d %p %p - returns empty error string\n",
-          handle, szColumnNameBuffer, pcchBuf );
+    TRACE("%u %p %p\n", handle, buffer, buflen);
 
-    if( !pcchBuf )
+    if (!buflen)
         return MSIDBERROR_INVALIDARG;
 
     query = msihandle2msiinfo( handle, MSIHANDLETYPE_VIEW );
-    if( !query )
+    if (!query)
         return MSIDBERROR_INVALIDARG;
 
-    len = strlen( szError );
-    if( szColumnNameBuffer )
+    if ((r = query->view->error)) column = query->view->error_column;
+    else column = szEmpty;
+
+    len = WideCharToMultiByte( CP_ACP, 0, column, -1, NULL, 0, NULL, NULL );
+    if (buffer)
     {
-        if( *pcchBuf > len )
-            lstrcpyA( szColumnNameBuffer, szError );
+        if (*buflen >= len)
+            WideCharToMultiByte( CP_ACP, 0, column, -1, buffer, *buflen, NULL, NULL );
         else
             r = MSIDBERROR_MOREDATA;
     }
-    *pcchBuf = len;
-
+    *buflen = len - 1;
     msiobj_release( &query->hdr );
     return r;
 }
diff --git a/dlls/msi/table.c b/dlls/msi/table.c
index 91f3676..7b36ff9 100644
--- a/dlls/msi/table.c
+++ b/dlls/msi/table.c
@@ -1579,9 +1579,9 @@ static UINT TABLE_get_column_info( struct tagMSIVIEW *view,
     return ERROR_SUCCESS;
 }
 
-static UINT msi_table_find_row( MSITABLEVIEW *tv, MSIRECORD *rec, UINT *row );
+static UINT msi_table_find_row( MSITABLEVIEW *tv, MSIRECORD *rec, UINT *row, UINT *column );
 
-static UINT table_validate_new( MSITABLEVIEW *tv, MSIRECORD *rec )
+static UINT table_validate_new( MSITABLEVIEW *tv, MSIRECORD *rec, UINT *column )
 {
     UINT r, row, i;
 
@@ -1599,7 +1599,10 @@ static UINT table_validate_new( MSITABLEVIEW *tv, MSIRECORD *rec )
 
             str = MSI_RecordGetString( rec, i+1 );
             if (str == NULL || str[0] == 0)
+            {
+                if (column) *column = i;
                 return ERROR_INVALID_DATA;
+            }
         }
         else
         {
@@ -1607,12 +1610,15 @@ static UINT table_validate_new( MSITABLEVIEW *tv, MSIRECORD *rec )
 
             n = MSI_RecordGetInteger( rec, i+1 );
             if (n == MSI_NULL_INTEGER)
+            {
+                if (column) *column = i;
                 return ERROR_INVALID_DATA;
+            }
         }
     }
 
     /* check there's no duplicate keys */
-    r = msi_table_find_row( tv, rec, &row );
+    r = msi_table_find_row( tv, rec, &row, column );
     if (r == ERROR_SUCCESS)
         return ERROR_FUNCTION_FAILED;
 
@@ -1685,7 +1691,7 @@ static UINT TABLE_insert_row( struct tagMSIVIEW *view, MSIRECORD *rec, UINT row,
     TRACE("%p %p %s\n", tv, rec, temporary ? "TRUE" : "FALSE" );
 
     /* check that the key is unique - can we find a matching row? */
-    r = table_validate_new( tv, rec );
+    r = table_validate_new( tv, rec, NULL );
     if( r != ERROR_SUCCESS )
         return ERROR_FUNCTION_FAILED;
 
@@ -1760,7 +1766,7 @@ static UINT msi_table_update(struct tagMSIVIEW *view, MSIRECORD *rec, UINT row)
     if (!tv->table)
         return ERROR_INVALID_PARAMETER;
 
-    r = msi_table_find_row(tv, rec, &new_row);
+    r = msi_table_find_row(tv, rec, &new_row, NULL);
     if (r != ERROR_SUCCESS)
     {
         ERR("can't find row to modify\n");
@@ -1785,7 +1791,7 @@ static UINT msi_table_assign(struct tagMSIVIEW *view, MSIRECORD *rec)
     if (!tv->table)
         return ERROR_INVALID_PARAMETER;
 
-    r = msi_table_find_row(tv, rec, &row);
+    r = msi_table_find_row(tv, rec, &row, NULL);
     if (r == ERROR_SUCCESS)
         return TABLE_set_row(view, row, rec, (1 << tv->num_cols) - 1);
     else
@@ -1797,7 +1803,7 @@ static UINT modify_delete_row( struct tagMSIVIEW *view, MSIRECORD *rec )
     MSITABLEVIEW *tv = (MSITABLEVIEW *)view;
     UINT row, r;
 
-    r = msi_table_find_row(tv, rec, &row);
+    r = msi_table_find_row(tv, rec, &row, NULL);
     if (r != ERROR_SUCCESS)
         return r;
 
@@ -1828,7 +1834,7 @@ static UINT TABLE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode,
                           MSIRECORD *rec, UINT row)
 {
     MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
-    UINT r;
+    UINT r, column;
 
     TRACE("%p %d %p\n", view, eModifyMode, rec );
 
@@ -1838,18 +1844,24 @@ static UINT TABLE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode,
         r = modify_delete_row( view, rec );
         break;
     case MSIMODIFY_VALIDATE_NEW:
-        r = table_validate_new( tv, rec );
+        r = table_validate_new( tv, rec, &column );
+        if (r != ERROR_SUCCESS)
+        {
+            tv->view.error = MSIDBERROR_DUPLICATEKEY;
+            tv->view.error_column = tv->columns[column].colname;
+            r = ERROR_INVALID_DATA;
+        }
         break;
 
     case MSIMODIFY_INSERT:
-        r = table_validate_new( tv, rec );
+        r = table_validate_new( tv, rec, NULL );
         if (r != ERROR_SUCCESS)
             break;
         r = TABLE_insert_row( view, rec, -1, FALSE );
         break;
 
     case MSIMODIFY_INSERT_TEMPORARY:
-        r = table_validate_new( tv, rec );
+        r = table_validate_new( tv, rec, NULL );
         if (r != ERROR_SUCCESS)
             break;
         r = TABLE_insert_row( view, rec, -1, TRUE );
@@ -2017,7 +2029,7 @@ static UINT TABLE_remove_column(struct tagMSIVIEW *view, LPCWSTR table, UINT num
     if (r != ERROR_SUCCESS)
         return r;
 
-    r = msi_table_find_row((MSITABLEVIEW *)columns, rec, &row);
+    r = msi_table_find_row((MSITABLEVIEW *)columns, rec, &row, NULL);
     if (r != ERROR_SUCCESS)
         goto done;
 
@@ -2294,7 +2306,7 @@ static UINT TABLE_drop(struct tagMSIVIEW *view)
     if (r != ERROR_SUCCESS)
         return r;
 
-    r = msi_table_find_row((MSITABLEVIEW *)tables, rec, &row);
+    r = msi_table_find_row((MSITABLEVIEW *)tables, rec, &row, NULL);
     if (r != ERROR_SUCCESS)
         goto done;
 
@@ -2660,7 +2672,7 @@ static UINT* msi_record_to_row( const MSITABLEVIEW *tv, MSIRECORD *rec )
     return data;
 }
 
-static UINT msi_row_matches( MSITABLEVIEW *tv, UINT row, const UINT *data )
+static UINT msi_row_matches( MSITABLEVIEW *tv, UINT row, const UINT *data, UINT *column )
 {
     UINT i, r, x, ret = ERROR_FUNCTION_FAILED;
 
@@ -2683,14 +2695,13 @@ static UINT msi_row_matches( MSITABLEVIEW *tv, UINT row, const UINT *data )
             ret = ERROR_FUNCTION_FAILED;
             break;
         }
-
+        if (column) *column = i;
         ret = ERROR_SUCCESS;
     }
-
     return ret;
 }
 
-static UINT msi_table_find_row( MSITABLEVIEW *tv, MSIRECORD *rec, UINT *row )
+static UINT msi_table_find_row( MSITABLEVIEW *tv, MSIRECORD *rec, UINT *row, UINT *column )
 {
     UINT i, r = ERROR_FUNCTION_FAILED, *data;
 
@@ -2699,7 +2710,7 @@ static UINT msi_table_find_row( MSITABLEVIEW *tv, MSIRECORD *rec, UINT *row )
         return r;
     for( i = 0; i < tv->table->row_count; i++ )
     {
-        r = msi_row_matches( tv, i, data );
+        r = msi_row_matches( tv, i, data, column );
         if( r == ERROR_SUCCESS )
         {
             *row = i;
@@ -2844,7 +2855,7 @@ static UINT msi_table_load_transform( MSIDATABASE *db, IStorage *stg,
 
             if (TRACE_ON(msidb)) dump_record( rec );
 
-            r = msi_table_find_row( tv, rec, &row );
+            r = msi_table_find_row( tv, rec, &row, NULL );
             if (r == ERROR_SUCCESS)
             {
                 if (!mask)
diff --git a/dlls/msi/tests/db.c b/dlls/msi/tests/db.c
index a9d0e933..d97a8cb 100644
--- a/dlls/msi/tests/db.c
+++ b/dlls/msi/tests/db.c
@@ -754,6 +754,19 @@ static void test_viewmodify(void)
     r = run_query( hdb, 0, query );
     ok(r == ERROR_SUCCESS, "query failed\n");
 
+    query = "CREATE TABLE `_Validation` ( "
+            "`Table` CHAR(32) NOT NULL, `Column` CHAR(32) NOT NULL, "
+            "`Nullable` CHAR(4) NOT NULL, `MinValue` INT, `MaxValue` INT, "
+            "`KeyTable` CHAR(255), `KeyColumn` SHORT, `Category` CHAR(32), "
+            "`Set` CHAR(255), `Description` CHAR(255) PRIMARY KEY `Table`, `Column`)";
+    r = run_query( hdb, 0, query );
+    ok(r == ERROR_SUCCESS, "query failed\n");
+
+    query = "INSERT INTO `_Validation` ( `Table`, `Column`, `Nullable` ) "
+            "VALUES('phone', 'id', 'N')";
+    r = run_query( hdb, 0, query );
+    ok(r == ERROR_SUCCESS, "query failed\n");
+
     /* check what the error function reports without doing anything */
     sz = 0;
     /* passing NULL as the 3rd param make function to crash on older platforms */
@@ -808,6 +821,13 @@ static void test_viewmodify(void)
     r = MsiViewModify(hview, -1, hrec );
     ok(r == ERROR_INVALID_DATA, "MsiViewModify failed\n");
 
+    sz = sizeof buffer;
+    buffer[0] = 'x';
+    err = MsiViewGetError( hview, buffer, &sz );
+    ok(err == MSIDBERROR_NOERROR, "MsiViewGetError return\n");
+    ok(buffer[0] == 0, "buffer not cleared\n");
+    ok(sz == 0, "size not zero\n");
+
     r = MsiCloseHandle(hrec);
     ok(r == ERROR_SUCCESS, "failed to close record\n");
 
@@ -826,6 +846,20 @@ static void test_viewmodify(void)
     r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec );
     ok(r == ERROR_SUCCESS, "MsiViewModify failed\n");
 
+    /* validate it */
+    r = MsiViewExecute(hview, 0);
+    ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
+
+    r = MsiViewModify(hview, MSIMODIFY_VALIDATE_NEW, hrec );
+    ok(r == ERROR_INVALID_DATA, "MsiViewModify failed %u\n", r);
+
+    sz = sizeof buffer;
+    buffer[0] = 'x';
+    err = MsiViewGetError( hview, buffer, &sz );
+    ok(err == MSIDBERROR_DUPLICATEKEY, "MsiViewGetError returned %u\n", err);
+    ok(!strcmp(buffer, "id"), "expected \"id\" c, got \"%s\"\n", buffer);
+    ok(sz == 2, "size not 2\n");
+
     /* insert the same thing again */
     r = MsiViewExecute(hview, 0);
     ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n");
-- 
1.7.4.1







More information about the wine-patches mailing list