Load a table's column information separately from the table itself.

This commit is contained in:
Mike McCormack 2005-09-22 10:34:07 +00:00 committed by Alexandre Julliard
parent 75658d7aaa
commit 1c5967c48c
1 changed files with 68 additions and 67 deletions

View File

@ -1,7 +1,7 @@
/* /*
* Implementation of the Microsoft Installer (msi.dll) * Implementation of the Microsoft Installer (msi.dll)
* *
* Copyright 2002-2004 Mike McCormack for CodeWeavers * Copyright 2002-2005 Mike McCormack for CodeWeavers
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -41,9 +41,9 @@ WINE_DEFAULT_DEBUG_CHANNEL(msi);
typedef struct tagMSICOLUMNINFO typedef struct tagMSICOLUMNINFO
{ {
LPWSTR tablename; LPCWSTR tablename;
UINT number; UINT number;
LPWSTR colname; LPCWSTR colname;
UINT type; UINT type;
UINT offset; UINT offset;
} MSICOLUMNINFO; } MSICOLUMNINFO;
@ -63,7 +63,7 @@ static UINT table_get_column_info( MSIDATABASE *db, LPCWSTR name,
static UINT get_tablecolumns( MSIDATABASE *db, static UINT get_tablecolumns( MSIDATABASE *db,
LPCWSTR szTableName, MSICOLUMNINFO *colinfo, UINT *sz); LPCWSTR szTableName, MSICOLUMNINFO *colinfo, UINT *sz);
static inline UINT bytes_per_column( MSICOLUMNINFO *col ) static inline UINT bytes_per_column( const MSICOLUMNINFO *col )
{ {
if( col->type & MSITYPE_STRING ) if( col->type & MSITYPE_STRING )
return 2; return 2;
@ -404,12 +404,14 @@ static void free_table( MSITABLE *table )
msi_free( table ); msi_free( table );
} }
static MSITABLE *read_table_from_storage( MSIDATABASE *db, LPCWSTR name ) /* add this table to the list of cached tables in the database */
static MSITABLE *read_table_from_storage( IStorage *stg, LPCWSTR name,
const MSICOLUMNINFO *cols, UINT num_cols )
{ {
MSITABLE *t; MSITABLE *t;
USHORT *rawdata = NULL; USHORT *rawdata = NULL;
UINT rawsize = 0, r, i, j, row_size = 0, num_cols = 0; UINT rawsize = 0, i, j, row_size = 0;
MSICOLUMNINFO *cols = NULL, *last_col; const MSICOLUMNINFO *last_col;
TRACE("%s\n",debugstr_w(name)); TRACE("%s\n",debugstr_w(name));
@ -418,10 +420,6 @@ static MSITABLE *read_table_from_storage( MSIDATABASE *db, LPCWSTR name )
if( !t ) if( !t )
return t; return t;
r = table_get_column_info( db, name, &cols, &num_cols );
if( r != ERROR_SUCCESS )
goto err;
last_col = &cols[num_cols-1]; last_col = &cols[num_cols-1];
row_size = last_col->offset + bytes_per_column( last_col ); row_size = last_col->offset + bytes_per_column( last_col );
@ -430,7 +428,7 @@ static MSITABLE *read_table_from_storage( MSIDATABASE *db, LPCWSTR name )
lstrcpyW( t->name, name ); lstrcpyW( t->name, name );
/* if we can't read the table, just assume that it's empty */ /* if we can't read the table, just assume that it's empty */
read_stream_data( db->storage, name, &rawdata, &rawsize ); read_stream_data( stg, name, &rawdata, &rawsize );
if( !rawdata ) if( !rawdata )
return t; return t;
@ -476,13 +474,9 @@ static MSITABLE *read_table_from_storage( MSIDATABASE *db, LPCWSTR name )
} }
} }
msi_free( cols );
msi_free( rawdata ); msi_free( rawdata );
return t; return t;
err: err:
msi_free( cols );
msi_free( rawdata ); msi_free( rawdata );
free_table( t ); free_table( t );
return NULL; return NULL;
@ -499,7 +493,7 @@ void free_cached_tables( MSIDATABASE *db )
} }
} }
static MSITABLE *find_cached_table(MSIDATABASE *db, LPCWSTR name ) static MSITABLE *find_cached_table( MSIDATABASE *db, LPCWSTR name )
{ {
MSITABLE *t; MSITABLE *t;
@ -512,7 +506,7 @@ static MSITABLE *find_cached_table(MSIDATABASE *db, LPCWSTR name )
static UINT table_get_column_info( MSIDATABASE *db, LPCWSTR name, MSICOLUMNINFO **pcols, UINT *pcount ) static UINT table_get_column_info( MSIDATABASE *db, LPCWSTR name, MSICOLUMNINFO **pcols, UINT *pcount )
{ {
UINT r, column_count; UINT r, column_count = 0;
MSICOLUMNINFO *columns; MSICOLUMNINFO *columns;
/* get the number of columns in this table */ /* get the number of columns in this table */
@ -527,7 +521,7 @@ static UINT table_get_column_info( MSIDATABASE *db, LPCWSTR name, MSICOLUMNINFO
TRACE("Table %s found\n", debugstr_w(name) ); TRACE("Table %s found\n", debugstr_w(name) );
columns = msi_alloc( column_count*sizeof (MSICOLUMNINFO)); columns = msi_alloc( column_count*sizeof (MSICOLUMNINFO) );
if( !columns ) if( !columns )
return ERROR_FUNCTION_FAILED; return ERROR_FUNCTION_FAILED;
@ -544,7 +538,8 @@ static UINT table_get_column_info( MSIDATABASE *db, LPCWSTR name, MSICOLUMNINFO
return r; return r;
} }
static MSITABLE *get_table( MSIDATABASE *db, LPCWSTR name ) static MSITABLE *get_table( MSIDATABASE *db, LPCWSTR name,
const MSICOLUMNINFO *cols, UINT num_cols )
{ {
MSITABLE *table; MSITABLE *table;
@ -553,7 +548,7 @@ static MSITABLE *get_table( MSIDATABASE *db, LPCWSTR name )
if( table ) if( table )
return table; return table;
table = read_table_from_storage( db, name ); table = read_table_from_storage( db->storage, name, cols, num_cols );
if( table ) if( table )
list_add_head( &db->tables, &table->entry ); list_add_head( &db->tables, &table->entry );
@ -809,53 +804,63 @@ static const WCHAR szColumn[] = { 'C','o','l','u','m','n',0 };
static const WCHAR szNumber[] = { 'N','u','m','b','e','r',0 }; static const WCHAR szNumber[] = { 'N','u','m','b','e','r',0 };
static const WCHAR szType[] = { 'T','y','p','e',0 }; static const WCHAR szType[] = { 'T','y','p','e',0 };
struct standard_table { static const MSICOLUMNINFO _Columns_cols[4] = {
LPCWSTR tablename; { szColumns, 1, szTable, MSITYPE_VALID | MSITYPE_STRING | 32, 0 },
LPCWSTR columnname; { szColumns, 2, szNumber, MSITYPE_VALID | 2, 2 },
UINT number; { szColumns, 3, szName, MSITYPE_VALID | MSITYPE_STRING | 32, 4 },
UINT type; { szColumns, 4, szType, MSITYPE_VALID | 2, 6 },
} MSI_standard_tables[] = };
{ static const MSICOLUMNINFO _Tables_cols[1] = {
{ szTables, szName, 1, MSITYPE_VALID | MSITYPE_STRING | 32}, { szTables, 1, szName, MSITYPE_VALID | MSITYPE_STRING | 32, 0 },
{ szColumns, szTable, 1, MSITYPE_VALID | MSITYPE_STRING | 32},
{ szColumns, szNumber, 2, MSITYPE_VALID | 2},
{ szColumns, szName, 3, MSITYPE_VALID | MSITYPE_STRING | 32},
{ szColumns, szType, 4, MSITYPE_VALID | 2},
}; };
#define STANDARD_TABLE_COUNT \ static UINT get_defaulttablecolumns( LPCWSTR name, MSICOLUMNINFO *colinfo, UINT *sz)
(sizeof(MSI_standard_tables)/sizeof(struct standard_table))
static UINT get_defaulttablecolumns( LPCWSTR szTable, MSICOLUMNINFO *colinfo, UINT *sz)
{ {
DWORD i, n=0; const MSICOLUMNINFO *p;
DWORD i, n;
for(i=0; i<STANDARD_TABLE_COUNT; i++) TRACE("%s\n", debugstr_w(name));
if (!lstrcmpW( name, szTables ))
{ {
if( lstrcmpW( szTable, MSI_standard_tables[i].tablename ) ) p = _Tables_cols;
continue; n = 1;
if(colinfo && (n < *sz) ) }
else if (!lstrcmpW( name, szColumns ))
{
p = _Columns_cols;
n = 4;
}
else
return ERROR_FUNCTION_FAILED;
/* duplicate the string data so we can free it in msi_free_colinfo */
for (i=0; i<n; i++)
{
if (colinfo && (i < *sz) )
{ {
colinfo[n].tablename = strdupW(MSI_standard_tables[i].tablename); memcpy( &colinfo[i], &p[i], sizeof(MSICOLUMNINFO) );
colinfo[n].colname = strdupW(MSI_standard_tables[i].columnname); colinfo[i].tablename = strdupW( p[i].tablename );
colinfo[n].number = MSI_standard_tables[i].number; colinfo[i].colname = strdupW( p[i].colname );
colinfo[n].type = MSI_standard_tables[i].type;
/* ERR("Table %s has column %s\n",debugstr_w(colinfo[n].tablename),
debugstr_w(colinfo[n].colname)); */
if( n )
colinfo[n].offset = colinfo[n-1].offset
+ bytes_per_column( &colinfo[n-1] );
else
colinfo[n].offset = 0;
} }
n++; if( colinfo && (i >= *sz) )
if( colinfo && (n >= *sz) )
break; break;
} }
*sz = n; *sz = n;
return ERROR_SUCCESS; return ERROR_SUCCESS;
} }
static void msi_free_colinfo( MSICOLUMNINFO *colinfo, UINT count )
{
UINT i;
for( i=0; i<count; i++ )
{
msi_free( (LPWSTR) colinfo[i].tablename );
msi_free( (LPWSTR) colinfo[i].colname );
}
}
LPWSTR MSI_makestring( MSIDATABASE *db, UINT stringid) LPWSTR MSI_makestring( MSIDATABASE *db, UINT stringid)
{ {
UINT sz=0, r; UINT sz=0, r;
@ -885,10 +890,10 @@ static UINT get_tablecolumns( MSIDATABASE *db,
if( ( r == ERROR_SUCCESS ) && *sz ) if( ( r == ERROR_SUCCESS ) && *sz )
return r; return r;
table = get_table( db, szColumns ); table = get_table( db, szColumns, _Columns_cols, 4 );
if( !table ) if( !table )
{ {
WARN("table %s not available\n", debugstr_w(szColumns)); ERR("couldn't load _Columns table\n");
return ERROR_FUNCTION_FAILED; return ERROR_FUNCTION_FAILED;
} }
@ -958,7 +963,7 @@ BOOL TABLE_Exists( MSIDATABASE *db, LPWSTR name )
return FALSE; return FALSE;
} }
table = get_table( db, szTables ); table = get_table( db, szTables, _Tables_cols, 1 );
if( !table ) if( !table )
{ {
TRACE("table %s not available\n", debugstr_w(szTables)); TRACE("table %s not available\n", debugstr_w(szTables));
@ -1167,7 +1172,8 @@ static UINT TABLE_execute( struct tagMSIVIEW *view, MSIRECORD *record )
TRACE("%p %p\n", tv, record); TRACE("%p %p\n", tv, record);
tv->table = get_table( tv->db, tv->name ); TRACE("There are %d columns\n", tv->num_cols );
tv->table = get_table( tv->db, tv->name, tv->columns, tv->num_cols );
if( !tv->table ) if( !tv->table )
return ERROR_FUNCTION_FAILED; return ERROR_FUNCTION_FAILED;
@ -1401,12 +1407,7 @@ static UINT TABLE_delete( struct tagMSIVIEW *view )
if( tv->columns ) if( tv->columns )
{ {
UINT i; msi_free_colinfo( tv->columns, tv->num_cols );
for( i=0; i<tv->num_cols; i++)
{
msi_free( tv->columns[i].colname );
msi_free( tv->columns[i].tablename );
}
msi_free( tv->columns ); msi_free( tv->columns );
} }
tv->columns = NULL; tv->columns = NULL;
@ -1434,7 +1435,7 @@ MSIVIEWOPS table_ops =
UINT TABLE_CreateView( MSIDATABASE *db, LPCWSTR name, MSIVIEW **view ) UINT TABLE_CreateView( MSIDATABASE *db, LPCWSTR name, MSIVIEW **view )
{ {
MSITABLEVIEW *tv ; MSITABLEVIEW *tv ;
UINT r, sz, column_count = 0; UINT r, sz, column_count;
MSICOLUMNINFO *columns, *last_col; MSICOLUMNINFO *columns, *last_col;
TRACE("%p %s %p\n", db, debugstr_w(name), view ); TRACE("%p %s %p\n", db, debugstr_w(name), view );
@ -1483,7 +1484,7 @@ UINT TABLE_CreateView( MSIDATABASE *db, LPCWSTR name, MSIVIEW **view )
tv->table = NULL; tv->table = NULL;
tv->row_size = last_col->offset + bytes_per_column( last_col ); tv->row_size = last_col->offset + bytes_per_column( last_col );
TRACE("one row is %d bytes\n", tv->row_size ); TRACE("%s one row is %d bytes\n", debugstr_w(name), tv->row_size );
*view = (MSIVIEW*) tv; *view = (MSIVIEW*) tv;
lstrcpyW( tv->name, name ); lstrcpyW( tv->name, name );