From 8e74308a10f2d0348de8d945a5525e3d9d810672 Mon Sep 17 00:00:00 2001 From: Mike McCormack Date: Wed, 28 Sep 2005 11:59:40 +0000 Subject: [PATCH] Fix and test MsiViewGetColumnInfo and binary fields. --- dlls/msi/msipriv.h | 3 +- dlls/msi/msiquery.c | 37 +++++++- dlls/msi/sql.y | 9 +- dlls/msi/table.c | 8 +- dlls/msi/tests/db.c | 227 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 271 insertions(+), 13 deletions(-) diff --git a/dlls/msi/msipriv.h b/dlls/msi/msipriv.h index 0356871abbd..cb0065a88ae 100644 --- a/dlls/msi/msipriv.h +++ b/dlls/msi/msipriv.h @@ -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; diff --git a/dlls/msi/msiquery.c b/dlls/msi/msiquery.c index 36aaded6a37..ed7d8ebfbe4 100644 --- a/dlls/msi/msiquery.c +++ b/dlls/msi/msiquery.c @@ -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 ) @@ -449,6 +448,29 @@ out: 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; @@ -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; @@ -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 ); } diff --git a/dlls/msi/sql.y b/dlls/msi/sql.y index 1bdc82aa9bb..6669441c2b4 100644 --- a/dlls/msi/sql.y +++ b/dlls/msi/sql.y @@ -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; } ; @@ -312,7 +311,7 @@ data_type: } | TK_OBJECT { - $$ = 0; + $$ = MSITYPE_STRING | MSITYPE_VALID; } ; diff --git a/dlls/msi/table.c b/dlls/msi/table.c index 99f75ce0e7c..b3b110ae989 100644 --- a/dlls/msi/table.c +++ b/dlls/msi/table.c @@ -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) @@ -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 diff --git a/dlls/msi/tests/db.c b/dlls/msi/tests/db.c index 72484b8d7a4..d7055db3f47 100644 --- a/dlls/msi/tests/db.c +++ b/dlls/msi/tests/db.c @@ -480,6 +480,231 @@ 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(); @@ -487,4 +712,6 @@ START_TEST(db) test_msidecomposedesc(); test_msibadqueries(); test_viewmodify(); + test_viewgetcolumninfo(); + test_getcolinfo(); }