[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