Skip to content

Commit

Permalink
Fix and test MsiViewGetColumnInfo and binary fields.
Browse files Browse the repository at this point in the history
  • Loading branch information
Mike McCormack authored and julliard committed Sep 28, 2005
1 parent 3c37734 commit 8e74308
Show file tree
Hide file tree
Showing 5 changed files with 271 additions and 13 deletions.
3 changes: 2 additions & 1 deletion dlls/msi/msipriv.h
Expand Up @@ -34,11 +34,12 @@

#define MSI_DATASIZEMASK 0x00ff
#define MSITYPE_VALID 0x0100
#define MSITYPE_LOCALIZABLE 0x200
#define MSITYPE_STRING 0x0800
#define MSITYPE_NULLABLE 0x1000
#define MSITYPE_KEY 0x2000

#define MSITYPE_BINARY 0x8900
#define MSITYPE_IS_BINARY(type) (((type) & ~MSITYPE_NULLABLE) == (MSITYPE_STRING|MSITYPE_VALID))

struct tagMSITABLE;
typedef struct tagMSITABLE MSITABLE;
Expand Down
37 changes: 34 additions & 3 deletions dlls/msi/msiquery.c
Expand Up @@ -294,8 +294,7 @@ UINT MSI_ViewFetch(MSIQUERY *query, MSIRECORD **prec)
ERR("Error getting column type for %d\n", i );
continue;
}
if (( type != MSITYPE_BINARY) && (type != (MSITYPE_BINARY |
MSITYPE_NULLABLE)))
if (!MSITYPE_IS_BINARY(type))
{
ret = view->ops->fetch_int( view, query->row, i, &ival );
if( ret )
Expand Down Expand Up @@ -449,6 +448,29 @@ UINT WINAPI MsiViewExecute(MSIHANDLE hView, MSIHANDLE hRec)
return ret;
}

static UINT msi_set_record_type_string( MSIRECORD *rec, UINT field, UINT type )
{
static const WCHAR fmt[] = { '%','d',0 };
WCHAR szType[0x10];

if (MSITYPE_IS_BINARY(type))
szType[0] = 'v';
else if (type & MSITYPE_LOCALIZABLE)
szType[0] = 'l';
else if (type & MSITYPE_STRING)
szType[0] = 's';
else
szType[0] = 'i';
if (type & MSITYPE_NULLABLE)
szType[0] &= ~0x20;

sprintfW( &szType[1], fmt, (type&0xff) );

TRACE("type %04x -> %s\n", type, debugstr_w(szType) );

return MSI_RecordSetStringW( rec, field, szType );
}

UINT WINAPI MsiViewGetColumnInfo(MSIHANDLE hView, MSICOLINFO info, MSIHANDLE *hRec)
{
MSIVIEW *view = NULL;
Expand All @@ -459,6 +481,12 @@ UINT WINAPI MsiViewGetColumnInfo(MSIHANDLE hView, MSICOLINFO info, MSIHANDLE *hR

TRACE("%ld %d %p\n", hView, info, hRec);

if( !hRec )
return ERROR_INVALID_PARAMETER;

if( info != MSICOLINFO_NAMES && info != MSICOLINFO_TYPES )
return ERROR_INVALID_PARAMETER;

query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
if( !query )
return ERROR_INVALID_HANDLE;
Expand Down Expand Up @@ -492,7 +520,10 @@ UINT WINAPI MsiViewGetColumnInfo(MSIHANDLE hView, MSICOLINFO info, MSIHANDLE *hR
r = view->ops->get_column_info( view, i+1, &name, &type );
if( r != ERROR_SUCCESS )
continue;
MSI_RecordSetStringW( rec, i+1, name );
if (info == MSICOLINFO_NAMES)
MSI_RecordSetStringW( rec, i+1, name );
else
msi_set_record_type_string( rec, i+1, type);
msi_free( name );
}

Expand Down
9 changes: 4 additions & 5 deletions dlls/msi/sql.y
Expand Up @@ -258,19 +258,18 @@ column_and_type:
column column_type
{
$$ = $1;
$$->type = $2;
$$->type = $2 | MSITYPE_VALID;
}
;

column_type:
data_type_l
{
$$ = $1 | MSITYPE_VALID;
$$ = $1;
}
| data_type_l TK_LOCALIZABLE
{
FIXME("LOCALIZABLE ignored\n");
$$ = $1 | MSITYPE_VALID;
$$ = $1 | MSITYPE_LOCALIZABLE;
}
;

Expand Down Expand Up @@ -312,7 +311,7 @@ data_type:
}
| TK_OBJECT
{
$$ = 0;
$$ = MSITYPE_STRING | MSITYPE_VALID;
}
;

Expand Down
8 changes: 4 additions & 4 deletions dlls/msi/table.c
Expand Up @@ -817,13 +817,13 @@ static const WCHAR szNumber[] = { 'N','u','m','b','e','r',0 };
static const WCHAR szType[] = { 'T','y','p','e',0 };

static const MSICOLUMNINFO _Columns_cols[4] = {
{ szColumns, 1, szTable, MSITYPE_VALID | MSITYPE_STRING | 32, 0 },
{ szColumns, 1, szTable, MSITYPE_VALID | MSITYPE_STRING | 64, 0 },
{ szColumns, 2, szNumber, MSITYPE_VALID | 2, 2 },
{ szColumns, 3, szName, MSITYPE_VALID | MSITYPE_STRING | 32, 4 },
{ szColumns, 3, szName, MSITYPE_VALID | MSITYPE_STRING | 64, 4 },
{ szColumns, 4, szType, MSITYPE_VALID | 2, 6 },
};
static const MSICOLUMNINFO _Tables_cols[1] = {
{ szTables, 1, szName, MSITYPE_VALID | MSITYPE_STRING | 32, 0 },
{ szTables, 1, szName, MSITYPE_VALID | MSITYPE_STRING | 64, 0 },
};

static UINT get_defaulttablecolumns( LPCWSTR name, MSICOLUMNINFO *colinfo, UINT *sz)
Expand Down Expand Up @@ -930,7 +930,7 @@ static UINT get_tablecolumns( MSIDATABASE *db,
colinfo[n].tablename = MSI_makestring( db, table_id );
colinfo[n].number = table->data[ i ][ 1 ] - (1<<15);
colinfo[n].colname = MSI_makestring( db, id );
colinfo[n].type = table->data[ i ] [ 3 ];
colinfo[n].type = table->data[ i ] [ 3 ] ^ 0x8000;
/* this assumes that columns are in order in the table */
if( n )
colinfo[n].offset = colinfo[n-1].offset
Expand Down
227 changes: 227 additions & 0 deletions dlls/msi/tests/db.c
Expand Up @@ -480,11 +480,238 @@ static void test_viewmodify(void)
ok(r == ERROR_SUCCESS, "MsiOpenDatabase close failed\n");
}

static MSIHANDLE create_db(void)
{
MSIHANDLE hdb = 0;
UINT res;

DeleteFile(msifile);

/* create an empty database */
res = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb );
ok( res == ERROR_SUCCESS , "Failed to create database\n" );
if( res != ERROR_SUCCESS )
return hdb;

res = MsiDatabaseCommit( hdb );
ok( res == ERROR_SUCCESS , "Failed to commit database\n" );

return hdb;
}

static void test_getcolinfo(void)
{
MSIHANDLE hdb, hview = 0, rec = 0;
UINT r;
DWORD sz;
char buffer[0x20];

/* create an empty db */
hdb = create_db();
ok( hdb, "failed to create db\n");

/* tables should be present */
r = MsiDatabaseOpenView(hdb, "select * from _Tables", &hview);
ok( r == ERROR_SUCCESS, "failed to open query\n");

r = MsiViewExecute(hview, 0);
ok( r == ERROR_SUCCESS, "failed to execute query\n");

/* check that NAMES works */
rec = 0;
r = MsiViewGetColumnInfo( hview, MSICOLINFO_NAMES, &rec );
ok( r == ERROR_SUCCESS, "failed to get names\n");
sz = sizeof buffer;
r = MsiRecordGetString(rec, 1, buffer, &sz );
ok( r == ERROR_SUCCESS, "failed to get string\n");
ok( !strcmp(buffer,"Name"), "_Tables has wrong column name\n");
r = MsiCloseHandle( rec );
ok( r == ERROR_SUCCESS, "failed to close record handle\n");

/* check that TYPES works */
rec = 0;
r = MsiViewGetColumnInfo( hview, MSICOLINFO_TYPES, &rec );
ok( r == ERROR_SUCCESS, "failed to get names\n");
sz = sizeof buffer;
r = MsiRecordGetString(rec, 1, buffer, &sz );
ok( r == ERROR_SUCCESS, "failed to get string\n");
ok( !strcmp(buffer,"s64"), "_Tables has wrong column type\n");
r = MsiCloseHandle( rec );
ok( r == ERROR_SUCCESS, "failed to close record handle\n");

/* check that invalid values fail */
rec = 0;
r = MsiViewGetColumnInfo( hview, 100, &rec );
ok( r == ERROR_INVALID_PARAMETER, "wrong error code\n");
ok( rec == 0, "returned a record\n");

r = MsiViewGetColumnInfo( hview, MSICOLINFO_TYPES, NULL );
ok( r == ERROR_INVALID_PARAMETER, "wrong error code\n");

r = MsiViewGetColumnInfo( 0, MSICOLINFO_TYPES, &rec );
ok( r == ERROR_INVALID_HANDLE, "wrong error code\n");

r = MsiViewClose(hview);
ok( r == ERROR_SUCCESS, "failed to close view\n");
r = MsiCloseHandle(hview);
ok( r == ERROR_SUCCESS, "failed to close view handle\n");
r = MsiCloseHandle(hdb);
ok( r == ERROR_SUCCESS, "failed to close database\n");
}

static MSIHANDLE get_column_info(MSIHANDLE hdb, const char *query, MSICOLINFO type)
{
MSIHANDLE hview = 0, rec = 0;
UINT r;

r = MsiDatabaseOpenView(hdb, query, &hview);
if( r != ERROR_SUCCESS )
return r;

r = MsiViewExecute(hview, 0);
if( r == ERROR_SUCCESS )
{
MsiViewGetColumnInfo( hview, type, &rec );
MsiViewClose(hview);
}
MsiCloseHandle(hview);
return rec;
}

static UINT get_columns_table_type(MSIHANDLE hdb, const char *table, UINT field)
{
MSIHANDLE hview = 0, rec = 0;
UINT r, type = 0;
char query[0x100];

sprintf(query, "select * from `_Columns` where `Table` = '%s'", table );

r = MsiDatabaseOpenView(hdb, query, &hview);
if( r != ERROR_SUCCESS )
return r;

r = MsiViewExecute(hview, 0);
if( r == ERROR_SUCCESS )
{
while (1)
{
r = MsiViewFetch( hview, &rec );
if( r != ERROR_SUCCESS)
break;
r = MsiRecordGetInteger( rec, 2 );
if (r == field)
type = MsiRecordGetInteger( rec, 4 );
MsiCloseHandle( rec );
}

MsiViewClose(hview);
}
MsiCloseHandle(hview);
return type;
}

static BOOL check_record( MSIHANDLE rec, UINT field, LPSTR val )
{
CHAR buffer[0x20];
UINT r;
DWORD sz;

sz = sizeof buffer;
r = MsiRecordGetString( rec, field, buffer, &sz );
return (r == ERROR_SUCCESS ) && !strcmp(val, buffer);
}

static void test_viewgetcolumninfo(void)
{
MSIHANDLE hdb = 0, rec;
UINT r;

hdb = create_db();
ok( hdb, "failed to create db\n");

r = run_query( hdb,
"CREATE TABLE `Properties` "
"( `Property` CHAR(255), `Value` CHAR(1) PRIMARY KEY `Property`)" );
ok( r == ERROR_SUCCESS , "Failed to create table\n" );

/* check the column types */
rec = get_column_info( hdb, "select * from `Properties`", MSICOLINFO_TYPES );
ok( rec, "failed to get column info record\n" );

ok( check_record( rec, 1, "S255"), "wrong record type\n");
ok( check_record( rec, 2, "S1"), "wrong record type\n");

MsiCloseHandle( rec );

/* check the type in _Columns */
ok( 0x3dff == get_columns_table_type(hdb, "Properties", 1 ), "_columns table wrong\n");
ok( 0x1d01 == get_columns_table_type(hdb, "Properties", 2 ), "_columns table wrong\n");

/* now try the names */
rec = get_column_info( hdb, "select * from `Properties`", MSICOLINFO_NAMES );
ok( rec, "failed to get column info record\n" );

ok( check_record( rec, 1, "Property"), "wrong record type\n");
ok( check_record( rec, 2, "Value"), "wrong record type\n");

MsiCloseHandle( rec );

r = run_query( hdb,
"CREATE TABLE `Binary` "
"( `Name` CHAR(255), `Data` OBJECT PRIMARY KEY `Name`)" );
ok( r == ERROR_SUCCESS , "Failed to create table\n" );

/* check the column types */
rec = get_column_info( hdb, "select * from `Binary`", MSICOLINFO_TYPES );
ok( rec, "failed to get column info record\n" );

ok( check_record( rec, 1, "S255"), "wrong record type\n");
ok( check_record( rec, 2, "V0"), "wrong record type\n");

MsiCloseHandle( rec );

/* check the type in _Columns */
ok( 0x3dff == get_columns_table_type(hdb, "Binary", 1 ), "_columns table wrong\n");
ok( 0x1900 == get_columns_table_type(hdb, "Binary", 2 ), "_columns table wrong\n");

/* now try the names */
rec = get_column_info( hdb, "select * from `Binary`", MSICOLINFO_NAMES );
ok( rec, "failed to get column info record\n" );

ok( check_record( rec, 1, "Name"), "wrong record type\n");
ok( check_record( rec, 2, "Data"), "wrong record type\n");
MsiCloseHandle( rec );

r = run_query( hdb,
"CREATE TABLE `UIText` "
"( `Key` CHAR(72) NOT NULL, `Text` CHAR(255) LOCALIZABLE PRIMARY KEY `Key`)" );
ok( r == ERROR_SUCCESS , "Failed to create table\n" );

ok( 0x2d48 == get_columns_table_type(hdb, "UIText", 1 ), "_columns table wrong\n");
ok( 0x1fff == get_columns_table_type(hdb, "UIText", 2 ), "_columns table wrong\n");

rec = get_column_info( hdb, "select * from `UIText`", MSICOLINFO_NAMES );
ok( rec, "failed to get column info record\n" );
ok( check_record( rec, 1, "Key"), "wrong record type\n");
ok( check_record( rec, 2, "Text"), "wrong record type\n");
MsiCloseHandle( rec );

rec = get_column_info( hdb, "select * from `UIText`", MSICOLINFO_TYPES );
ok( rec, "failed to get column info record\n" );
ok( check_record( rec, 1, "s72"), "wrong record type\n");
ok( check_record( rec, 2, "L255"), "wrong record type\n");
MsiCloseHandle( rec );

MsiCloseHandle( hdb );
}

START_TEST(db)
{
test_msidatabase();
test_msiinsert();
test_msidecomposedesc();
test_msibadqueries();
test_viewmodify();
test_viewgetcolumninfo();
test_getcolinfo();
}

0 comments on commit 8e74308

Please sign in to comment.