msi: Add support for returning validation errors.
This commit is contained in:
parent
c869192c92
commit
ab13c00fc9
|
@ -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");
|
||||
|
|
Loading…
Reference in New Issue