From e8d1a167df7d48988848704ab8f1b9894c842058 Mon Sep 17 00:00:00 2001 From: Mike McCormack Date: Wed, 24 Aug 2005 11:10:23 +0000 Subject: [PATCH] Implement MsiModifyView (MSIMODIFY_INSERT_TEMPORARY). --- dlls/msi/create.c | 66 +++++++++----------- dlls/msi/delete.c | 4 +- dlls/msi/insert.c | 31 +-------- dlls/msi/msipriv.h | 5 +- dlls/msi/select.c | 6 +- dlls/msi/table.c | 152 +++++++++++++++++++++++++++++++++++++++++++-- 6 files changed, 188 insertions(+), 76 deletions(-) diff --git a/dlls/msi/create.c b/dlls/msi/create.c index 2d92db1f1f6..e442361071a 100644 --- a/dlls/msi/create.c +++ b/dlls/msi/create.c @@ -60,10 +60,11 @@ static UINT CREATE_execute( struct tagMSIVIEW *view, MSIRECORD *record ) { MSICREATEVIEW *cv = (MSICREATEVIEW*)view; column_info *col; - UINT r, nField, row, table_val, column_val; + UINT r, nField; static const WCHAR szTables[] = { '_','T','a','b','l','e','s',0 }; static const WCHAR szColumns[] = { '_','C','o','l','u','m','n','s',0 }; MSIVIEW *tv = NULL; + MSIRECORD *rec; TRACE("%p Table %s (%s)\n", cv, debugstr_w(cv->name), cv->bIsTemp?"temporary":"permanent"); @@ -72,12 +73,6 @@ static UINT CREATE_execute( struct tagMSIVIEW *view, MSIRECORD *record ) if( TABLE_Exists(cv->db, cv->name ) ) return ERROR_BAD_QUERY_SYNTAX; - /* add the name to the _Tables table */ - table_val = msi_addstringW( cv->db->strings, 0, cv->name, -1, 1 ); - TRACE("New string %s -> %d\n", debugstr_w( cv->name ), table_val ); - if( table_val < 0 ) - return ERROR_FUNCTION_FAILED; - r = TABLE_CreateView( cv->db, szTables, &tv ); TRACE("CreateView returned %x\n", r); if( r ) @@ -86,20 +81,26 @@ static UINT CREATE_execute( struct tagMSIVIEW *view, MSIRECORD *record ) r = tv->ops->execute( tv, 0 ); TRACE("tv execute returned %x\n", r); if( r ) - return r; + goto err; - row = -1; - r = tv->ops->insert_row( tv, &row ); + rec = MSI_CreateRecord( 1 ); + if( !rec ) + goto err; + + r = MSI_RecordSetStringW( rec, 1, cv->name ); + if( r ) + goto err; + + r = tv->ops->insert_row( tv, rec ); TRACE("insert_row returned %x\n", r); if( r ) goto err; - r = tv->ops->set_int( tv, row, 1, table_val ); - if( r ) - goto err; tv->ops->delete( tv ); tv = NULL; + msiobj_release( &rec->hdr ); + /* add each column to the _Columns table */ r = TABLE_CreateView( cv->db, szColumns, &tv ); if( r ) @@ -108,7 +109,15 @@ static UINT CREATE_execute( struct tagMSIVIEW *view, MSIRECORD *record ) r = tv->ops->execute( tv, 0 ); TRACE("tv execute returned %x\n", r); if( r ) - return r; + goto err; + + rec = MSI_CreateRecord( 4 ); + if( !rec ) + goto err; + + r = MSI_RecordSetStringW( rec, 1, cv->name ); + if( r ) + goto err; /* * need to set the table, column number, col name and type @@ -117,36 +126,21 @@ static UINT CREATE_execute( struct tagMSIVIEW *view, MSIRECORD *record ) nField = 1; for( col = cv->col_info; col; col = col->next ) { - row = -1; - r = tv->ops->insert_row( tv, &row ); + r = MSI_RecordSetInteger( rec, 2, nField ); if( r ) goto err; - column_val = msi_addstringW( cv->db->strings, 0, col->column, -1, 1 ); - TRACE("New string %s -> %d\n", debugstr_w( col->column ), column_val ); - if( column_val < 0 ) - break; - - /* add the string again here so we increase the reference count */ - table_val = msi_addstringW( cv->db->strings, 0, cv->name, -1, 1 ); - if( table_val < 0 ) - break; - - r = tv->ops->set_int( tv, row, 1, table_val ); + r = MSI_RecordSetStringW( rec, 3, col->column ); if( r ) - break; + goto err; - r = tv->ops->set_int( tv, row, 2, 0x8000|nField ); + r = MSI_RecordSetInteger( rec, 4, col->type ); if( r ) - break; + goto err; - r = tv->ops->set_int( tv, row, 3, column_val ); + r = tv->ops->insert_row( tv, rec ); if( r ) - break; - - r = tv->ops->set_int( tv, row, 4, 0x8000|col->type ); - if( r ) - break; + goto err; nField++; } diff --git a/dlls/msi/delete.c b/dlls/msi/delete.c index fdb1c00c4fd..46eab5fd826 100644 --- a/dlls/msi/delete.c +++ b/dlls/msi/delete.c @@ -82,11 +82,11 @@ static UINT DELETE_set_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT va return ERROR_FUNCTION_FAILED; } -static UINT DELETE_insert_row( struct tagMSIVIEW *view, UINT *num ) +static UINT DELETE_insert_row( struct tagMSIVIEW *view, MSIRECORD *record ) { MSIDELETEVIEW *dv = (MSIDELETEVIEW*)view; - TRACE("%p %p\n", dv, num ); + TRACE("%p %p\n", dv, record ); return ERROR_FUNCTION_FAILED; } diff --git a/dlls/msi/insert.c b/dlls/msi/insert.c index c3932907a15..7e317bb30ce 100644 --- a/dlls/msi/insert.c +++ b/dlls/msi/insert.c @@ -109,7 +109,7 @@ err: static UINT INSERT_execute( struct tagMSIVIEW *view, MSIRECORD *record ) { MSIINSERTVIEW *iv = (MSIINSERTVIEW*)view; - UINT n, type, val, r, row, col_count = 0; + UINT r, col_count = 0; MSIVIEW *sv; MSIRECORD *values = NULL; @@ -136,38 +136,13 @@ static UINT INSERT_execute( struct tagMSIVIEW *view, MSIRECORD *record ) if( !values ) goto err; - row = -1; - r = sv->ops->insert_row( sv, &row ); - TRACE("insert_row returned %x\n", r); - if( r ) - goto err; - - for( n = 1; n <= col_count; n++ ) - { - r = sv->ops->get_column_info( sv, n, NULL, &type ); - if( r ) - break; - - if( type & MSITYPE_STRING ) - { - const WCHAR *str = MSI_RecordGetString( values, n ); - val = msi_addstringW( iv->db->strings, 0, str, -1, 1 ); - } - else - { - val = MSI_RecordGetInteger( values, n ); - val |= 0x8000; - } - r = sv->ops->set_int( sv, row, n, val ); - if( r ) - break; - } + r = sv->ops->insert_row( sv, values ); err: if( values ) msiobj_release( &values->hdr ); - return ERROR_SUCCESS; + return r; } diff --git a/dlls/msi/msipriv.h b/dlls/msi/msipriv.h index 95f7ebcd6c6..e98dc32997d 100644 --- a/dlls/msi/msipriv.h +++ b/dlls/msi/msipriv.h @@ -129,10 +129,9 @@ typedef struct tagMSIVIEWOPS UINT (*set_int)( struct tagMSIVIEW *, UINT row, UINT col, UINT val ); /* - * Inserts a new, blank row into the database - * *row receives the number of the new row + * Inserts a new row into the database from the records contents */ - UINT (*insert_row)( struct tagMSIVIEW *, UINT *row ); + UINT (*insert_row)( struct tagMSIVIEW *, MSIRECORD * ); /* * execute - loads the underlying data into memory so it can be read diff --git a/dlls/msi/select.c b/dlls/msi/select.c index 9378676f719..0ab500f2f15 100644 --- a/dlls/msi/select.c +++ b/dlls/msi/select.c @@ -99,16 +99,16 @@ static UINT SELECT_set_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT va return sv->table->ops->set_int( sv->table, row, col, val ); } -static UINT SELECT_insert_row( struct tagMSIVIEW *view, UINT *num ) +static UINT SELECT_insert_row( struct tagMSIVIEW *view, MSIRECORD *record ) { MSISELECTVIEW *sv = (MSISELECTVIEW*)view; - TRACE("%p %p\n", sv, num ); + TRACE("%p %p\n", sv, record ); if( !sv->table ) return ERROR_FUNCTION_FAILED; - return sv->table->ops->insert_row( sv->table, num ); + return sv->table->ops->insert_row( sv->table, record ); } static UINT SELECT_execute( struct tagMSIVIEW *view, MSIRECORD *record ) diff --git a/dlls/msi/table.c b/dlls/msi/table.c index b8bb8de1170..806211ab4d4 100644 --- a/dlls/msi/table.c +++ b/dlls/msi/table.c @@ -1192,7 +1192,7 @@ static UINT TABLE_set_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT val return ERROR_SUCCESS; } -static UINT TABLE_insert_row( struct tagMSIVIEW *view, UINT *num ) +static UINT table_create_new_row( struct tagMSIVIEW *view, UINT *num ) { MSITABLEVIEW *tv = (MSITABLEVIEW*)view; USHORT **p, *row; @@ -1242,7 +1242,7 @@ static UINT TABLE_execute( struct tagMSIVIEW *view, MSIRECORD *record ) r = get_table( tv->db, tv->name, &tv->table ); if( r != ERROR_SUCCESS ) return r; - + return ERROR_SUCCESS; } @@ -1301,11 +1301,155 @@ static UINT TABLE_get_column_info( struct tagMSIVIEW *view, return ERROR_SUCCESS; } +static UINT table_find_in_column( MSITABLEVIEW *tv, UINT col, UINT val, UINT *row ) +{ + UINT i, r, x; + + for( i=0; itable->row_count; i++ ) + { + r = TABLE_fetch_int( (struct tagMSIVIEW*) tv, i, col, &x ); + if ( r != ERROR_SUCCESS ) + { + ERR("TABLE_fetch_int shouldn't fail here\n"); + break; + } + if ( x == val ) + { + *row = i; + return ERROR_SUCCESS; + } + } + return ERROR_FUNCTION_FAILED; +} + +static UINT table_validate_new( MSITABLEVIEW *tv, MSIRECORD *rec ) +{ + LPCWSTR str; + UINT i, val, r, row; + + /* FIXME: set the MsiViewGetError value */ + + for( i = 0; inum_cols; i++ ) + { + /* check for duplicate keys */ + if( !( tv->columns[i].type & MSITYPE_KEY ) ) + continue; + + TRACE("column %d (%s.%s)is a key\n", i, + debugstr_w(tv->columns[i].tablename), + debugstr_w(tv->columns[i].colname) ); + + val = 0; + if( tv->columns[i].type & MSITYPE_STRING ) + { + /* keys can't be null */ + str = MSI_RecordGetString( rec, i+1 ); + if( !str ) + return ERROR_INVALID_DATA; + + /* if the string doesn't exist in the string table yet, it's OK */ + r = msi_string2idW( tv->db->strings, str, &val ); + if( ERROR_SUCCESS != r ) + continue; + } + else + { + val = MSI_RecordGetInteger( rec, i+1 ); + val ^= 0x8000; + } + + /* if we find the same value in the table, it's a duplicate */ + row = 0; + r = table_find_in_column( tv, i+1, val, &row ); + if( ERROR_SUCCESS == r ) + { + TRACE("found in row %d\n", row ); + return ERROR_INVALID_DATA; + } + } + + return ERROR_SUCCESS; +} + +static UINT TABLE_insert_row( struct tagMSIVIEW *view, MSIRECORD *rec ) +{ + MSITABLEVIEW *tv = (MSITABLEVIEW*)view; + UINT n, type, val, r, row, col_count = 0; + + r = TABLE_get_dimensions( view, NULL, &col_count ); + if( r ) + return r; + + row = -1; + r = table_create_new_row( view, &row ); + TRACE("insert_row returned %08x\n", r); + if( r ) + return r; + + for( n = 1; n <= col_count; n++ ) + { + r = TABLE_get_column_info( view, n, NULL, &type ); + if( r ) + break; + + if( type & MSITYPE_STRING ) + { + const WCHAR *str = MSI_RecordGetString( rec, n ); + val = msi_addstringW( tv->db->strings, 0, str, -1, 1 ); + } + else + { + val = MSI_RecordGetInteger( rec, n ); + val ^= 0x8000; + } + r = TABLE_set_int( view, row, n, val ); + if( r ) + break; + } + + return r; +} + static UINT TABLE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, MSIRECORD *rec) { - FIXME("%p %d %p\n", view, eModifyMode, rec ); - return ERROR_CALL_NOT_IMPLEMENTED; + MSITABLEVIEW *tv = (MSITABLEVIEW*)view; + UINT r; + + TRACE("%p %d %p\n", view, eModifyMode, rec ); + + switch (eModifyMode) + { + case MSIMODIFY_VALIDATE_NEW: + r = table_validate_new( tv, rec ); + break; + + case MSIMODIFY_INSERT_TEMPORARY: + r = table_validate_new( tv, rec ); + if (r != ERROR_SUCCESS) + break; + r = TABLE_insert_row( view, rec ); + break; + + case MSIMODIFY_REFRESH: + case MSIMODIFY_INSERT: + case MSIMODIFY_UPDATE: + case MSIMODIFY_ASSIGN: + case MSIMODIFY_REPLACE: + case MSIMODIFY_MERGE: + case MSIMODIFY_DELETE: + case MSIMODIFY_VALIDATE: + case MSIMODIFY_VALIDATE_FIELD: + case MSIMODIFY_VALIDATE_DELETE: + FIXME("%p %d %p - mode not implemented\n", view, eModifyMode, rec ); + r = ERROR_CALL_NOT_IMPLEMENTED; + break; + + default: + r = ERROR_INVALID_DATA; + } + + return r; } static UINT TABLE_delete( struct tagMSIVIEW *view )