UINT type;
UINT offset;
INT ref_count;
+ BOOL temporary;
MSICOLUMNHASHENTRY **hash_table;
} MSICOLUMNINFO;
struct tagMSITABLE
{
BYTE **data;
+ BOOL *data_persistent;
UINT row_count;
- BYTE **nonpersistent_data;
- UINT nonpersistent_row_count;
struct list entry;
MSICOLUMNINFO *colinfo;
UINT col_count;
- BOOL persistent;
+ MSICONDITION persistent;
INT ref_count;
WCHAR name[1];
};
static WCHAR szType[] = { 'T','y','p','e',0 };
static const MSICOLUMNINFO _Columns_cols[4] = {
- { szColumns, 1, szTable, MSITYPE_VALID | MSITYPE_STRING | MSITYPE_KEY | 64, 0, 0, NULL },
- { szColumns, 2, szNumber, MSITYPE_VALID | MSITYPE_KEY | 2, 2, 0, NULL },
- { szColumns, 3, szName, MSITYPE_VALID | MSITYPE_STRING | 64, 4, 0, NULL },
- { szColumns, 4, szType, MSITYPE_VALID | 2, 6, 0, NULL },
+ { szColumns, 1, szTable, MSITYPE_VALID | MSITYPE_STRING | MSITYPE_KEY | 64, 0, 0, 0, NULL },
+ { szColumns, 2, szNumber, MSITYPE_VALID | MSITYPE_KEY | 2, 2, 0, 0, NULL },
+ { szColumns, 3, szName, MSITYPE_VALID | MSITYPE_STRING | 64, 4, 0, 0, NULL },
+ { szColumns, 4, szType, MSITYPE_VALID | 2, 6, 0, 0, NULL },
};
static const MSICOLUMNINFO _Tables_cols[1] = {
- { szTables, 1, szName, MSITYPE_VALID | MSITYPE_STRING | MSITYPE_KEY | 64, 0, 0, NULL },
+ { szTables, 1, szName, MSITYPE_VALID | MSITYPE_STRING | MSITYPE_KEY | 64, 0, 0, 0, NULL },
};
#define MAX_STREAM_NAME 0x1f
static UINT get_tablecolumns( MSIDATABASE *db,
LPCWSTR szTableName, MSICOLUMNINFO *colinfo, UINT *sz);
static void msi_free_colinfo( MSICOLUMNINFO *colinfo, UINT count );
+static UINT table_find_insert_idx (MSIVIEW *view, LPCWSTR name, INT *pidx);
static inline UINT bytes_per_column( MSIDATABASE *db, const MSICOLUMNINFO *col )
{
if( MSITYPE_IS_BINARY(col->type) )
return 2;
+
if( col->type & MSITYPE_STRING )
return db->bytes_per_strref;
- if( (col->type & 0xff) > 4 )
+
+ if( (col->type & 0xff) <= 2)
+ return 2;
+
+ if( (col->type & 0xff) != 4 )
ERR("Invalid column size!\n");
- return col->type & 0xff;
+
+ return 4;
}
static int utf2mime(int x)
for( i=0; i<table->row_count; i++ )
msi_free( table->data[i] );
msi_free( table->data );
- for( i=0; i<table->nonpersistent_row_count; i++ )
- msi_free( table->nonpersistent_data[i] );
- msi_free( table->nonpersistent_data );
+ msi_free( table->data_persistent );
msi_free_colinfo( table->colinfo, table->col_count );
msi_free( table->colinfo );
msi_free( table );
t->data = msi_alloc_zero( t->row_count * sizeof (USHORT*) );
if( !t->data )
goto err;
+ t->data_persistent = msi_alloc_zero( t->row_count * sizeof(BOOL));
+ if ( !t->data_persistent )
+ goto err;
/* transpose all the data */
TRACE("Transposing data from %d rows\n", t->row_count );
t->data[i] = msi_alloc( row_size );
if( !t->data[i] )
goto err;
+ t->data_persistent[i] = TRUE;
for( j=0; j<t->col_count; j++ )
{
}
UINT msi_create_table( MSIDATABASE *db, LPCWSTR name, column_info *col_info,
- BOOL persistent, MSITABLE **table_ret)
+ MSICONDITION persistent, MSITABLE **table_ret)
{
UINT r, nField;
MSIVIEW *tv = NULL;
column_info *col;
MSITABLE *table;
UINT i;
+ INT idx;
/* only add tables that don't exist already */
if( TABLE_Exists(db, name ) )
table->ref_count = 1;
table->row_count = 0;
table->data = NULL;
- table->nonpersistent_row_count = 0;
- table->nonpersistent_data = NULL;
+ table->data_persistent = NULL;
table->colinfo = NULL;
table->col_count = 0;
table->persistent = persistent;
table->colinfo[ i ].offset = 0;
table->colinfo[ i ].ref_count = 0;
table->colinfo[ i ].hash_table = NULL;
+ table->colinfo[ i ].temporary = col->temporary;
}
table_calc_column_offsets( db, table->colinfo, table->col_count);
if( r )
goto err;
- r = tv->ops->insert_row( tv, rec, !persistent );
+ r = table_find_insert_idx (tv, name, &idx);
+ if (r != ERROR_SUCCESS)
+ idx = -1;
+
+ r = tv->ops->insert_row( tv, rec, idx, persistent == MSICONDITION_FALSE );
TRACE("insert_row returned %x\n", r);
if( r )
goto err;
msiobj_release( &rec->hdr );
rec = NULL;
- if( persistent )
+ if( persistent != MSICONDITION_FALSE )
{
/* add each column to the _Columns table */
r = TABLE_CreateView( db, szColumns, &tv );
if( r )
goto err;
- r = tv->ops->insert_row( tv, rec, FALSE );
+ r = table_find_insert_idx (tv, name, &idx);
+ if (r != ERROR_SUCCESS)
+ idx = -1;
+
+ r = tv->ops->insert_row( tv, rec, idx, FALSE );
if( r )
goto err;
table->row_count = 0;
table->data = NULL;
- table->nonpersistent_row_count = 0;
- table->nonpersistent_data = NULL;
+ table->data_persistent = NULL;
table->colinfo = NULL;
table->col_count = 0;
- table->persistent = TRUE;
+ table->persistent = MSICONDITION_TRUE;
lstrcpyW( table->name, name );
+ if ( !lstrcmpW(name, szTables) || !lstrcmpW(name, szColumns) )
+ table->persistent = MSICONDITION_NONE;
+
r = table_get_column_info( db, name, &table->colinfo, &table->col_count);
if (r != ERROR_SUCCESS)
{
UINT rawsize, r, i, j, row_size;
/* Nothing to do for non-persistent tables */
- if( !t->persistent )
+ if( t->persistent == MSICONDITION_FALSE )
return ERROR_SUCCESS;
TRACE("Saving %s\n", debugstr_w( t->name ) );
goto err;
}
+ rawsize = 0;
p = rawdata;
for( i=0; i<t->col_count; i++ )
{
{
UINT offset = t->colinfo[i].offset;
+ if (!t->data_persistent[j]) continue;
+ if (i == 0)
+ rawsize += row_size;
+
*p++ = t->data[j][offset];
*p++ = t->data[j][offset + 1];
if( 4 == bytes_per_column( db, &t->colinfo[i] ) )
table = find_cached_table( db, name );
old_count = table->col_count;
msi_free( table->colinfo );
- table_get_column_info( db, name, &table->colinfo, &table->col_count );
+ table->colinfo = NULL;
+ table_get_column_info( db, name, &table->colinfo, &table->col_count );
if (!table->col_count)
return;
UINT r, table_id = 0, i, count;
MSITABLE *table = NULL;
- if( !lstrcmpW( name, szTables ) )
- return TRUE;
- if( !lstrcmpW( name, szColumns ) )
+ static const WCHAR szStreams[] = {'_','S','t','r','e','a','m','s',0};
+ static const WCHAR szStorages[] = {'_','S','t','o','r','a','g','e','s',0};
+
+ if( !lstrcmpW( name, szTables ) || !lstrcmpW( name, szColumns ) ||
+ !lstrcmpW( name, szStreams ) || !lstrcmpW( name, szStorages ) )
return TRUE;
r = msi_string2idW( db->strings, name, &table_id );
if( table->data[ i ][ 0 ] == table_id )
return TRUE;
- count = table->nonpersistent_row_count;
- for( i=0; i<count; i++ )
- if( table->nonpersistent_data[ i ][ 0 ] == table_id )
- return TRUE;
-
return FALSE;
}
{
MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
UINT offset, n;
- BYTE **data;
if( !tv->table )
return ERROR_INVALID_PARAMETER;
return ERROR_INVALID_PARAMETER;
/* how many rows are there ? */
- if( row >= tv->table->row_count + tv->table->nonpersistent_row_count )
+ if( row >= tv->table->row_count )
return ERROR_NO_MORE_ITEMS;
if( tv->columns[col-1].offset >= tv->row_size )
if (tv->order)
row = tv->order->reorder[row];
- if (row >= tv->table->row_count)
- {
- row -= tv->table->row_count;
- data = tv->table->nonpersistent_data;
- }
- else
- data = tv->table->data;
-
n = bytes_per_column( tv->db, &tv->columns[col-1] );
if (n != 2 && n != 3 && n != 4)
{
}
offset = tv->columns[col-1].offset;
- *val = read_table_int(data, row, offset, n);
+ *val = read_table_int(tv->table->data, row, offset, n);
/* TRACE("Data [%d][%d] = %d\n", row, col, *val ); */
return ERROR_SUCCESS;
}
+static UINT msi_stream_name( const MSITABLEVIEW *tv, UINT row, LPWSTR *pstname )
+{
+ LPWSTR p, stname = NULL;
+ UINT i, r, type, ival;
+ DWORD len;
+ LPCWSTR sval;
+ MSIVIEW *view = (MSIVIEW *) tv;
+
+ TRACE("%p %d\n", tv, row);
+
+ len = lstrlenW( tv->name ) + 1;
+ stname = msi_alloc( len*sizeof(WCHAR) );
+ if ( !stname )
+ {
+ r = ERROR_OUTOFMEMORY;
+ goto err;
+ }
+
+ lstrcpyW( stname, tv->name );
+
+ for ( i = 0; i < tv->num_cols; i++ )
+ {
+ type = tv->columns[i].type;
+ if ( type & MSITYPE_KEY )
+ {
+ static const WCHAR szDot[] = { '.', 0 };
+
+ r = TABLE_fetch_int( view, row, i+1, &ival );
+ if ( r != ERROR_SUCCESS )
+ goto err;
+
+ if ( tv->columns[i].type & MSITYPE_STRING )
+ {
+ sval = msi_string_lookup_id( tv->db->strings, ival );
+ if ( !sval )
+ {
+ r = ERROR_INVALID_PARAMETER;
+ goto err;
+ }
+ }
+ else
+ {
+ static const WCHAR fmt[] = { '%','d',0 };
+ WCHAR number[0x20];
+ UINT n = bytes_per_column( tv->db, &tv->columns[i] );
+
+ switch( n )
+ {
+ case 2:
+ sprintfW( number, fmt, ival^0x8000 );
+ break;
+ case 4:
+ sprintfW( number, fmt, ival^0x80000000 );
+ break;
+ default:
+ ERR( "oops - unknown column width %d\n", n );
+ r = ERROR_FUNCTION_FAILED;
+ goto err;
+ }
+ sval = number;
+ }
+
+ len += lstrlenW( szDot ) + lstrlenW( sval );
+ p = msi_realloc ( stname, len*sizeof(WCHAR) );
+ if ( !p )
+ {
+ r = ERROR_OUTOFMEMORY;
+ goto err;
+ }
+ stname = p;
+
+ lstrcatW( stname, szDot );
+ lstrcatW( stname, sval );
+ }
+ else
+ continue;
+ }
+
+ *pstname = stname;
+ return ERROR_SUCCESS;
+
+err:
+ msi_free( stname );
+ *pstname = NULL;
+ return r;
+}
+
/*
* We need a special case for streams, as we need to reference column with
* the name of the stream in the same table, and the table name
static UINT TABLE_fetch_stream( struct tagMSIVIEW *view, UINT row, UINT col, IStream **stm )
{
MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
- UINT ival = 0, refcol = 0, r;
- LPCWSTR sval;
- LPWSTR full_name;
- DWORD len;
- static const WCHAR szDot[] = { '.', 0 };
- WCHAR number[0x20];
+ UINT r;
+ LPWSTR full_name = NULL;
if( !view->ops->fetch_int )
return ERROR_INVALID_PARAMETER;
- /*
- * The column marked with the type stream data seems to have a single number
- * which references the column containing the name of the stream data
- *
- * Fetch the column to reference first.
- */
- r = view->ops->fetch_int( view, row, col, &ival );
- if( r != ERROR_SUCCESS )
- return r;
-
- /* check the column value is in range */
- if (ival > tv->num_cols || ival == col)
- {
- ERR("bad column ref (%u) for stream\n", ival);
- return ERROR_FUNCTION_FAILED;
- }
-
- if ( tv->columns[ival - 1].type & MSITYPE_STRING )
- {
- /* now get the column with the name of the stream */
- r = view->ops->fetch_int( view, row, ival, &refcol );
- if ( r != ERROR_SUCCESS )
- return r;
-
- /* lookup the string value from the string table */
- sval = msi_string_lookup_id( tv->db->strings, refcol );
- if ( !sval )
- return ERROR_INVALID_PARAMETER;
- }
- else
+ r = msi_stream_name( tv, row, &full_name );
+ if ( r != ERROR_SUCCESS )
{
- static const WCHAR fmt[] = { '%','d',0 };
- sprintfW( number, fmt, ival );
- sval = number;
+ ERR("fetching stream, error = %d\n", r);
+ return r;
}
- len = lstrlenW( tv->name ) + 2 + lstrlenW( sval );
- full_name = msi_alloc( len*sizeof(WCHAR) );
- lstrcpyW( full_name, tv->name );
- lstrcatW( full_name, szDot );
- lstrcatW( full_name, sval );
-
r = db_get_raw_stream( tv->db, full_name, stm );
if( r )
ERR("fetching stream %s, error = %d\n",debugstr_w(full_name), r);
static UINT TABLE_set_int( MSITABLEVIEW *tv, UINT row, UINT col, UINT val )
{
UINT offset, n, i;
- BYTE **data;
if( !tv->table )
return ERROR_INVALID_PARAMETER;
if( (col==0) || (col>tv->num_cols) )
return ERROR_INVALID_PARAMETER;
- if( row >= tv->table->row_count + tv->table->nonpersistent_row_count )
+ if( row >= tv->table->row_count )
return ERROR_INVALID_PARAMETER;
if( tv->columns[col-1].offset >= tv->row_size )
msi_free( tv->columns[col-1].hash_table );
tv->columns[col-1].hash_table = NULL;
- if (row >= tv->table->row_count)
- {
- row -= tv->table->row_count;
- data = tv->table->nonpersistent_data;
- }
- else
- data = tv->table->data;
-
n = bytes_per_column( tv->db, &tv->columns[col-1] );
if ( n != 2 && n != 3 && n != 4 )
{
offset = tv->columns[col-1].offset;
for ( i = 0; i < n; i++ )
- data[row][offset + i] = (val >> i * 8) & 0xff;
+ tv->table->data[row][offset + i] = (val >> i * 8) & 0xff;
return ERROR_SUCCESS;
}
return msi_view_get_row(tv->db, view, row, rec);
}
+static UINT msi_addstreamW( MSIDATABASE *db, LPCWSTR name, IStream *data )
+{
+ UINT r;
+ MSIQUERY *query = NULL;
+ MSIRECORD *rec = NULL;
+
+ static const WCHAR insert[] = {
+ 'I','N','S','E','R','T',' ','I','N','T','O',' ',
+ '`','_','S','t','r','e','a','m','s','`',' ',
+ '(','`','N','a','m','e','`',',',
+ '`','D','a','t','a','`',')',' ',
+ 'V','A','L','U','E','S',' ','(','?',',','?',')',0};
+
+ TRACE("%p %s %p\n", db, debugstr_w(name), data);
+
+ rec = MSI_CreateRecord( 2 );
+ if ( !rec )
+ return ERROR_OUTOFMEMORY;
+
+ r = MSI_RecordSetStringW( rec, 1, name );
+ if ( r != ERROR_SUCCESS )
+ goto err;
+
+ r = MSI_RecordSetIStream( rec, 2, data );
+ if ( r != ERROR_SUCCESS )
+ goto err;
+
+ r = MSI_DatabaseOpenViewW( db, insert, &query );
+ if ( r != ERROR_SUCCESS )
+ goto err;
+
+ r = MSI_ViewExecute( query, rec );
+
+err:
+ msiobj_release( &query->hdr );
+ msiobj_release( &rec->hdr );
+
+ return r;
+}
+
static UINT TABLE_set_row( struct tagMSIVIEW *view, UINT row, MSIRECORD *rec, UINT mask )
{
MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
if ( !(mask&(1<<i)) )
continue;
- /* if row >= tv->table->row_count then it is a non-persistent row */
- persistent = tv->table->persistent && (row < tv->table->row_count);
+ persistent = (tv->table->persistent != MSICONDITION_FALSE) &&
+ (tv->table->data_persistent[row]);
/* FIXME: should we allow updating keys? */
val = 0;
{
if ( MSITYPE_IS_BINARY(tv->columns[ i ].type) )
{
+ IStream *stm;
+ LPWSTR stname;
+
+ r = MSI_RecordGetIStream( rec, i + 1, &stm );
+ if ( r != ERROR_SUCCESS )
+ return r;
+
+ r = msi_stream_name( tv, row, &stname );
+ if ( r != ERROR_SUCCESS )
+ {
+ IStream_Release( stm );
+ return r;
+ }
+
+ r = msi_addstreamW( tv->db, stname, stm );
+ IStream_Release( stm );
+ msi_free ( stname );
+
+ if ( r != ERROR_SUCCESS )
+ return r;
+
val = 1; /* refers to the first key column */
}
else if ( tv->columns[i].type & MSITYPE_STRING )
{
MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
BYTE **p, *row;
+ BOOL *b;
UINT sz;
BYTE ***data_ptr;
+ BOOL **data_persist_ptr;
UINT *row_count;
TRACE("%p %s\n", view, temporary ? "TRUE" : "FALSE");
if( !row )
return ERROR_NOT_ENOUGH_MEMORY;
- if( temporary )
- {
- row_count = &tv->table->nonpersistent_row_count;
- data_ptr = &tv->table->nonpersistent_data;
- *num = tv->table->row_count + tv->table->nonpersistent_row_count;
- }
- else
- {
- row_count = &tv->table->row_count;
- data_ptr = &tv->table->data;
+ row_count = &tv->table->row_count;
+ data_ptr = &tv->table->data;
+ data_persist_ptr = &tv->table->data_persistent;
+ if (*num == -1)
*num = tv->table->row_count;
- }
sz = (*row_count + 1) * sizeof (BYTE*);
if( *data_ptr )
return ERROR_NOT_ENOUGH_MEMORY;
}
+ sz = (*row_count + 1) * sizeof (BOOL);
+ if( *data_persist_ptr )
+ b = msi_realloc( *data_persist_ptr, sz );
+ else
+ b = msi_alloc( sz );
+ if( !b )
+ {
+ msi_free( row );
+ msi_free( p );
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
*data_ptr = p;
(*data_ptr)[*row_count] = row;
+
+ *data_persist_ptr = b;
+ (*data_persist_ptr)[*row_count] = !temporary;
+
(*row_count)++;
return ERROR_SUCCESS;
{
if( !tv->table )
return ERROR_INVALID_PARAMETER;
- *rows = tv->table->row_count + tv->table->nonpersistent_row_count;
+ *rows = tv->table->row_count;
}
return ERROR_SUCCESS;
}
static UINT TABLE_get_column_info( struct tagMSIVIEW *view,
- UINT n, LPWSTR *name, UINT *type )
+ UINT n, LPWSTR *name, UINT *type, BOOL *temporary )
{
MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
if( !*name )
return ERROR_FUNCTION_FAILED;
}
+
if( type )
*type = tv->columns[n-1].type;
+ if( temporary )
+ *temporary = tv->columns[n-1].temporary;
+
return ERROR_SUCCESS;
}
return ERROR_SUCCESS;
}
-static UINT TABLE_insert_row( struct tagMSIVIEW *view, MSIRECORD *rec, BOOL temporary )
+static UINT TABLE_insert_row( struct tagMSIVIEW *view, MSIRECORD *rec, UINT row, BOOL temporary )
{
MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
- UINT r, row = -1;
+ UINT i, r;
TRACE("%p %p %s\n", tv, rec, temporary ? "TRUE" : "FALSE" );
if( r != ERROR_SUCCESS )
return r;
+ /* shift the rows to make room for the new row */
+ for (i = tv->table->row_count - 1; i > row; i--)
+ {
+ memmove(&(tv->table->data[i][0]),
+ &(tv->table->data[i - 1][0]), tv->row_size);
+ tv->table->data_persistent[i] = tv->table->data_persistent[i - 1];
+ }
+
+ /* Re-set the persistence flag */
+ tv->table->data_persistent[row] = !temporary;
return TABLE_set_row( view, row, rec, (1<<tv->num_cols) - 1 );
}
{
MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
UINT r, num_rows, num_cols, i;
- BYTE **data;
TRACE("%p %d\n", tv, row);
if ( row >= num_rows )
return ERROR_FUNCTION_FAILED;
- if ( row < tv->table->row_count )
- {
- num_rows = tv->table->row_count;
- tv->table->row_count--;
- data = tv->table->data;
- }
- else
- {
- num_rows = tv->table->nonpersistent_row_count;
- row -= tv->table->row_count;
- tv->table->nonpersistent_row_count--;
- data = tv->table->nonpersistent_data;
- }
+ num_rows = tv->table->row_count;
+ tv->table->row_count--;
/* reset the hash tables */
for (i = 0; i < tv->num_cols; i++)
return ERROR_SUCCESS;
for (i = row + 1; i < num_rows; i++)
- memcpy(data[i - 1], data[i], tv->row_size);
+ {
+ memcpy(tv->table->data[i - 1], tv->table->data[i], tv->row_size);
+ tv->table->data_persistent[i - 1] = tv->table->data_persistent[i];
+ }
return ERROR_SUCCESS;
}
return TABLE_set_row(view, new_row, rec, (1 << tv->num_cols) - 1);
}
+static UINT msi_table_assign(struct tagMSIVIEW *view, MSIRECORD *rec)
+{
+ MSITABLEVIEW *tv = (MSITABLEVIEW *)view;
+ UINT r, row;
+
+ if (!tv->table)
+ return ERROR_INVALID_PARAMETER;
+
+ r = msi_table_find_row(tv, rec, &row);
+ if (r == ERROR_SUCCESS)
+ return TABLE_set_row(view, row, rec, (1 << tv->num_cols) - 1);
+ else
+ return TABLE_insert_row( view, rec, -1, FALSE );
+}
+
static UINT modify_delete_row( struct tagMSIVIEW *view, MSIRECORD *rec )
{
MSITABLEVIEW *tv = (MSITABLEVIEW *)view;
r = table_validate_new( tv, rec );
if (r != ERROR_SUCCESS)
break;
- r = TABLE_insert_row( view, rec, FALSE );
+ r = TABLE_insert_row( view, rec, -1, FALSE );
break;
case MSIMODIFY_INSERT_TEMPORARY:
r = table_validate_new( tv, rec );
if (r != ERROR_SUCCESS)
break;
- r = TABLE_insert_row( view, rec, TRUE );
+ r = TABLE_insert_row( view, rec, -1, TRUE );
break;
case MSIMODIFY_REFRESH:
break;
case MSIMODIFY_ASSIGN:
+ r = msi_table_assign( view, rec );
+ break;
+
case MSIMODIFY_REPLACE:
case MSIMODIFY_MERGE:
case MSIMODIFY_VALIDATE:
if( !tv->columns[col-1].hash_table )
{
UINT i;
- UINT num_rows = tv->table->row_count + tv->table->nonpersistent_row_count;
+ UINT num_rows = tv->table->row_count;
MSICOLUMNHASHENTRY **hash_table;
MSICOLUMNHASHENTRY *new_entry;
done:
msiobj_release(&rec->hdr);
- if (columns) columns->ops->delete(columns);
+ columns->ops->delete(columns);
return r;
}
MSI_RecordSetStringW(rec, 3, column);
MSI_RecordSetInteger(rec, 4, type);
- r = TABLE_insert_row(&tv->view, rec, FALSE);
+ r = TABLE_insert_row(&tv->view, rec, -1, FALSE);
if (r != ERROR_SUCCESS)
goto done;
if (r != ERROR_SUCCESS)
return MSICONDITION_NONE;
- if (t->persistent)
- return MSICONDITION_TRUE;
- else
- return MSICONDITION_FALSE;
+ return t->persistent;
}
static UINT read_raw_int(const BYTE *data, UINT col, UINT bytes)
return ret;
}
+static UINT msi_record_encoded_stream_name( const MSITABLEVIEW *tv, MSIRECORD *rec, LPWSTR *pstname )
+{
+ static const WCHAR szDot[] = { '.', 0 };
+ LPWSTR stname = NULL, sval, p;
+ DWORD len;
+ UINT i, r;
+
+ TRACE("%p %p\n", tv, rec);
+
+ len = lstrlenW( tv->name ) + 1;
+ stname = msi_alloc( len*sizeof(WCHAR) );
+ if ( !stname )
+ {
+ r = ERROR_OUTOFMEMORY;
+ goto err;
+ }
+
+ lstrcpyW( stname, tv->name );
+
+ for ( i = 0; i < tv->num_cols; i++ )
+ {
+ if ( tv->columns[i].type & MSITYPE_KEY )
+ {
+ sval = msi_dup_record_field( rec, i + 1 );
+ if ( !sval )
+ {
+ r = ERROR_OUTOFMEMORY;
+ goto err;
+ }
+
+ len += lstrlenW( szDot ) + lstrlenW ( sval );
+ p = msi_realloc ( stname, len*sizeof(WCHAR) );
+ if ( !p )
+ {
+ r = ERROR_OUTOFMEMORY;
+ goto err;
+ }
+ stname = p;
+
+ lstrcatW( stname, szDot );
+ lstrcatW( stname, sval );
+
+ msi_free( sval );
+ }
+ else
+ continue;
+ }
+
+ *pstname = encode_streamname( FALSE, stname );
+ msi_free( stname );
+
+ return ERROR_SUCCESS;
+
+err:
+ msi_free ( stname );
+ *pstname = NULL;
+ return r;
+}
+
static MSIRECORD *msi_get_transform_record( const MSITABLEVIEW *tv, const string_table *st,
+ IStorage *stg,
const BYTE *rawdata, UINT bytes_per_strref )
{
UINT i, val, ofs = 0;
if ( (~mask&1) && (~columns[i].type & MSITYPE_KEY) && ((1<<i) & ~mask) )
continue;
- if( (columns[i].type & MSITYPE_STRING) &&
- ! MSITYPE_IS_BINARY(tv->columns[i].type) )
+ if( MSITYPE_IS_BINARY(tv->columns[i].type) )
+ {
+ LPWSTR encname;
+ IStream *stm = NULL;
+ UINT r;
+
+ ofs += bytes_per_column( tv->db, &columns[i] );
+
+ r = msi_record_encoded_stream_name( tv, rec, &encname );
+ if ( r != ERROR_SUCCESS )
+ return NULL;
+
+ r = IStorage_OpenStream( stg, encname, NULL,
+ STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm );
+ msi_free( encname );
+ if ( r != ERROR_SUCCESS )
+ return NULL;
+
+ MSI_RecordSetStream( rec, i+1, stm );
+ TRACE(" field %d [%s]\n", i+1, debugstr_w(encname));
+ }
+ else if( columns[i].type & MSITYPE_STRING )
{
LPCWSTR sval;
else
{
data[i] = MSI_RecordGetInteger( rec, i+1 );
- if ((tv->columns[i].type&0xff) == 2)
+
+ if (data[i] == MSI_NULL_INTEGER)
+ data[i] = 0;
+ else if ((tv->columns[i].type&0xff) == 2)
data[i] += 0x8000;
else
data[i] += 0x80000000;
data = msi_record_to_row( tv, rec );
if( !data )
return r;
- for( i = 0; i < tv->table->row_count + tv->table->nonpersistent_row_count; i++ )
+ for( i = 0; i < tv->table->row_count; i++ )
{
r = msi_row_matches( tv, i, data );
if( r == ERROR_SUCCESS )
break;
}
- rec = msi_get_transform_record( tv, st, &rawdata[n], bytes_per_strref );
+ rec = msi_get_transform_record( tv, st, stg, &rawdata[n], bytes_per_strref );
if (rec)
{
if ( mask & 1 )
}
}
- r = TABLE_insert_row( &tv->view, rec, FALSE );
+ r = TABLE_insert_row( &tv->view, rec, -1, FALSE );
if (r != ERROR_SUCCESS)
- ERR("insert row failed\n");
+ WARN("insert row failed\n");
if ( number != MSI_NULL_INTEGER && !lstrcmpW(name, szColumns) )
msi_update_table_columns( db, table );
r = msi_table_find_row( tv, rec, &row );
if (r != ERROR_SUCCESS)
- ERR("no matching row to transform\n");
+ WARN("no matching row to transform\n");
else if ( mask )
{
TRACE("modifying row [%d]:\n", row);
msi_free( t );
}
}
+
+static UINT table_find_insert_idx (MSIVIEW *view, LPCWSTR name, INT *pidx)
+{
+ UINT r, name_id, row_id;
+ INT idx;
+ MSITABLEVIEW *tv = (MSITABLEVIEW *)view;
+
+ TRACE ("%p %s\n", view, debugstr_w(name));
+
+ r = msi_string2idW(tv->db->strings, name, &name_id);
+ if (r != ERROR_SUCCESS)
+ {
+ *pidx = -1;
+ return r;
+ }
+
+ for( idx = 0; idx < tv->table->row_count; idx++ )
+ {
+ r = TABLE_fetch_int( &tv->view, idx, 1, &row_id );
+ if (row_id > name_id)
+ break;
+ }
+
+ *pidx = idx;
+ return ERROR_SUCCESS;
+}