Commit ab13c00f authored by Hans Leidekker's avatar Hans Leidekker Committed by Alexandre Julliard

msi: Add support for returning validation errors.

parent c869192c
......@@ -325,6 +325,8 @@ struct tagMSIVIEW
{
MSIOBJECTHDR hdr;
const MSIVIEWOPS *ops;
MSIDBERROR error;
const WCHAR *error_column;
};
struct msi_dialog_tag;
......
......@@ -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;
}
......
......@@ -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)
......
......@@ -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");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment