From fb131be992277bd4e36e8cbcb2650588f1ee831e Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 23 Oct 2012 09:39:12 +0200 Subject: add tests --- tests/Makefile.am | 29 + tests/runtest.in | 12 + tests/test.h | 20 + tests/testdatabase.c | 9380 +++++++++++++++++++++++++++++++++++++++++++++++++ tests/testdatabase.ok | 2955 ++++++++++++++++ tests/testrecord.c | 621 ++++ tests/testrecord.ok | 214 ++ tests/testsuminfo.c | 429 +++ tests/testsuminfo.ok | 87 + 9 files changed, 13747 insertions(+) create mode 100644 tests/Makefile.am create mode 100644 tests/runtest.in create mode 100644 tests/test.h create mode 100644 tests/testdatabase.c create mode 100644 tests/testdatabase.ok create mode 100644 tests/testrecord.c create mode 100644 tests/testrecord.ok create mode 100644 tests/testsuminfo.c create mode 100644 tests/testsuminfo.ok (limited to 'tests') diff --git a/tests/Makefile.am b/tests/Makefile.am new file mode 100644 index 0000000..e9d4b94 --- /dev/null +++ b/tests/Makefile.am @@ -0,0 +1,29 @@ +AM_CPPFLAGS = -I$(top_srcdir)/include -I$(srcdir) -I. + +check_PROGRAMS = testdatabase testrecord testsuminfo + +testdatabase_SOURCES = testdatabase.c +testdatabase_LDADD = ../libmsi/libmsi.la -lole32 +testrecord_SOURCES = testrecord.c +testrecord_LDADD = ../libmsi/libmsi.la -lole32 +testsuminfo_SOURCES = testsuminfo.c +testsuminfo_LDADD = ../libmsi/libmsi.la -lole32 + +TESTS = \ + testdatabase$(EXEEXT) \ + testrecord$(EXEEXT) \ + testsuminfo$(EXEEXT) + +TESTS_ENVIRONMENT = srcdir=$(srcdir) ./runtest + +CLEANFILES = \ + testdatabase.log testdatabase.diff \ + testrecord.log testrecord.diff \ + testsuminfo.log testsuminfo.diff + +EXTRA_DIST = \ + testdatabase.ok \ + testrecord.ok \ + testsuminfo.ok + +.NOTPARALLEL: diff --git a/tests/runtest.in b/tests/runtest.in new file mode 100644 index 0000000..f8a3f4e --- /dev/null +++ b/tests/runtest.in @@ -0,0 +1,12 @@ +#! /bin/bash + +: ${srcdir=$(basename $0)} +: ${EXEEXT=@EXEEXT@} + +base=${1%${EXEEXT}} + +rm -f winetest-db.msi +$1 > $base.log +diff -u $srcdir/$base.ok $base.log | tee $base.diff +test -s $base.diff && exit 1 +exit 0 diff --git a/tests/test.h b/tests/test.h new file mode 100644 index 0000000..72234df --- /dev/null +++ b/tests/test.h @@ -0,0 +1,20 @@ +#include +#include +#include "debug.h" + +#define todo_wine if(0) + +#define ok(cond, desc, ...) _ok(cond, #cond, desc, ## __VA_ARGS__ ) + +static inline void _ok(bool cond, const char *cond_str, const char *str, ...) +{ + va_list ap; + va_start(ap, str); + if (!cond) { + printf("FAIL: %s\n ", cond_str); + vprintf(str, ap); + } else { + printf("ok: %s\n", cond_str); + } + va_end(ap); +} diff --git a/tests/testdatabase.c b/tests/testdatabase.c new file mode 100644 index 0000000..3b2d316 --- /dev/null +++ b/tests/testdatabase.c @@ -0,0 +1,9380 @@ +/* + * Copyright (C) 2005 Mike McCormack for CodeWeavers + * + * A test program for MSI database files. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#define COBJMACROS + +#include + +#include +#include + +#include + +#include "test.h" + +static const char *msifile = "winetest-db.msi"; +static const char *msifile2 = "winetst2-db.msi"; +static const char *mstfile = "winetst-db.mst"; +static const WCHAR msifileW[] = {'w','i','n','e','t','e','s','t','-','d','b','.','m','s','i',0}; + +static void test_msidatabase(void) +{ + MSIHANDLE hdb = 0, hdb2 = 0; + UINT res; + + DeleteFile(msifile); + + res = MsiOpenDatabase( msifile, msifile2, &hdb ); + ok( res == ERROR_OPEN_FAILED, "expected failure\n"); + + res = MsiOpenDatabase( msifile, (LPSTR) 0xff, &hdb ); + ok( res == ERROR_INVALID_PARAMETER, "expected failure\n"); + + res = MsiCloseHandle( hdb ); + ok( res == ERROR_SUCCESS , "Failed to close database\n" ); + + /* create an empty database */ + res = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb ); + ok( res == ERROR_SUCCESS , "Failed to create database\n" ); + + res = MsiDatabaseCommit( hdb ); + ok( res == ERROR_SUCCESS , "Failed to commit database\n" ); + + ok( INVALID_FILE_ATTRIBUTES != GetFileAttributes( msifile ), "database should exist\n"); + + res = MsiCloseHandle( hdb ); + ok( res == ERROR_SUCCESS , "Failed to close database\n" ); + res = MsiOpenDatabase( msifile, msifile2, &hdb2 ); + ok( res == ERROR_SUCCESS , "Failed to open database\n" ); + + ok( INVALID_FILE_ATTRIBUTES != GetFileAttributes( msifile2 ), "database should exist\n"); + + res = MsiDatabaseCommit( hdb2 ); + ok( res == ERROR_SUCCESS , "Failed to commit database\n" ); + + res = MsiCloseHandle( hdb2 ); + ok( res == ERROR_SUCCESS , "Failed to close database\n" ); + + res = MsiOpenDatabase( msifile, msifile2, &hdb2 ); + ok( res == ERROR_SUCCESS , "Failed to open database\n" ); + + res = MsiCloseHandle( hdb2 ); + ok( res == ERROR_SUCCESS , "Failed to close database\n" ); + + ok( INVALID_FILE_ATTRIBUTES == GetFileAttributes( msifile2 ), "uncommitted database should not exist\n"); + + res = MsiOpenDatabase( msifile, msifile2, &hdb2 ); + ok( res == ERROR_SUCCESS , "Failed to close database\n" ); + + res = MsiDatabaseCommit( hdb2 ); + ok( res == ERROR_SUCCESS , "Failed to commit database\n" ); + + res = MsiCloseHandle( hdb2 ); + ok( res == ERROR_SUCCESS , "Failed to close database\n" ); + + ok( INVALID_FILE_ATTRIBUTES != GetFileAttributes( msifile2 ), "committed database should exist\n"); + + res = MsiOpenDatabase( msifile, MSIDBOPEN_READONLY, &hdb ); + ok( res == ERROR_SUCCESS , "Failed to open database\n" ); + + res = MsiDatabaseCommit( hdb ); + ok( res == ERROR_SUCCESS , "Failed to commit database\n" ); + + res = MsiCloseHandle( hdb ); + ok( res == ERROR_SUCCESS , "Failed to close database\n" ); + + res = MsiOpenDatabase( msifile, MSIDBOPEN_DIRECT, &hdb ); + ok( res == ERROR_SUCCESS , "Failed to open database\n" ); + + res = MsiCloseHandle( hdb ); + ok( res == ERROR_SUCCESS , "Failed to close database\n" ); + + res = MsiOpenDatabase( msifile, MSIDBOPEN_TRANSACT, &hdb ); + ok( res == ERROR_SUCCESS , "Failed to open database\n" ); + + res = MsiCloseHandle( hdb ); + ok( res == ERROR_SUCCESS , "Failed to close database\n" ); + ok( INVALID_FILE_ATTRIBUTES != GetFileAttributes( msifile ), "database should exist\n"); + + /* MSIDBOPEN_CREATE deletes the database if MsiCommitDatabase isn't called */ + res = MsiOpenDatabase( msifile, MSIDBOPEN_CREATE, &hdb ); + ok( res == ERROR_SUCCESS , "Failed to open database\n" ); + + ok( INVALID_FILE_ATTRIBUTES != GetFileAttributes( msifile ), "database should exist\n"); + + res = MsiCloseHandle( hdb ); + ok( res == ERROR_SUCCESS , "Failed to close database\n" ); + + ok( INVALID_FILE_ATTRIBUTES == GetFileAttributes( msifile ), "database should exist\n"); + + res = MsiOpenDatabase( msifile, MSIDBOPEN_CREATE, &hdb ); + ok( res == ERROR_SUCCESS , "Failed to open database\n" ); + + res = MsiDatabaseCommit( hdb ); + ok( res == ERROR_SUCCESS , "Failed to commit database\n" ); + + ok( INVALID_FILE_ATTRIBUTES != GetFileAttributes( msifile ), "database should exist\n"); + + res = MsiCloseHandle( hdb ); + ok( res == ERROR_SUCCESS , "Failed to close database\n" ); + + res = DeleteFile( msifile2 ); + ok( res == TRUE, "Failed to delete database\n" ); + + res = DeleteFile( msifile ); + ok( res == TRUE, "Failed to delete database\n" ); +} + +static UINT do_query(MSIHANDLE hdb, const char *query, MSIHANDLE *phrec) +{ + MSIHANDLE hview = 0; + UINT r, ret; + + if (phrec) + *phrec = 0; + + /* open a select query */ + r = MsiDatabaseOpenView(hdb, query, &hview); + if (r != ERROR_SUCCESS) + return r; + r = MsiViewExecute(hview, 0); + if (r != ERROR_SUCCESS) + return r; + ret = MsiViewFetch(hview, phrec); + r = MsiViewClose(hview); + if (r != ERROR_SUCCESS) + return r; + r = MsiCloseHandle(hview); + if (r != ERROR_SUCCESS) + return r; + return ret; +} + +static UINT run_query( MSIHANDLE hdb, MSIHANDLE hrec, const char *query ) +{ + MSIHANDLE hview = 0; + UINT r; + + r = MsiDatabaseOpenView(hdb, query, &hview); + if( r != ERROR_SUCCESS ) + return r; + + r = MsiViewExecute(hview, hrec); + if( r == ERROR_SUCCESS ) + r = MsiViewClose(hview); + MsiCloseHandle(hview); + return r; +} + +static UINT run_queryW( MSIHANDLE hdb, MSIHANDLE hrec, const WCHAR *query ) +{ + MSIHANDLE hview = 0; + UINT r; + + r = MsiDatabaseOpenViewW(hdb, query, &hview); + if( r != ERROR_SUCCESS ) + return r; + + r = MsiViewExecute(hview, hrec); + if( r == ERROR_SUCCESS ) + r = MsiViewClose(hview); + MsiCloseHandle(hview); + return r; +} + +static UINT create_component_table( MSIHANDLE hdb ) +{ + return run_query( hdb, 0, + "CREATE TABLE `Component` ( " + "`Component` CHAR(72) NOT NULL, " + "`ComponentId` CHAR(38), " + "`Directory_` CHAR(72) NOT NULL, " + "`Attributes` SHORT NOT NULL, " + "`Condition` CHAR(255), " + "`KeyPath` CHAR(72) " + "PRIMARY KEY `Component`)" ); +} + +static UINT create_custom_action_table( MSIHANDLE hdb ) +{ + return run_query( hdb, 0, + "CREATE TABLE `CustomAction` ( " + "`Action` CHAR(72) NOT NULL, " + "`Type` SHORT NOT NULL, " + "`Source` CHAR(72), " + "`Target` CHAR(255) " + "PRIMARY KEY `Action`)" ); +} + +static UINT create_directory_table( MSIHANDLE hdb ) +{ + return run_query( hdb, 0, + "CREATE TABLE `Directory` ( " + "`Directory` CHAR(255) NOT NULL, " + "`Directory_Parent` CHAR(255), " + "`DefaultDir` CHAR(255) NOT NULL " + "PRIMARY KEY `Directory`)" ); +} + +static UINT create_feature_components_table( MSIHANDLE hdb ) +{ + return run_query( hdb, 0, + "CREATE TABLE `FeatureComponents` ( " + "`Feature_` CHAR(38) NOT NULL, " + "`Component_` CHAR(72) NOT NULL " + "PRIMARY KEY `Feature_`, `Component_` )" ); +} + +static UINT create_std_dlls_table( MSIHANDLE hdb ) +{ + return run_query( hdb, 0, + "CREATE TABLE `StdDlls` ( " + "`File` CHAR(255) NOT NULL, " + "`Binary_` CHAR(72) NOT NULL " + "PRIMARY KEY `File` )" ); +} + +static UINT create_binary_table( MSIHANDLE hdb ) +{ + return run_query( hdb, 0, + "CREATE TABLE `Binary` ( " + "`Name` CHAR(72) NOT NULL, " + "`Data` CHAR(72) NOT NULL " + "PRIMARY KEY `Name` )" ); +} + +#define make_add_entry(type, qtext) \ + static UINT add##_##type##_##entry( MSIHANDLE hdb, const char *values ) \ + { \ + char insert[] = qtext; \ + char *query; \ + UINT sz, r; \ + sz = strlen(values) + sizeof insert; \ + query = HeapAlloc(GetProcessHeap(),0,sz); \ + sprintf(query,insert,values); \ + r = run_query( hdb, 0, query ); \ + HeapFree(GetProcessHeap(), 0, query); \ + return r; \ + } + +make_add_entry(component, + "INSERT INTO `Component` " + "(`Component`, `ComponentId`, `Directory_`, " + "`Attributes`, `Condition`, `KeyPath`) VALUES( %s )") + +make_add_entry(custom_action, + "INSERT INTO `CustomAction` " + "(`Action`, `Type`, `Source`, `Target`) VALUES( %s )") + +make_add_entry(feature_components, + "INSERT INTO `FeatureComponents` " + "(`Feature_`, `Component_`) VALUES( %s )") + +make_add_entry(std_dlls, + "INSERT INTO `StdDlls` (`File`, `Binary_`) VALUES( %s )") + +make_add_entry(binary, + "INSERT INTO `Binary` (`Name`, `Data`) VALUES( %s )") + +static void test_msiinsert(void) +{ + MSIHANDLE hdb = 0, hview = 0, hview2 = 0, hrec = 0; + UINT r; + const char *query; + char buf[80]; + DWORD sz; + + DeleteFile(msifile); + + /* just MsiOpenDatabase should not create a file */ + r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb); + ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n"); + + /* create a table */ + query = "CREATE TABLE `phone` ( " + "`id` INT, `name` CHAR(32), `number` CHAR(32) " + "PRIMARY KEY `id`)"; + r = MsiDatabaseOpenView(hdb, query, &hview); + ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n"); + r = MsiViewExecute(hview, 0); + ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n"); + r = MsiViewClose(hview); + ok(r == ERROR_SUCCESS, "MsiViewClose failed\n"); + r = MsiCloseHandle(hview); + ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n"); + + query = "SELECT * FROM phone WHERE number = '8675309'"; + r = MsiDatabaseOpenView(hdb, query, &hview2); + ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n"); + r = MsiViewExecute(hview2, 0); + ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n"); + r = MsiViewFetch(hview2, &hrec); + ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch produced items\n"); + + /* insert a value into it */ + query = "INSERT INTO `phone` ( `id`, `name`, `number` )" + "VALUES('1', 'Abe', '8675309')"; + r = MsiDatabaseOpenView(hdb, query, &hview); + ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n"); + r = MsiViewExecute(hview, 0); + ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n"); + r = MsiViewClose(hview); + ok(r == ERROR_SUCCESS, "MsiViewClose failed\n"); + r = MsiCloseHandle(hview); + ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n"); + + r = MsiViewFetch(hview2, &hrec); + ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch produced items\n"); + r = MsiViewExecute(hview2, 0); + ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n"); + r = MsiViewFetch(hview2, &hrec); + ok(r == ERROR_SUCCESS, "MsiViewFetch failed: %u\n", r); + + r = MsiCloseHandle(hrec); + ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n"); + r = MsiViewClose(hview2); + ok(r == ERROR_SUCCESS, "MsiViewClose failed\n"); + r = MsiCloseHandle(hview2); + ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n"); + + query = "SELECT * FROM `phone` WHERE `id` = 1"; + r = do_query(hdb, query, &hrec); + ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n"); + + /* check the record contains what we put in it */ + r = MsiRecordGetFieldCount(hrec); + ok(r == 3, "record count wrong\n"); + + r = MsiRecordIsNull(hrec, 0); + ok(r == FALSE, "field 0 not null\n"); + + r = MsiRecordGetInteger(hrec, 1); + ok(r == 1, "field 1 contents wrong\n"); + sz = sizeof buf; + r = MsiRecordGetString(hrec, 2, buf, &sz); + ok(r == ERROR_SUCCESS, "field 2 content fetch failed\n"); + ok(!strcmp(buf,"Abe"), "field 2 content incorrect\n"); + sz = sizeof buf; + r = MsiRecordGetString(hrec, 3, buf, &sz); + ok(r == ERROR_SUCCESS, "field 3 content fetch failed\n"); + ok(!strcmp(buf,"8675309"), "field 3 content incorrect\n"); + + r = MsiCloseHandle(hrec); + ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n"); + + /* open a select query */ + hrec = 100; + query = "SELECT * FROM `phone` WHERE `id` >= 10"; + r = do_query(hdb, query, &hrec); + ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch failed\n"); + ok(hrec == 0, "hrec should be null\n"); + + r = MsiCloseHandle(hrec); + ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n"); + + query = "SELECT * FROM `phone` WHERE `id` < 0"; + r = do_query(hdb, query, &hrec); + ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch failed\n"); + + query = "SELECT * FROM `phone` WHERE `id` <= 0"; + r = do_query(hdb, query, &hrec); + ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch failed\n"); + + query = "SELECT * FROM `phone` WHERE `id` <> 1"; + r = do_query(hdb, query, &hrec); + ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch failed\n"); + + query = "SELECT * FROM `phone` WHERE `id` > 10"; + r = do_query(hdb, query, &hrec); + ok(r == ERROR_NO_MORE_ITEMS, "MsiViewFetch failed\n"); + + /* now try a few bad INSERT xqueries */ + query = "INSERT INTO `phone` ( `id`, `name`, `number` )" + "VALUES(?, ?)"; + r = MsiDatabaseOpenView(hdb, query, &hview); + ok(r == ERROR_BAD_QUERY_SYNTAX, "MsiDatabaseOpenView failed\n"); + + /* construct a record to insert */ + hrec = MsiCreateRecord(4); + r = MsiRecordSetInteger(hrec, 1, 2); + ok(r == ERROR_SUCCESS, "MsiRecordSetInteger failed\n"); + r = MsiRecordSetString(hrec, 2, "Adam"); + ok(r == ERROR_SUCCESS, "MsiRecordSetString failed\n"); + r = MsiRecordSetString(hrec, 3, "96905305"); + ok(r == ERROR_SUCCESS, "MsiRecordSetString failed\n"); + + /* insert another value, using a record and wildcards */ + query = "INSERT INTO `phone` ( `id`, `name`, `number` )" + "VALUES(?, ?, ?)"; + r = MsiDatabaseOpenView(hdb, query, &hview); + ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n"); + + if (r == ERROR_SUCCESS) + { + r = MsiViewExecute(hview, hrec); + ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n"); + r = MsiViewClose(hview); + ok(r == ERROR_SUCCESS, "MsiViewClose failed\n"); + r = MsiCloseHandle(hview); + ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n"); + } + r = MsiCloseHandle(hrec); + ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n"); + + r = MsiViewFetch(0, NULL); + ok(r == ERROR_INVALID_PARAMETER, "MsiViewFetch failed\n"); + + r = MsiDatabaseCommit(hdb); + ok(r == ERROR_SUCCESS, "MsiDatabaseCommit failed\n"); + + r = MsiCloseHandle(hdb); + ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n"); + + r = DeleteFile(msifile); + ok(r == TRUE, "file didn't exist after commit\n"); +} + +static UINT try_query_param( MSIHANDLE hdb, LPCSTR szQuery, MSIHANDLE hrec ) +{ + MSIHANDLE htab = 0; + UINT res; + + res = MsiDatabaseOpenView( hdb, szQuery, &htab ); + if(res == ERROR_SUCCESS ) + { + UINT r; + + r = MsiViewExecute( htab, hrec ); + if(r != ERROR_SUCCESS ) + res = r; + + r = MsiViewClose( htab ); + if(r != ERROR_SUCCESS ) + res = r; + + r = MsiCloseHandle( htab ); + if(r != ERROR_SUCCESS ) + res = r; + } + return res; +} + +static UINT try_query( MSIHANDLE hdb, LPCSTR szQuery ) +{ + return try_query_param( hdb, szQuery, 0 ); +} + +static UINT try_insert_query( MSIHANDLE hdb, LPCSTR szQuery ) +{ + MSIHANDLE hrec = 0; + UINT r; + + hrec = MsiCreateRecord( 1 ); + MsiRecordSetString( hrec, 1, "Hello"); + + r = try_query_param( hdb, szQuery, hrec ); + + MsiCloseHandle( hrec ); + return r; +} + +static void test_msibadqueries(void) +{ + MSIHANDLE hdb = 0; + UINT r; + + DeleteFile(msifile); + + /* just MsiOpenDatabase should not create a file */ + r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb); + ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n"); + + r = MsiDatabaseCommit( hdb ); + ok(r == ERROR_SUCCESS , "Failed to commit database\n"); + + r = MsiCloseHandle( hdb ); + ok(r == ERROR_SUCCESS , "Failed to close database\n"); + + /* open it readonly */ + r = MsiOpenDatabase(msifile, MSIDBOPEN_READONLY, &hdb ); + ok(r == ERROR_SUCCESS , "Failed to open database r/o\n"); + + /* add a table to it */ + r = try_query( hdb, "select * from _Tables"); + ok(r == ERROR_SUCCESS , "query 1 failed\n"); + + r = MsiCloseHandle( hdb ); + ok(r == ERROR_SUCCESS , "Failed to close database r/o\n"); + + /* open it read/write */ + r = MsiOpenDatabase(msifile, MSIDBOPEN_TRANSACT, &hdb ); + ok(r == ERROR_SUCCESS , "Failed to open database r/w\n"); + + /* a bunch of test queries that fail with the native MSI */ + + r = try_query( hdb, "CREATE TABLE"); + ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2a return code\n"); + + r = try_query( hdb, "CREATE TABLE `a`"); + ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2b return code\n"); + + r = try_query( hdb, "CREATE TABLE `a` ()"); + ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2c return code\n"); + + r = try_query( hdb, "CREATE TABLE `a` (`b`)"); + ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2d return code\n"); + + r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) )"); + ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2e return code\n"); + + r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL)"); + ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2f return code\n"); + + r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY)"); + ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2g return code\n"); + + r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY)"); + ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2h return code\n"); + + r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY)"); + ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2i return code\n"); + + r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY 'b')"); + ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2j return code\n"); + + r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY `b')"); + ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2k return code\n"); + + r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY `b')"); + ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2l return code\n"); + + r = try_query( hdb, "CREATE TABLE `a` (`b` CHA(72) NOT NULL PRIMARY KEY `b`)"); + ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2m return code\n"); + + r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(-1) NOT NULL PRIMARY KEY `b`)"); + ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2n return code\n"); + + r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(720) NOT NULL PRIMARY KEY `b`)"); + ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2o return code\n"); + + r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL KEY `b`)"); + ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2p return code\n"); + + r = try_query( hdb, "CREATE TABLE `a` (`` CHAR(72) NOT NULL PRIMARY KEY `b`)"); + ok(r == ERROR_BAD_QUERY_SYNTAX , "invalid query 2p return code\n"); + + r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY `b`)"); + ok(r == ERROR_SUCCESS , "valid query 2z failed\n"); + + r = try_query( hdb, "CREATE TABLE `a` (`b` CHAR(72) NOT NULL PRIMARY KEY `b`)"); + ok(r == ERROR_BAD_QUERY_SYNTAX , "created same table again\n"); + + r = try_query( hdb, "CREATE TABLE `aa` (`b` CHAR(72) NOT NULL, `c` " + "CHAR(72), `d` CHAR(255) NOT NULL LOCALIZABLE PRIMARY KEY `b`)"); + ok(r == ERROR_SUCCESS , "query 4 failed\n"); + + r = MsiDatabaseCommit( hdb ); + ok(r == ERROR_SUCCESS , "Failed to commit database after write\n"); + + r = try_query( hdb, "CREATE TABLE `blah` (`foo` CHAR(72) NOT NULL " + "PRIMARY KEY `foo`)"); + ok(r == ERROR_SUCCESS , "query 4 failed\n"); + + r = try_insert_query( hdb, "insert into a ( `b` ) VALUES ( ? )"); + ok(r == ERROR_SUCCESS , "failed to insert record in db\n"); + + r = MsiDatabaseCommit( hdb ); + ok(r == ERROR_SUCCESS , "Failed to commit database after write\n"); + + r = try_query( hdb, "CREATE TABLE `boo` (`foo` CHAR(72) NOT NULL " + "PRIMARY KEY `ba`)"); + ok(r != ERROR_SUCCESS , "query 5 succeeded\n"); + + r = try_query( hdb,"CREATE TABLE `bee` (`foo` CHAR(72) NOT NULL )"); + ok(r != ERROR_SUCCESS , "query 6 succeeded\n"); + + r = try_query( hdb, "CREATE TABLE `temp` (`t` CHAR(72) NOT NULL " + "PRIMARY KEY `t`)"); + ok(r == ERROR_SUCCESS , "query 7 failed\n"); + + r = try_query( hdb, "CREATE TABLE `c` (`b` CHAR NOT NULL PRIMARY KEY `b`)"); + ok(r == ERROR_SUCCESS , "query 8 failed\n"); + + r = try_query( hdb, "select * from c"); + ok(r == ERROR_SUCCESS , "query failed\n"); + + r = try_query( hdb, "select * from c where b = 'x"); + ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n"); + + r = try_query( hdb, "select * from c where b = 'x'"); + ok(r == ERROR_SUCCESS, "query failed\n"); + + r = try_query( hdb, "select * from 'c'"); + ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n"); + + r = try_query( hdb, "select * from ''"); + ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n"); + + r = try_query( hdb, "select * from c where b = x"); + ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n"); + + r = try_query( hdb, "select * from c where b = \"x\""); + ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n"); + + r = try_query( hdb, "select * from c where b = 'x'"); + ok(r == ERROR_SUCCESS, "query failed\n"); + + r = try_query( hdb, "select * from c where b = '\"x'"); + ok(r == ERROR_SUCCESS, "query failed\n"); + + if (0) /* FIXME: this query causes trouble with other tests */ + { + r = try_query( hdb, "select * from c where b = '\\\'x'"); + ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n"); + } + + r = try_query( hdb, "select * from 'c'"); + ok(r == ERROR_BAD_QUERY_SYNTAX, "query failed\n"); + + r = try_query( hdb, "select `c`.`b` from `c` order by `c`.`order`"); + ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %u\n", r ); + + r = try_query( hdb, "select `c`.b` from `c`"); + ok( r == ERROR_SUCCESS, "query failed: %u\n", r ); + + r = try_query( hdb, "select `c`.`b from `c`"); + ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %u\n", r ); + + r = try_query( hdb, "select `c`.b from `c`"); + ok( r == ERROR_SUCCESS, "query failed: %u\n", r ); + + r = try_query( hdb, "select `c.`b` from `c`"); + ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %u\n", r ); + + r = try_query( hdb, "select c`.`b` from `c`"); + ok( r == ERROR_SUCCESS, "query failed: %u\n", r ); + + r = try_query( hdb, "select c.`b` from `c`"); + ok( r == ERROR_SUCCESS, "query failed: %u\n", r ); + + r = try_query( hdb, "select `c`.`b` from c`"); + ok( r == ERROR_SUCCESS, "query failed: %u\n", r ); + + r = try_query( hdb, "select `c`.`b` from `c"); + ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %u\n", r ); + + r = try_query( hdb, "select `c`.`b` from c"); + ok( r == ERROR_SUCCESS, "query failed: %u\n", r ); + + r = try_query( hdb, "CREATE TABLE `\5a` (`b` CHAR NOT NULL PRIMARY KEY `b`)" ); + ok( r == ERROR_SUCCESS , "query failed: %u\n", r ); + + r = try_query( hdb, "SELECT * FROM \5a" ); + ok( r == ERROR_SUCCESS , "query failed: %u\n", r ); + + r = try_query( hdb, "CREATE TABLE `a\5` (`b` CHAR NOT NULL PRIMARY KEY `b`)" ); + ok( r == ERROR_SUCCESS , "query failed: %u\n", r ); + + r = try_query( hdb, "SELECT * FROM a\5" ); + ok( r == ERROR_SUCCESS , "query failed: %u\n", r ); + + r = try_query( hdb, "CREATE TABLE `-a` (`b` CHAR NOT NULL PRIMARY KEY `b`)" ); + ok( r == ERROR_SUCCESS , "query failed: %u\n", r ); + + r = try_query( hdb, "SELECT * FROM -a" ); + todo_wine ok( r == ERROR_SUCCESS , "query failed: %u\n", r ); + + r = try_query( hdb, "CREATE TABLE `a-` (`b` CHAR NOT NULL PRIMARY KEY `b`)" ); + ok( r == ERROR_SUCCESS , "query failed: %u\n", r ); + + r = try_query( hdb, "SELECT * FROM a-" ); + ok( r == ERROR_SUCCESS , "query failed: %u\n", r ); + + r = MsiCloseHandle( hdb ); + ok(r == ERROR_SUCCESS , "Failed to close database transact\n"); + + r = DeleteFile( msifile ); + ok(r == TRUE, "file didn't exist after commit\n"); +} + +static void test_viewmodify(void) +{ + MSIHANDLE hdb = 0, hview = 0, hrec = 0; + UINT r; + MSIDBERROR err; + const char *query; + char buffer[0x100]; + DWORD sz; + + DeleteFile(msifile); + + /* just MsiOpenDatabase should not create a file */ + r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb); + ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n"); + + query = "CREATE TABLE `phone` ( " + "`id` INT, `name` CHAR(32), `number` CHAR(32) " + "PRIMARY KEY `id`)"; + r = run_query( hdb, 0, query ); + ok(r == ERROR_SUCCESS, "query failed\n"); + + query = "CREATE TABLE `_Validation` ( " + "`Table` CHAR(32) NOT NULL, `Column` CHAR(32) NOT NULL, " + "`Nullable` CHAR(4) NOT NULL, `MinValue` INT, `MaxValue` INT, " + "`KeyTable` CHAR(255), `KeyColumn` SHORT, `Category` CHAR(32), " + "`Set` CHAR(255), `Description` CHAR(255) PRIMARY KEY `Table`, `Column`)"; + r = run_query( hdb, 0, query ); + ok(r == ERROR_SUCCESS, "query failed\n"); + + query = "INSERT INTO `_Validation` ( `Table`, `Column`, `Nullable` ) " + "VALUES('phone', 'id', 'N')"; + r = run_query( hdb, 0, query ); + ok(r == ERROR_SUCCESS, "query failed\n"); + + /* check what the error function reports without doing anything */ + sz = 0; + /* passing NULL as the 3rd param make function to crash on older platforms */ + err = MsiViewGetError( 0, NULL, &sz ); + ok(err == MSIDBERROR_INVALIDARG, "MsiViewGetError return\n"); + + /* open a view */ + query = "SELECT * FROM `phone`"; + r = MsiDatabaseOpenView(hdb, query, &hview); + ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n"); + + /* see what happens with a good hview and bad args */ + err = MsiViewGetError( hview, NULL, NULL ); + ok(err == MSIDBERROR_INVALIDARG || err == MSIDBERROR_NOERROR, + "MsiViewGetError returns %u (expected -3)\n", err); + err = MsiViewGetError( hview, buffer, NULL ); + ok(err == MSIDBERROR_INVALIDARG, "MsiViewGetError return\n"); + + /* see what happens with a zero length buffer */ + sz = 0; + buffer[0] = 'x'; + err = MsiViewGetError( hview, buffer, &sz ); + ok(err == MSIDBERROR_MOREDATA, "MsiViewGetError return\n"); + ok(buffer[0] == 'x', "buffer cleared\n"); + ok(sz == 0, "size not zero\n"); + + /* ok this one is strange */ + sz = 0; + err = MsiViewGetError( hview, NULL, &sz ); + ok(err == MSIDBERROR_NOERROR, "MsiViewGetError return\n"); + ok(sz == 0, "size not zero\n"); + + /* see if it really has an error */ + sz = sizeof buffer; + buffer[0] = 'x'; + err = MsiViewGetError( hview, buffer, &sz ); + ok(err == MSIDBERROR_NOERROR, "MsiViewGetError return\n"); + ok(buffer[0] == 0, "buffer not cleared\n"); + ok(sz == 0, "size not zero\n"); + + r = MsiViewExecute(hview, 0); + ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n"); + + /* try some invalid records */ + r = MsiViewModify(hview, MSIMODIFY_INSERT, 0 ); + ok(r == ERROR_INVALID_HANDLE, "MsiViewModify failed\n"); + r = MsiViewModify(hview, -1, 0 ); + ok(r == ERROR_INVALID_HANDLE, "MsiViewModify failed\n"); + + /* try an small record */ + hrec = MsiCreateRecord(1); + r = MsiViewModify(hview, -1, hrec ); + ok(r == ERROR_INVALID_DATA, "MsiViewModify failed\n"); + + sz = sizeof buffer; + buffer[0] = 'x'; + err = MsiViewGetError( hview, buffer, &sz ); + ok(err == MSIDBERROR_NOERROR, "MsiViewGetError return\n"); + ok(buffer[0] == 0, "buffer not cleared\n"); + ok(sz == 0, "size not zero\n"); + + r = MsiCloseHandle(hrec); + ok(r == ERROR_SUCCESS, "failed to close record\n"); + + /* insert a valid record */ + hrec = MsiCreateRecord(3); + + r = MsiRecordSetInteger(hrec, 1, 1); + ok(r == ERROR_SUCCESS, "failed to set integer\n"); + r = MsiRecordSetString(hrec, 2, "bob"); + ok(r == ERROR_SUCCESS, "failed to set string\n"); + r = MsiRecordSetString(hrec, 3, "7654321"); + ok(r == ERROR_SUCCESS, "failed to set string\n"); + + r = MsiViewExecute(hview, 0); + ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n"); + r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec ); + ok(r == ERROR_SUCCESS, "MsiViewModify failed\n"); + + /* validate it */ + r = MsiViewExecute(hview, 0); + ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n"); + + r = MsiViewModify(hview, MSIMODIFY_VALIDATE_NEW, hrec ); + ok(r == ERROR_INVALID_DATA, "MsiViewModify failed %u\n", r); + + sz = sizeof buffer; + buffer[0] = 'x'; + err = MsiViewGetError( hview, buffer, &sz ); + ok(err == MSIDBERROR_DUPLICATEKEY, "MsiViewGetError returned %u\n", err); + ok(!strcmp(buffer, "id"), "expected \"id\" c, got \"%s\"\n", buffer); + ok(sz == 2, "size not 2\n"); + + /* insert the same thing again */ + r = MsiViewExecute(hview, 0); + ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n"); + + /* should fail ... */ + r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec ); + ok(r == ERROR_FUNCTION_FAILED, "MsiViewModify failed\n"); + + /* try to merge the same record */ + r = MsiViewExecute(hview, 0); + ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n"); + r = MsiViewModify(hview, MSIMODIFY_MERGE, hrec ); + ok(r == ERROR_SUCCESS, "MsiViewModify failed\n"); + + r = MsiCloseHandle(hrec); + ok(r == ERROR_SUCCESS, "failed to close record\n"); + + /* try merging a new record */ + hrec = MsiCreateRecord(3); + + r = MsiRecordSetInteger(hrec, 1, 10); + ok(r == ERROR_SUCCESS, "failed to set integer\n"); + r = MsiRecordSetString(hrec, 2, "pepe"); + ok(r == ERROR_SUCCESS, "failed to set string\n"); + r = MsiRecordSetString(hrec, 3, "7654321"); + ok(r == ERROR_SUCCESS, "failed to set string\n"); + + r = MsiViewModify(hview, MSIMODIFY_MERGE, hrec ); + ok(r == ERROR_SUCCESS, "MsiViewModify failed\n"); + r = MsiViewExecute(hview, 0); + ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n"); + + r = MsiCloseHandle(hrec); + ok(r == ERROR_SUCCESS, "failed to close record\n"); + + r = MsiViewClose(hview); + ok(r == ERROR_SUCCESS, "MsiViewClose failed\n"); + r = MsiCloseHandle(hview); + ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n"); + + query = "SELECT * FROM `phone`"; + r = MsiDatabaseOpenView(hdb, query, &hview); + ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n"); + + r = MsiViewExecute(hview, 0); + ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n"); + + r = MsiViewFetch(hview, &hrec); + ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n"); + + r = MsiRecordGetInteger(hrec, 1); + ok(r == 1, "Expected 1, got %d\n", r); + + sz = sizeof(buffer); + r = MsiRecordGetString(hrec, 2, buffer, &sz); + ok(r == ERROR_SUCCESS, "MsiRecordGetString failed\n"); + ok(!lstrcmp(buffer, "bob"), "Expected bob, got %s\n", buffer); + + sz = sizeof(buffer); + r = MsiRecordGetString(hrec, 3, buffer, &sz); + ok(r == ERROR_SUCCESS, "MsiRecordGetString failed\n"); + ok(!lstrcmp(buffer, "7654321"), "Expected 7654321, got %s\n", buffer); + + /* update the view, non-primary key */ + r = MsiRecordSetString(hrec, 3, "3141592"); + ok(r == ERROR_SUCCESS, "MsiRecordSetString failed\n"); + + r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec); + ok(r == ERROR_SUCCESS, "MsiViewModify failed\n"); + + /* do it again */ + r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec); + ok(r == ERROR_SUCCESS, "MsiViewModify failed: %d\n", r); + + /* update the view, primary key */ + r = MsiRecordSetInteger(hrec, 1, 5); + ok(r == ERROR_SUCCESS, "MsiRecordSetInteger failed\n"); + + r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec); + ok(r == ERROR_FUNCTION_FAILED, "MsiViewModify failed\n"); + + r = MsiCloseHandle(hrec); + ok(r == ERROR_SUCCESS, "failed to close record\n"); + + r = MsiViewClose(hview); + ok(r == ERROR_SUCCESS, "MsiViewClose failed\n"); + r = MsiCloseHandle(hview); + ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n"); + + query = "SELECT * FROM `phone`"; + r = MsiDatabaseOpenView(hdb, query, &hview); + ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n"); + + r = MsiViewExecute(hview, 0); + ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n"); + + r = MsiViewFetch(hview, &hrec); + ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n"); + + r = MsiRecordGetInteger(hrec, 1); + ok(r == 1, "Expected 1, got %d\n", r); + + sz = sizeof(buffer); + r = MsiRecordGetString(hrec, 2, buffer, &sz); + ok(r == ERROR_SUCCESS, "MsiRecordGetString failed\n"); + ok(!lstrcmp(buffer, "bob"), "Expected bob, got %s\n", buffer); + + sz = sizeof(buffer); + r = MsiRecordGetString(hrec, 3, buffer, &sz); + ok(r == ERROR_SUCCESS, "MsiRecordGetString failed\n"); + ok(!lstrcmp(buffer, "3141592"), "Expected 3141592, got %s\n", buffer); + + r = MsiCloseHandle(hrec); + ok(r == ERROR_SUCCESS, "failed to close record\n"); + + /* use a record that doesn't come from a view fetch */ + hrec = MsiCreateRecord(3); + ok(hrec != 0, "MsiCreateRecord failed\n"); + + r = MsiRecordSetInteger(hrec, 1, 3); + ok(r == ERROR_SUCCESS, "failed to set integer\n"); + r = MsiRecordSetString(hrec, 2, "jane"); + ok(r == ERROR_SUCCESS, "failed to set string\n"); + r = MsiRecordSetString(hrec, 3, "112358"); + ok(r == ERROR_SUCCESS, "failed to set string\n"); + + r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec); + ok(r == ERROR_FUNCTION_FAILED, "Expected ERROR_FUNCTION_FAILED, got %d\n", r); + + r = MsiCloseHandle(hrec); + ok(r == ERROR_SUCCESS, "failed to close record\n"); + + /* use a record that doesn't come from a view fetch, primary key matches */ + hrec = MsiCreateRecord(3); + ok(hrec != 0, "MsiCreateRecord failed\n"); + + r = MsiRecordSetInteger(hrec, 1, 1); + ok(r == ERROR_SUCCESS, "failed to set integer\n"); + r = MsiRecordSetString(hrec, 2, "jane"); + ok(r == ERROR_SUCCESS, "failed to set string\n"); + r = MsiRecordSetString(hrec, 3, "112358"); + ok(r == ERROR_SUCCESS, "failed to set string\n"); + + r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec); + ok(r == ERROR_FUNCTION_FAILED, "MsiViewModify failed\n"); + + r = MsiCloseHandle(hrec); + ok(r == ERROR_SUCCESS, "failed to close record\n"); + + hrec = MsiCreateRecord(3); + + r = MsiRecordSetInteger(hrec, 1, 2); + ok(r == ERROR_SUCCESS, "failed to set integer\n"); + r = MsiRecordSetString(hrec, 2, "nick"); + ok(r == ERROR_SUCCESS, "failed to set string\n"); + r = MsiRecordSetString(hrec, 3, "141421"); + ok(r == ERROR_SUCCESS, "failed to set string\n"); + + r = MsiViewExecute(hview, 0); + ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n"); + r = MsiViewModify(hview, MSIMODIFY_INSERT_TEMPORARY, hrec ); + ok(r == ERROR_SUCCESS, "MsiViewModify failed\n"); + + r = MsiCloseHandle(hrec); + ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n"); + r = MsiViewClose(hview); + ok(r == ERROR_SUCCESS, "MsiViewClose failed\n"); + r = MsiCloseHandle(hview); + ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n"); + + query = "SELECT * FROM `phone` WHERE `id` = 1"; + r = MsiDatabaseOpenView(hdb, query, &hview); + ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n"); + r = MsiViewExecute(hview, 0); + ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n"); + r = MsiViewFetch(hview, &hrec); + ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n"); + + /* change the id to match the second row */ + r = MsiRecordSetInteger(hrec, 1, 2); + ok(r == ERROR_SUCCESS, "failed to set integer\n"); + r = MsiRecordSetString(hrec, 2, "jerry"); + ok(r == ERROR_SUCCESS, "failed to set string\n"); + + r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec); + ok(r == ERROR_FUNCTION_FAILED, "MsiViewModify failed\n"); + + r = MsiCloseHandle(hrec); + ok(r == ERROR_SUCCESS, "failed to close record\n"); + r = MsiViewClose(hview); + ok(r == ERROR_SUCCESS, "MsiViewClose failed\n"); + r = MsiCloseHandle(hview); + ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n"); + + /* broader search */ + query = "SELECT * FROM `phone` ORDER BY `id`"; + r = MsiDatabaseOpenView(hdb, query, &hview); + ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n"); + r = MsiViewExecute(hview, 0); + ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n"); + r = MsiViewFetch(hview, &hrec); + ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n"); + + /* change the id to match the second row */ + r = MsiRecordSetInteger(hrec, 1, 2); + ok(r == ERROR_SUCCESS, "failed to set integer\n"); + r = MsiRecordSetString(hrec, 2, "jerry"); + ok(r == ERROR_SUCCESS, "failed to set string\n"); + + r = MsiViewModify(hview, MSIMODIFY_UPDATE, hrec); + ok(r == ERROR_FUNCTION_FAILED, "MsiViewModify failed\n"); + + r = MsiCloseHandle(hrec); + ok(r == ERROR_SUCCESS, "failed to close record\n"); + r = MsiViewClose(hview); + ok(r == ERROR_SUCCESS, "MsiViewClose failed\n"); + r = MsiCloseHandle(hview); + ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n"); + + r = MsiCloseHandle( hdb ); + 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, LPCSTR 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, 0, + "CREATE TABLE `Properties` " + "( `Property` CHAR(255), " + " `Value` CHAR(1), " + " `Intvalue` INT, " + " `Integervalue` INTEGER, " + " `Shortvalue` SHORT, " + " `Longvalue` LONG, " + " `Longcharvalue` LONGCHAR " + " 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"); + ok( check_record( rec, 3, "I2"), "wrong record type\n"); + ok( check_record( rec, 4, "I2"), "wrong record type\n"); + ok( check_record( rec, 5, "I2"), "wrong record type\n"); + ok( check_record( rec, 6, "I4"), "wrong record type\n"); + ok( check_record( rec, 7, "S0"), "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"); + ok( 0x1502 == get_columns_table_type(hdb, "Properties", 3 ), "_columns table wrong\n"); + ok( 0x1502 == get_columns_table_type(hdb, "Properties", 4 ), "_columns table wrong\n"); + ok( 0x1502 == get_columns_table_type(hdb, "Properties", 5 ), "_columns table wrong\n"); + ok( 0x1104 == get_columns_table_type(hdb, "Properties", 6 ), "_columns table wrong\n"); + ok( 0x1d00 == get_columns_table_type(hdb, "Properties", 7 ), "_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"); + ok( check_record( rec, 3, "Intvalue"), "wrong record type\n"); + ok( check_record( rec, 4, "Integervalue"), "wrong record type\n"); + ok( check_record( rec, 5, "Shortvalue"), "wrong record type\n"); + ok( check_record( rec, 6, "Longvalue"), "wrong record type\n"); + ok( check_record( rec, 7, "Longcharvalue"), "wrong record type\n"); + + MsiCloseHandle( rec ); + + r = run_query( hdb, 0, + "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, 0, + "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 ); +} + +static void test_msiexport(void) +{ + MSIHANDLE hdb = 0, hview = 0; + UINT r; + const char *query; + char path[MAX_PATH]; + const char file[] = "phone.txt"; + HANDLE handle; + char buffer[0x100]; + DWORD length; + const char expected[] = + "id\tname\tnumber\r\n" + "I2\tS32\tS32\r\n" + "phone\tid\r\n" + "1\tAbe\t8675309\r\n"; + + DeleteFile(msifile); + + /* just MsiOpenDatabase should not create a file */ + r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb); + ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n"); + + /* create a table */ + query = "CREATE TABLE `phone` ( " + "`id` INT, `name` CHAR(32), `number` CHAR(32) " + "PRIMARY KEY `id`)"; + r = MsiDatabaseOpenView(hdb, query, &hview); + ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n"); + r = MsiViewExecute(hview, 0); + ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n"); + r = MsiViewClose(hview); + ok(r == ERROR_SUCCESS, "MsiViewClose failed\n"); + r = MsiCloseHandle(hview); + ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n"); + + /* insert a value into it */ + query = "INSERT INTO `phone` ( `id`, `name`, `number` )" + "VALUES('1', 'Abe', '8675309')"; + r = MsiDatabaseOpenView(hdb, query, &hview); + ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n"); + r = MsiViewExecute(hview, 0); + ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n"); + r = MsiViewClose(hview); + ok(r == ERROR_SUCCESS, "MsiViewClose failed\n"); + r = MsiCloseHandle(hview); + ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n"); + + GetCurrentDirectory(MAX_PATH, path); + + r = MsiDatabaseExport(hdb, "phone", path, file); + ok(r == ERROR_SUCCESS, "MsiDatabaseExport failed\n"); + + MsiCloseHandle(hdb); + + lstrcat(path, "\\"); + lstrcat(path, file); + + /* check the data that was written */ + length = 0; + memset(buffer, 0, sizeof buffer); + handle = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL); + if (handle != INVALID_HANDLE_VALUE) + { + ReadFile(handle, buffer, sizeof buffer, &length, NULL); + CloseHandle(handle); + DeleteFile(path); + } + else + ok(0, "failed to open file %s\n", path); + + ok( length == strlen(expected), "length of data wrong\n"); + ok( !lstrcmp(buffer, expected), "data doesn't match\n"); + DeleteFile(msifile); +} + +static void test_longstrings(void) +{ + const char insert_query[] = + "INSERT INTO `strings` ( `id`, `val` ) VALUES('1', 'Z')"; + char *str; + MSIHANDLE hdb = 0, hview = 0, hrec = 0; + DWORD len; + UINT r; + const DWORD STRING_LENGTH = 0x10005; + + DeleteFile(msifile); + /* just MsiOpenDatabase should not create a file */ + r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb); + ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n"); + + /* create a table */ + r = try_query( hdb, + "CREATE TABLE `strings` ( `id` INT, `val` CHAR(0) PRIMARY KEY `id`)"); + ok(r == ERROR_SUCCESS, "query failed\n"); + + /* try a insert a very long string */ + str = HeapAlloc(GetProcessHeap(), 0, STRING_LENGTH+sizeof insert_query); + len = strchr(insert_query, 'Z') - insert_query; + strcpy(str, insert_query); + memset(str+len, 'Z', STRING_LENGTH); + strcpy(str+len+STRING_LENGTH, insert_query+len+1); + r = try_query( hdb, str ); + ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n"); + + HeapFree(GetProcessHeap(), 0, str); + + r = MsiDatabaseCommit(hdb); + ok(r == ERROR_SUCCESS, "MsiDatabaseCommit failed\n"); + MsiCloseHandle(hdb); + + r = MsiOpenDatabase(msifile, MSIDBOPEN_READONLY, &hdb); + ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n"); + + r = MsiDatabaseOpenView(hdb, "select * from `strings` where `id` = 1", &hview); + ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n"); + + r = MsiViewExecute(hview, 0); + ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n"); + + r = MsiViewFetch(hview, &hrec); + ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n"); + + MsiViewClose(hview); + MsiCloseHandle(hview); + + r = MsiRecordGetString(hrec, 2, NULL, &len); + ok(r == ERROR_SUCCESS, "MsiViewFetch failed\n"); + ok(len == STRING_LENGTH, "string length wrong\n"); + + MsiCloseHandle(hrec); + MsiCloseHandle(hdb); + DeleteFile(msifile); +} + +static void create_file_data(LPCSTR name, LPCSTR data, DWORD size) +{ + HANDLE file; + DWORD written; + + file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); + if (file == INVALID_HANDLE_VALUE) + return; + + WriteFile(file, data, strlen(data), &written, NULL); + WriteFile(file, "\n", strlen("\n"), &written, NULL); + + if (size) + { + SetFilePointer(file, size, NULL, FILE_BEGIN); + SetEndOfFile(file); + } + + CloseHandle(file); +} + +#define create_file(name) create_file_data(name, name, 0) + +static void test_streamtable(void) +{ + MSIHANDLE hdb = 0, rec, view, hsi; + char file[MAX_PATH]; + char buf[MAX_PATH]; + DWORD size; + UINT r; + + hdb = create_db(); + ok( hdb, "failed to create db\n"); + + r = run_query( hdb, 0, + "CREATE TABLE `Properties` " + "( `Property` CHAR(255), `Value` CHAR(1) PRIMARY KEY `Property`)" ); + ok( r == ERROR_SUCCESS , "Failed to create table\n" ); + + r = run_query( hdb, 0, + "INSERT INTO `Properties` " + "( `Value`, `Property` ) VALUES ( 'Prop', 'value' )" ); + ok( r == ERROR_SUCCESS, "Failed to add to table\n" ); + + r = MsiDatabaseCommit( hdb ); + ok( r == ERROR_SUCCESS , "Failed to commit database\n" ); + + MsiCloseHandle( hdb ); + + r = MsiOpenDatabase(msifile, MSIDBOPEN_TRANSACT, &hdb ); + ok( r == ERROR_SUCCESS , "Failed to open database\n" ); + + /* check the column types */ + rec = get_column_info( hdb, "select * from `_Streams`", MSICOLINFO_TYPES ); + ok( rec, "failed to get column info record\n" ); + + ok( check_record( rec, 1, "s62"), "wrong record type\n"); + ok( check_record( rec, 2, "V0"), "wrong record type\n"); + + MsiCloseHandle( rec ); + + /* now try the names */ + rec = get_column_info( hdb, "select * from `_Streams`", 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 = MsiDatabaseOpenView( hdb, + "SELECT * FROM `_Streams` WHERE `Name` = '\5SummaryInformation'", &view ); + ok( r == ERROR_SUCCESS, "Failed to open database view: %u\n", r ); + + r = MsiViewExecute( view, 0 ); + ok( r == ERROR_SUCCESS, "Failed to execute view: %u\n", r ); + + r = MsiViewFetch( view, &rec ); + ok( r == ERROR_NO_MORE_ITEMS, "Unexpected result: %u\n", r ); + + MsiCloseHandle( rec ); + MsiViewClose( view ); + MsiCloseHandle( view ); + + /* create a summary information stream */ + r = MsiGetSummaryInformationA( hdb, NULL, 1, &hsi ); + ok( r == ERROR_SUCCESS, "Failed to get summary information handle: %u\n", r ); + + r = MsiSummaryInfoSetPropertyA( hsi, MSI_PID_SECURITY, VT_I4, 2, NULL, NULL ); + ok( r == ERROR_SUCCESS, "Failed to set property: %u\n", r ); + + r = MsiSummaryInfoPersist( hsi ); + ok( r == ERROR_SUCCESS, "Failed to save summary information: %u\n", r ); + + MsiCloseHandle( hsi ); + + r = MsiDatabaseOpenView( hdb, + "SELECT * FROM `_Streams` WHERE `Name` = '\5SummaryInformation'", &view ); + ok( r == ERROR_SUCCESS, "Failed to open database view: %u\n", r ); + + r = MsiViewExecute( view, 0 ); + ok( r == ERROR_SUCCESS, "Failed to execute view: %u\n", r ); + + r = MsiViewFetch( view, &rec ); + ok( r == ERROR_SUCCESS, "Unexpected result: %u\n", r ); + + MsiCloseHandle( rec ); + MsiViewClose( view ); + MsiCloseHandle( view ); + + /* insert a file into the _Streams table */ + create_file( "test.txt" ); + + rec = MsiCreateRecord( 2 ); + MsiRecordSetString( rec, 1, "data" ); + + r = MsiRecordSetStream( rec, 2, "test.txt" ); + ok( r == ERROR_SUCCESS, "Failed to add stream data to the record: %d\n", r); + + DeleteFile("test.txt"); + + r = MsiDatabaseOpenView( hdb, + "INSERT INTO `_Streams` ( `Name`, `Data` ) VALUES ( ?, ? )", &view ); + ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r); + + r = MsiViewExecute( view, rec ); + ok( r == ERROR_SUCCESS, "Failed to execute view: %d\n", r); + + MsiCloseHandle( rec ); + MsiViewClose( view ); + MsiCloseHandle( view ); + + /* insert another one */ + create_file( "test1.txt" ); + + rec = MsiCreateRecord( 2 ); + MsiRecordSetString( rec, 1, "data1" ); + + r = MsiRecordSetStream( rec, 2, "test1.txt" ); + ok( r == ERROR_SUCCESS, "Failed to add stream data to the record: %d\n", r); + + DeleteFile("test1.txt"); + + r = MsiDatabaseOpenView( hdb, + "INSERT INTO `_Streams` ( `Name`, `Data` ) VALUES ( ?, ? )", &view ); + ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r); + + r = MsiViewExecute( view, rec ); + ok( r == ERROR_SUCCESS, "Failed to execute view: %d\n", r); + + MsiCloseHandle( rec ); + MsiViewClose( view ); + MsiCloseHandle( view ); + + r = MsiDatabaseOpenView( hdb, + "SELECT `Name`, `Data` FROM `_Streams` WHERE `Name` = 'data'", &view ); + ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r); + + r = MsiViewExecute( view, 0 ); + ok( r == ERROR_SUCCESS, "Failed to execute view: %d\n", r); + + r = MsiViewFetch( view, &rec ); + ok( r == ERROR_SUCCESS, "Failed to fetch record: %d\n", r); + + size = MAX_PATH; + r = MsiRecordGetString( rec, 1, file, &size ); + ok( r == ERROR_SUCCESS, "Failed to get string: %d\n", r); + ok( !lstrcmp(file, "data"), "Expected 'data', got %s\n", file); + + size = MAX_PATH; + memset(buf, 0, MAX_PATH); + r = MsiRecordReadStream( rec, 2, buf, &size ); + ok( r == ERROR_SUCCESS, "Failed to get stream: %d\n", r); + ok( !lstrcmp(buf, "test.txt\n"), "Expected 'test.txt\\n', got %s\n", buf); + + MsiCloseHandle( rec ); + MsiViewClose( view ); + MsiCloseHandle( view ); + + r = MsiDatabaseOpenView( hdb, + "SELECT `Name`, `Data` FROM `_Streams` WHERE `Name` = 'data1'", &view ); + ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r); + + r = MsiViewExecute( view, 0 ); + ok( r == ERROR_SUCCESS, "Failed to execute view: %d\n", r); + + r = MsiViewFetch( view, &rec ); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + size = MAX_PATH; + r = MsiRecordGetString( rec, 1, file, &size ); + ok( r == ERROR_SUCCESS, "Failed to get string: %d\n", r); + ok( !lstrcmp(file, "data1"), "Expected 'data1', got %s\n", file); + + size = MAX_PATH; + memset(buf, 0, MAX_PATH); + r = MsiRecordReadStream( rec, 2, buf, &size ); + ok( r == ERROR_SUCCESS, "Failed to get stream: %d\n", r); + ok( !lstrcmp(buf, "test1.txt\n"), "Expected 'test1.txt\\n', got %s\n", buf); + + MsiCloseHandle( rec ); + MsiViewClose( view ); + MsiCloseHandle( view ); + + /* perform an update */ + create_file( "test2.txt" ); + rec = MsiCreateRecord( 1 ); + + r = MsiRecordSetStream( rec, 1, "test2.txt" ); + ok( r == ERROR_SUCCESS, "Failed to add stream data to the record: %d\n", r); + + DeleteFile("test2.txt"); + + r = MsiDatabaseOpenView( hdb, + "UPDATE `_Streams` SET `Data` = ? WHERE `Name` = 'data1'", &view ); + ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r); + + r = MsiViewExecute( view, rec ); + ok( r == ERROR_SUCCESS, "Failed to execute view: %d\n", r); + + MsiCloseHandle( rec ); + MsiViewClose( view ); + MsiCloseHandle( view ); + + r = MsiDatabaseOpenView( hdb, + "SELECT `Name`, `Data` FROM `_Streams` WHERE `Name` = 'data1'", &view ); + ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r); + + r = MsiViewExecute( view, 0 ); + ok( r == ERROR_SUCCESS, "Failed to execute view: %d\n", r); + + r = MsiViewFetch( view, &rec ); + ok( r == ERROR_SUCCESS, "Failed to fetch record: %d\n", r); + + size = MAX_PATH; + r = MsiRecordGetString( rec, 1, file, &size ); + ok( r == ERROR_SUCCESS, "Failed to get string: %d\n", r); + ok( !lstrcmp(file, "data1"), "Expected 'data1', got %s\n", file); + + size = MAX_PATH; + memset(buf, 0, MAX_PATH); + r = MsiRecordReadStream( rec, 2, buf, &size ); + ok( r == ERROR_SUCCESS, "Failed to get stream: %d\n", r); + todo_wine ok( !lstrcmp(buf, "test2.txt\n"), "Expected 'test2.txt\\n', got %s\n", buf); + + MsiCloseHandle( rec ); + MsiViewClose( view ); + MsiCloseHandle( view ); + MsiCloseHandle( hdb ); + DeleteFile(msifile); +} + +static void test_binary(void) +{ + MSIHANDLE hdb = 0, rec; + char file[MAX_PATH]; + char buf[MAX_PATH]; + DWORD size; + LPCSTR query; + UINT r; + + /* insert a file into the Binary table */ + r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb ); + ok( r == ERROR_SUCCESS , "Failed to open database\n" ); + + query = "CREATE TABLE `Binary` ( `Name` CHAR(72) NOT NULL, `ID` INT NOT NULL, `Data` OBJECT PRIMARY KEY `Name`, `ID`)"; + r = run_query( hdb, 0, query ); + ok( r == ERROR_SUCCESS, "Cannot create Binary table: %d\n", r ); + + create_file( "test.txt" ); + rec = MsiCreateRecord( 1 ); + r = MsiRecordSetStream( rec, 1, "test.txt" ); + ok( r == ERROR_SUCCESS, "Failed to add stream data to the record: %d\n", r); + DeleteFile( "test.txt" ); + + query = "INSERT INTO `Binary` ( `Name`, `ID`, `Data` ) VALUES ( 'filename1', 1, ? )"; + r = run_query( hdb, rec, query ); + ok( r == ERROR_SUCCESS, "Insert into Binary table failed: %d\n", r ); + + r = MsiCloseHandle( rec ); + ok( r == ERROR_SUCCESS , "Failed to close record handle\n" ); + + r = MsiDatabaseCommit( hdb ); + ok( r == ERROR_SUCCESS , "Failed to commit database\n" ); + + r = MsiCloseHandle( hdb ); + ok( r == ERROR_SUCCESS , "Failed to close database\n" ); + + /* read file from the Stream table */ + r = MsiOpenDatabase( msifile, MSIDBOPEN_READONLY, &hdb ); + ok( r == ERROR_SUCCESS , "Failed to open database\n" ); + + query = "SELECT * FROM `_Streams`"; + r = do_query( hdb, query, &rec ); + ok( r == ERROR_SUCCESS, "SELECT query failed: %d\n", r ); + + size = MAX_PATH; + r = MsiRecordGetString( rec, 1, file, &size ); + ok( r == ERROR_SUCCESS, "Failed to get string: %d\n", r ); + ok( !lstrcmp(file, "Binary.filename1.1"), "Expected 'Binary.filename1.1', got %s\n", file ); + + size = MAX_PATH; + memset( buf, 0, MAX_PATH ); + r = MsiRecordReadStream( rec, 2, buf, &size ); + ok( r == ERROR_SUCCESS, "Failed to get stream: %d\n", r ); + ok( !lstrcmp(buf, "test.txt\n"), "Expected 'test.txt\\n', got %s\n", buf ); + + r = MsiCloseHandle( rec ); + ok( r == ERROR_SUCCESS , "Failed to close record handle\n" ); + + /* read file from the Binary table */ + query = "SELECT * FROM `Binary`"; + r = do_query( hdb, query, &rec ); + ok( r == ERROR_SUCCESS, "SELECT query failed: %d\n", r ); + + size = MAX_PATH; + r = MsiRecordGetString( rec, 1, file, &size ); + ok( r == ERROR_SUCCESS, "Failed to get string: %d\n", r ); + ok( !lstrcmp(file, "filename1"), "Expected 'filename1', got %s\n", file ); + + size = MAX_PATH; + memset( buf, 0, MAX_PATH ); + r = MsiRecordReadStream( rec, 3, buf, &size ); + ok( r == ERROR_SUCCESS, "Failed to get stream: %d\n", r ); + ok( !lstrcmp(buf, "test.txt\n"), "Expected 'test.txt\\n', got %s\n", buf ); + + r = MsiCloseHandle( rec ); + ok( r == ERROR_SUCCESS , "Failed to close record handle\n" ); + + r = MsiCloseHandle( hdb ); + ok( r == ERROR_SUCCESS , "Failed to close database\n" ); + + DeleteFile( msifile ); +} + +static void test_where_not_in_selected(void) +{ + MSIHANDLE hdb = 0, rec, view; + LPCSTR query; + UINT r; + + hdb = create_db(); + ok( hdb, "failed to create db\n"); + + r = run_query(hdb, 0, + "CREATE TABLE `IESTable` (" + "`Action` CHAR(64), " + "`Condition` CHAR(64), " + "`Sequence` LONG PRIMARY KEY `Sequence`)"); + ok( r == S_OK, "Cannot create IESTable table: %d\n", r); + + r = run_query(hdb, 0, + "CREATE TABLE `CATable` (" + "`Action` CHAR(64), " + "`Type` LONG PRIMARY KEY `Type`)"); + ok( r == S_OK, "Cannot create CATable table: %d\n", r); + + r = run_query(hdb, 0, "INSERT INTO `IESTable` " + "( `Action`, `Condition`, `Sequence`) " + "VALUES ( 'clean', 'cond4', 4)"); + ok( r == S_OK, "cannot add entry to IESTable table:%d\n", r ); + + r = run_query(hdb, 0, "INSERT INTO `IESTable` " + "( `Action`, `Condition`, `Sequence`) " + "VALUES ( 'depends', 'cond1', 1)"); + ok( r == S_OK, "cannot add entry to IESTable table:%d\n", r ); + + r = run_query(hdb, 0, "INSERT INTO `IESTable` " + "( `Action`, `Condition`, `Sequence`) " + "VALUES ( 'build', 'cond2', 2)"); + ok( r == S_OK, "cannot add entry to IESTable table:%d\n", r ); + + r = run_query(hdb, 0, "INSERT INTO `IESTable` " + "( `Action`, `Condition`, `Sequence`) " + "VALUES ( 'build2', 'cond6', 6)"); + ok( r == S_OK, "cannot add entry to IESTable table:%d\n", r ); + + r = run_query(hdb, 0, "INSERT INTO `IESTable` " + "( `Action`, `Condition`, `Sequence`) " + "VALUES ( 'build', 'cond3', 3)"); + ok(r == S_OK, "cannot add entry to IESTable table:%d\n", r ); + + r = run_query(hdb, 0, "INSERT INTO `CATable` " + "( `Action`, `Type` ) " + "VALUES ( 'build', 32)"); + ok(r == S_OK, "cannot add entry to CATable table:%d\n", r ); + + r = run_query(hdb, 0, "INSERT INTO `CATable` " + "( `Action`, `Type` ) " + "VALUES ( 'depends', 64)"); + ok(r == S_OK, "cannot add entry to CATable table:%d\n", r ); + + r = run_query(hdb, 0, "INSERT INTO `CATable` " + "( `Action`, `Type` ) " + "VALUES ( 'clean', 63)"); + ok(r == S_OK, "cannot add entry to CATable table:%d\n", r ); + + r = run_query(hdb, 0, "INSERT INTO `CATable` " + "( `Action`, `Type` ) " + "VALUES ( 'build2', 34)"); + ok(r == S_OK, "cannot add entry to CATable table:%d\n", r ); + query = "Select IESTable.Condition from CATable, IESTable where " + "CATable.Action = IESTable.Action and CATable.Type = 32"; + r = MsiDatabaseOpenView(hdb, query, &view); + ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r ); + + r = MsiViewExecute(view, 0); + ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r ); + + r = MsiViewFetch(view, &rec); + ok( r == ERROR_SUCCESS, "failed to fetch view: %d\n", r ); + + ok( check_record( rec, 1, "cond2"), "wrong condition\n"); + + MsiCloseHandle( rec ); + r = MsiViewFetch(view, &rec); + ok( r == ERROR_SUCCESS, "failed to fetch view: %d\n", r ); + + ok( check_record( rec, 1, "cond3"), "wrong condition\n"); + + MsiCloseHandle( rec ); + MsiViewClose(view); + MsiCloseHandle(view); + + MsiCloseHandle( hdb ); + DeleteFile(msifile); + +} + + +static void test_where(void) +{ + MSIHANDLE hdb = 0, rec, view; + LPCSTR query; + UINT r; + DWORD size; + CHAR buf[MAX_PATH]; + UINT count; + + hdb = create_db(); + ok( hdb, "failed to create db\n"); + + r = run_query( hdb, 0, + "CREATE TABLE `Media` (" + "`DiskId` SHORT NOT NULL, " + "`LastSequence` LONG, " + "`DiskPrompt` CHAR(64) LOCALIZABLE, " + "`Cabinet` CHAR(255), " + "`VolumeLabel` CHAR(32), " + "`Source` CHAR(72) " + "PRIMARY KEY `DiskId`)" ); + ok( r == S_OK, "cannot create Media table: %d\n", r ); + + r = run_query( hdb, 0, "INSERT INTO `Media` " + "( `DiskId`, `LastSequence`, `DiskPrompt`, `Cabinet`, `VolumeLabel`, `Source` ) " + "VALUES ( 1, 0, '', 'zero.cab', '', '' )" ); + ok( r == S_OK, "cannot add file to the Media table: %d\n", r ); + + r = run_query( hdb, 0, "INSERT INTO `Media` " + "( `DiskId`, `LastSequence`, `DiskPrompt`, `Cabinet`, `VolumeLabel`, `Source` ) " + "VALUES ( 2, 1, '', 'one.cab', '', '' )" ); + ok( r == S_OK, "cannot add file to the Media table: %d\n", r ); + + r = run_query( hdb, 0, "INSERT INTO `Media` " + "( `DiskId`, `LastSequence`, `DiskPrompt`, `Cabinet`, `VolumeLabel`, `Source` ) " + "VALUES ( 3, 2, '', 'two.cab', '', '' )" ); + ok( r == S_OK, "cannot add file to the Media table: %d\n", r ); + + query = "SELECT * FROM `Media`"; + r = do_query(hdb, query, &rec); + ok(r == ERROR_SUCCESS, "MsiViewFetch failed: %d\n", r); + ok( check_record( rec, 4, "zero.cab"), "wrong cabinet\n"); + MsiCloseHandle( rec ); + + query = "SELECT * FROM `Media` WHERE `LastSequence` >= 1"; + r = do_query(hdb, query, &rec); + ok(r == ERROR_SUCCESS, "MsiViewFetch failed: %d\n", r); + ok( check_record( rec, 4, "one.cab"), "wrong cabinet\n"); + + r = MsiRecordGetInteger(rec, 1); + ok( 2 == r, "field wrong\n"); + r = MsiRecordGetInteger(rec, 2); + ok( 1 == r, "field wrong\n"); + MsiCloseHandle( rec ); + + query = "SELECT `DiskId` FROM `Media` WHERE `LastSequence` >= 1 AND DiskId >= 0"; + r = MsiDatabaseOpenView(hdb, query, &view); + ok( r == ERROR_SUCCESS, "failed to open view: %d\n", r ); + + r = MsiViewExecute(view, 0); + ok( r == ERROR_SUCCESS, "failed to execute view: %d\n", r ); + + r = MsiViewFetch(view, &rec); + ok( r == ERROR_SUCCESS, "failed to fetch view: %d\n", r ); + + count = MsiRecordGetFieldCount( rec ); + ok( count == 1, "Expected 1 record fields, got %d\n", count ); + + size = MAX_PATH; + r = MsiRecordGetString( rec, 1, buf, &size ); + ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r ); + ok( !lstrcmp( buf, "2" ), + "For (row %d, column 1) expected '%d', got %s\n", 0, 2, buf ); + MsiCloseHandle( rec ); + + r = MsiViewFetch(view, &rec); + ok( r == ERROR_SUCCESS, "failed to fetch view: %d\n", r ); + + size = MAX_PATH; + r = MsiRecordGetString( rec, 1, buf, &size ); + ok( r == ERROR_SUCCESS, "failed to get record string: %d\n", r ); + ok( !lstrcmp( buf, "3" ), + "For (row %d, column 1) expected '%d', got %s\n", 1, 3, buf ); + MsiCloseHandle( rec ); + + r = MsiViewFetch(view, &rec); + ok( r == ERROR_NO_MORE_ITEMS, "expected no more items: %d\n", r ); + + MsiViewClose(view); + MsiCloseHandle(view); + + MsiCloseHandle( rec ); + + rec = 0; + query = "SELECT * FROM `Media` WHERE `DiskPrompt` IS NULL"; + r = do_query(hdb, query, &rec); + ok( r == ERROR_SUCCESS, "query failed: %d\n", r ); + MsiCloseHandle( rec ); + + rec = 0; + query = "SELECT * FROM `Media` WHERE `DiskPrompt` < 'Cabinet'"; + r = do_query(hdb, query, &rec); + ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %d\n", r ); + MsiCloseHandle( rec ); + + rec = 0; + query = "SELECT * FROM `Media` WHERE `DiskPrompt` > 'Cabinet'"; + r = do_query(hdb, query, &rec); + ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %d\n", r ); + MsiCloseHandle( rec ); + + rec = 0; + query = "SELECT * FROM `Media` WHERE `DiskPrompt` <> 'Cabinet'"; + r = do_query(hdb, query, &rec); + ok( r == ERROR_SUCCESS, "query failed: %d\n", r ); + MsiCloseHandle( rec ); + + rec = 0; + query = "SELECT * FROM `Media` WHERE `DiskPrompt` = 'Cabinet'"; + r = do_query(hdb, query, &rec); + ok( r == ERROR_NO_MORE_ITEMS, "query failed: %d\n", r ); + MsiCloseHandle( rec ); + + rec = MsiCreateRecord(1); + MsiRecordSetString(rec, 1, ""); + + query = "SELECT * FROM `Media` WHERE `DiskPrompt` = ?"; + r = MsiDatabaseOpenView(hdb, query, &view); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + r = MsiViewExecute(view, rec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + MsiCloseHandle(rec); + + r = MsiViewFetch(view, &rec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + MsiCloseHandle(rec); + MsiViewClose(view); + MsiCloseHandle(view); + + MsiCloseHandle( hdb ); + DeleteFile(msifile); +} + +static CHAR CURR_DIR[MAX_PATH]; + +static const CHAR test_data[] = "FirstPrimaryColumn\tSecondPrimaryColumn\tShortInt\tShortIntNullable\tLongInt\tLongIntNullable\tString\tLocalizableString\tLocalizableStringNullable\n" + "s255\ti2\ti2\tI2\ti4\tI4\tS255\tS0\ts0\n" + "TestTable\tFirstPrimaryColumn\n" + "stringage\t5\t2\t\t2147483640\t-2147483640\tanother string\tlocalizable\tduh\n"; + +static const CHAR two_primary[] = "PrimaryOne\tPrimaryTwo\n" + "s255\ts255\n" + "TwoPrimary\tPrimaryOne\tPrimaryTwo\n" + "papaya\tleaf\n" + "papaya\tflower\n"; + +static const CHAR endlines1[] = "A\tB\tC\tD\tE\tF\r\n" + "s72\ts72\ts72\ts72\ts72\ts72\n" + "Table\tA\r\n" + "a\tb\tc\td\te\tf\n" + "g\th\ti\t\rj\tk\tl\r\n"; + +static const CHAR endlines2[] = "A\tB\tC\tD\tE\tF\r" + "s72\ts72\ts72\ts72\ts72\ts72\n" + "Table2\tA\r\n" + "a\tb\tc\td\te\tf\n" + "g\th\ti\tj\tk\tl\r\n"; + +static const CHAR suminfo[] = "PropertyId\tValue\n" + "i2\tl255\n" + "_SummaryInformation\tPropertyId\n" + "1\t1252\n" + "2\tInstaller Database\n" + "3\tInstaller description\n" + "4\tWineHQ\n" + "5\tInstaller\n" + "6\tInstaller comments\n" + "7\tIntel;1033,2057\n" + "9\t{12345678-1234-1234-1234-123456789012}\n" + "12\t2009/04/12 15:46:11\n" + "13\t2009/04/12 15:46:11\n" + "14\t200\n" + "15\t2\n" + "18\tVim\n" + "19\t2\n"; + +static void write_file(const CHAR *filename, const char *data, int data_size) +{ + DWORD size; + + HANDLE hf = CreateFile(filename, GENERIC_WRITE, 0, NULL, + CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + + WriteFile(hf, data, data_size, &size, NULL); + CloseHandle(hf); +} + +static UINT add_table_to_db(MSIHANDLE hdb, LPCSTR table_data) +{ + UINT r; + + write_file("temp_file", table_data, (lstrlen(table_data) - 1) * sizeof(char)); + r = MsiDatabaseImportA(hdb, CURR_DIR, "temp_file"); + DeleteFileA("temp_file"); + + return r; +} + +static void test_suminfo_import(void) +{ + MSIHANDLE hdb, hsi, view = 0; + LPCSTR query; + UINT r, count, size, type; + char str_value[50]; + INT int_value; + FILETIME ft_value; + + GetCurrentDirectoryA(MAX_PATH, CURR_DIR); + + r = MsiOpenDatabaseA(msifile, MSIDBOPEN_CREATE, &hdb); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + + r = add_table_to_db(hdb, suminfo); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + + /* _SummaryInformation is not imported as a regular table... */ + + query = "SELECT * FROM `_SummaryInformation`"; + r = MsiDatabaseOpenViewA(hdb, query, &view); + ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %u\n", r); + MsiCloseHandle(view); + + /* ...its data is added to the special summary information stream */ + + r = MsiGetSummaryInformationA(hdb, NULL, 0, &hsi); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + + r = MsiSummaryInfoGetPropertyCount(hsi, &count); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + ok(count == 14, "Expected 14, got %u\n", count); + + r = MsiSummaryInfoGetPropertyA(hsi, MSI_PID_CODEPAGE, &type, &int_value, NULL, NULL, NULL); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + ok(type == VT_I2, "Expected VT_I2, got %u\n", type); + ok(int_value == 1252, "Expected 1252, got %d\n", int_value); + + size = sizeof(str_value); + r = MsiSummaryInfoGetPropertyA(hsi, MSI_PID_TITLE, &type, NULL, NULL, str_value, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type); + ok(size == 18, "Expected 18, got %u\n", size); + ok(!strcmp(str_value, "Installer Database"), + "Expected \"Installer Database\", got %s\n", str_value); + + size = sizeof(str_value); + r = MsiSummaryInfoGetPropertyA(hsi, MSI_PID_SUBJECT, &type, NULL, NULL, str_value, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type); + ok(!strcmp(str_value, "Installer description"), + "Expected \"Installer description\", got %s\n", str_value); + + size = sizeof(str_value); + r = MsiSummaryInfoGetPropertyA(hsi, MSI_PID_AUTHOR, &type, NULL, NULL, str_value, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type); + ok(!strcmp(str_value, "WineHQ"), + "Expected \"WineHQ\", got %s\n", str_value); + + size = sizeof(str_value); + r = MsiSummaryInfoGetPropertyA(hsi, MSI_PID_KEYWORDS, &type, NULL, NULL, str_value, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type); + ok(!strcmp(str_value, "Installer"), + "Expected \"Installer\", got %s\n", str_value); + + size = sizeof(str_value); + r = MsiSummaryInfoGetPropertyA(hsi, MSI_PID_COMMENTS, &type, NULL, NULL, str_value, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type); + ok(!strcmp(str_value, "Installer comments"), + "Expected \"Installer comments\", got %s\n", str_value); + + size = sizeof(str_value); + r = MsiSummaryInfoGetPropertyA(hsi, MSI_PID_TEMPLATE, &type, NULL, NULL, str_value, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type); + ok(!strcmp(str_value, "Intel;1033,2057"), + "Expected \"Intel;1033,2057\", got %s\n", str_value); + + size = sizeof(str_value); + r = MsiSummaryInfoGetPropertyA(hsi, MSI_PID_REVNUMBER, &type, NULL, NULL, str_value, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type); + ok(!strcmp(str_value, "{12345678-1234-1234-1234-123456789012}"), + "Expected \"{12345678-1234-1234-1234-123456789012}\", got %s\n", str_value); + + r = MsiSummaryInfoGetPropertyA(hsi, MSI_PID_CREATE_DTM, &type, NULL, &ft_value, NULL, NULL); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + ok(type == VT_FILETIME, "Expected VT_FILETIME, got %u\n", type); + + r = MsiSummaryInfoGetPropertyA(hsi, MSI_PID_LASTSAVE_DTM, &type, NULL, &ft_value, NULL, NULL); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + ok(type == VT_FILETIME, "Expected VT_FILETIME, got %u\n", type); + + r = MsiSummaryInfoGetPropertyA(hsi, MSI_PID_PAGECOUNT, &type, &int_value, NULL, NULL, NULL); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + ok(type == VT_I4, "Expected VT_I4, got %u\n", type); + ok(int_value == 200, "Expected 200, got %d\n", int_value); + + r = MsiSummaryInfoGetPropertyA(hsi, MSI_PID_WORDCOUNT, &type, &int_value, NULL, NULL, NULL); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + ok(type == VT_I4, "Expected VT_I4, got %u\n", type); + ok(int_value == 2, "Expected 2, got %d\n", int_value); + + r = MsiSummaryInfoGetPropertyA(hsi, MSI_PID_SECURITY, &type, &int_value, NULL, NULL, NULL); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + ok(type == VT_I4, "Expected VT_I4, got %u\n", type); + ok(int_value == 2, "Expected 2, got %d\n", int_value); + + size = sizeof(str_value); + r = MsiSummaryInfoGetPropertyA(hsi, MSI_PID_APPNAME, &type, NULL, NULL, str_value, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + ok(type == VT_LPSTR, "Expected VT_LPSTR, got %u\n", type); + ok(!strcmp(str_value, "Vim"), "Expected \"Vim\", got %s\n", str_value); + + MsiCloseHandle(hsi); + MsiCloseHandle(hdb); + DeleteFileA(msifile); +} + +static void test_msiimport(void) +{ + MSIHANDLE hdb, view, rec; + LPCSTR query; + UINT r, count; + signed int i; + + GetCurrentDirectoryA(MAX_PATH, CURR_DIR); + + r = MsiOpenDatabaseA(msifile, MSIDBOPEN_CREATE, &hdb); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_table_to_db(hdb, test_data); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_table_to_db(hdb, two_primary); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_table_to_db(hdb, endlines1); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = add_table_to_db(hdb, endlines2); + ok(r == ERROR_FUNCTION_FAILED, "Expected ERROR_FUNCTION_FAILED, got %d\n", r); + + query = "SELECT * FROM `TestTable`"; + r = MsiDatabaseOpenView(hdb, query, &view); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + count = MsiRecordGetFieldCount(rec); + ok(count == 9, "Expected 9, got %d\n", count); + ok(check_record(rec, 1, "FirstPrimaryColumn"), "Expected FirstPrimaryColumn\n"); + ok(check_record(rec, 2, "SecondPrimaryColumn"), "Expected SecondPrimaryColumn\n"); + ok(check_record(rec, 3, "ShortInt"), "Expected ShortInt\n"); + ok(check_record(rec, 4, "ShortIntNullable"), "Expected ShortIntNullalble\n"); + ok(check_record(rec, 5, "LongInt"), "Expected LongInt\n"); + ok(check_record(rec, 6, "LongIntNullable"), "Expected LongIntNullalble\n"); + ok(check_record(rec, 7, "String"), "Expected String\n"); + ok(check_record(rec, 8, "LocalizableString"), "Expected LocalizableString\n"); + ok(check_record(rec, 9, "LocalizableStringNullable"), "Expected LocalizableStringNullable\n"); + MsiCloseHandle(rec); + + r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + count = MsiRecordGetFieldCount(rec); + ok(count == 9, "Expected 9, got %d\n", count); + ok(check_record(rec, 1, "s255"), "Expected s255\n"); + ok(check_record(rec, 2, "i2"), "Expected i2\n"); + ok(check_record(rec, 3, "i2"), "Expected i2\n"); + ok(check_record(rec, 4, "I2"), "Expected I2\n"); + ok(check_record(rec, 5, "i4"), "Expected i4\n"); + ok(check_record(rec, 6, "I4"), "Expected I4\n"); + ok(check_record(rec, 7, "S255"), "Expected S255\n"); + ok(check_record(rec, 8, "S0"), "Expected S0\n"); + ok(check_record(rec, 9, "s0"), "Expected s0\n"); + MsiCloseHandle(rec); + + query = "SELECT * FROM `TestTable`"; + r = do_query(hdb, query, &rec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(check_record(rec, 1, "stringage"), "Expected 'stringage'\n"); + ok(check_record(rec, 7, "another string"), "Expected 'another string'\n"); + ok(check_record(rec, 8, "localizable"), "Expected 'localizable'\n"); + ok(check_record(rec, 9, "duh"), "Expected 'duh'\n"); + + i = MsiRecordGetInteger(rec, 2); + ok(i == 5, "Expected 5, got %d\n", i); + + i = MsiRecordGetInteger(rec, 3); + ok(i == 2, "Expected 2, got %d\n", i); + + i = MsiRecordGetInteger(rec, 4); + ok(i == MSI_NULL_INTEGER, "Expected MSI_NULL_INTEGER, got %d\n", i); + + i = MsiRecordGetInteger(rec, 5); + ok(i == 2147483640, "Expected 2147483640, got %d\n", i); + + i = MsiRecordGetInteger(rec, 6); + ok(i == -2147483640, "Expected -2147483640, got %d\n", i); + + MsiCloseHandle(rec); + MsiViewClose(view); + MsiCloseHandle(view); + + query = "SELECT * FROM `TwoPrimary`"; + r = MsiDatabaseOpenView(hdb, query, &view); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + count = MsiRecordGetFieldCount(rec); + ok(count == 2, "Expected 2, got %d\n", count); + ok(check_record(rec, 1, "PrimaryOne"), "Expected PrimaryOne\n"); + ok(check_record(rec, 2, "PrimaryTwo"), "Expected PrimaryTwo\n"); + + MsiCloseHandle(rec); + + r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + count = MsiRecordGetFieldCount(rec); + ok(count == 2, "Expected 2, got %d\n", count); + ok(check_record(rec, 1, "s255"), "Expected s255\n"); + ok(check_record(rec, 2, "s255"), "Expected s255\n"); + MsiCloseHandle(rec); + + r = MsiViewExecute(view, 0); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = MsiViewFetch(view, &rec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + ok(check_record(rec, 1, "papaya"), "Expected 'papaya'\n"); + ok(check_record(rec, 2, "leaf"), "Expected 'leaf'\n"); + + MsiCloseHandle(rec); + + r = MsiViewFetch(view, &rec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + ok(check_record(rec, 1, "papaya"), "Expected 'papaya'\n"); + ok(check_record(rec, 2, "flower"), "Expected 'flower'\n"); + + MsiCloseHandle(rec); + + r = MsiViewFetch(view, &rec); + ok(r == ERROR_NO_MORE_ITEMS, + "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + + r = MsiViewClose(view); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + MsiCloseHandle(view); + + query = "SELECT * FROM `Table`"; + r = MsiDatabaseOpenView(hdb, query, &view); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + count = MsiRecordGetFieldCount(rec); + ok(count == 6, "Expected 6, got %d\n", count); + ok(check_record(rec, 1, "A"), "Expected A\n"); + ok(check_record(rec, 2, "B"), "Expected B\n"); + ok(check_record(rec, 3, "C"), "Expected C\n"); + ok(check_record(rec, 4, "D"), "Expected D\n"); + ok(check_record(rec, 5, "E"), "Expected E\n"); + ok(check_record(rec, 6, "F"), "Expected F\n"); + MsiCloseHandle(rec); + + r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + count = MsiRecordGetFieldCount(rec); + ok(count == 6, "Expected 6, got %d\n", count); + ok(check_record(rec, 1, "s72"), "Expected s72\n"); + ok(check_record(rec, 2, "s72"), "Expected s72\n"); + ok(check_record(rec, 3, "s72"), "Expected s72\n"); + ok(check_record(rec, 4, "s72"), "Expected s72\n"); + ok(check_record(rec, 5, "s72"), "Expected s72\n"); + ok(check_record(rec, 6, "s72"), "Expected s72\n"); + MsiCloseHandle(rec); + + MsiViewClose(view); + MsiCloseHandle(view); + + query = "SELECT * FROM `Table`"; + r = MsiDatabaseOpenView(hdb, query, &view); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = MsiViewExecute(view, 0); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = MsiViewFetch(view, &rec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(check_record(rec, 1, "a"), "Expected 'a'\n"); + ok(check_record(rec, 2, "b"), "Expected 'b'\n"); + ok(check_record(rec, 3, "c"), "Expected 'c'\n"); + ok(check_record(rec, 4, "d"), "Expected 'd'\n"); + ok(check_record(rec, 5, "e"), "Expected 'e'\n"); + ok(check_record(rec, 6, "f"), "Expected 'f'\n"); + + MsiCloseHandle(rec); + + r = MsiViewFetch(view, &rec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(check_record(rec, 1, "g"), "Expected 'g'\n"); + ok(check_record(rec, 2, "h"), "Expected 'h'\n"); + ok(check_record(rec, 3, "i"), "Expected 'i'\n"); + ok(check_record(rec, 4, "j"), "Expected 'j'\n"); + ok(check_record(rec, 5, "k"), "Expected 'k'\n"); + ok(check_record(rec, 6, "l"), "Expected 'l'\n"); + + MsiCloseHandle(rec); + + r = MsiViewFetch(view, &rec); + ok(r == ERROR_NO_MORE_ITEMS, + "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + + MsiViewClose(view); + MsiCloseHandle(view); + MsiCloseHandle(hdb); + DeleteFileA(msifile); +} + +static const CHAR bin_import_dat[] = "Name\tData\r\n" + "s72\tV0\r\n" + "Binary\tName\r\n" + "filename1\tfilename1.ibd\r\n"; + +static void test_binary_import(void) +{ + MSIHANDLE hdb = 0, rec; + char file[MAX_PATH]; + char buf[MAX_PATH]; + char path[MAX_PATH]; + DWORD size; + LPCSTR query; + UINT r; + + /* create files to import */ + write_file("bin_import.idt", bin_import_dat, + (sizeof(bin_import_dat) - 1) * sizeof(char)); + CreateDirectory("bin_import", NULL); + create_file_data("bin_import/filename1.ibd", "just some words", 15); + + /* import files into database */ + r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb); + ok( r == ERROR_SUCCESS , "Failed to open database\n"); + + GetCurrentDirectory(MAX_PATH, path); + r = MsiDatabaseImport(hdb, path, "bin_import.idt"); + ok(r == ERROR_SUCCESS , "Failed to import Binary table\n"); + + /* read file from the Binary table */ + query = "SELECT * FROM `Binary`"; + r = do_query(hdb, query, &rec); + ok(r == ERROR_SUCCESS, "SELECT query failed: %d\n", r); + + size = MAX_PATH; + r = MsiRecordGetString(rec, 1, file, &size); + ok(r == ERROR_SUCCESS, "Failed to get string: %d\n", r); + ok(!lstrcmp(file, "filename1"), "Expected 'filename1', got %s\n", file); + + size = MAX_PATH; + memset(buf, 0, MAX_PATH); + r = MsiRecordReadStream(rec, 2, buf, &size); + ok(r == ERROR_SUCCESS, "Failed to get stream: %d\n", r); + ok(!lstrcmp(buf, "just some words"), + "Expected 'just some words', got %s\n", buf); + + r = MsiCloseHandle(rec); + ok(r == ERROR_SUCCESS , "Failed to close record handle\n"); + + r = MsiCloseHandle(hdb); + ok(r == ERROR_SUCCESS , "Failed to close database\n"); + + DeleteFile("bin_import/filename1.ibd"); + RemoveDirectory("bin_import"); + DeleteFile("bin_import.idt"); +} + +static void test_markers(void) +{ + MSIHANDLE hdb, rec; + LPCSTR query; + UINT r; + + hdb = create_db(); + ok( hdb, "failed to create db\n"); + + rec = MsiCreateRecord(3); + MsiRecordSetString(rec, 1, "Table"); + MsiRecordSetString(rec, 2, "Apples"); + MsiRecordSetString(rec, 3, "Oranges"); + + /* try a legit create */ + query = "CREATE TABLE `Table` ( `One` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`)"; + r = run_query(hdb, 0, query); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + MsiCloseHandle(rec); + + /* try table name as marker */ + rec = MsiCreateRecord(1); + MsiRecordSetString(rec, 1, "Fable"); + query = "CREATE TABLE `?` ( `One` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`)"; + r = run_query(hdb, rec, query); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* verify that we just created a table called '?', not 'Fable' */ + r = try_query(hdb, "SELECT * from `Fable`"); + ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r); + + r = try_query(hdb, "SELECT * from `?`"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* try table name as marker without backticks */ + MsiRecordSetString(rec, 1, "Mable"); + query = "CREATE TABLE ? ( `One` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`)"; + r = run_query(hdb, rec, query); + ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r); + + /* try one column name as marker */ + MsiRecordSetString(rec, 1, "One"); + query = "CREATE TABLE `Mable` ( `?` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`)"; + r = run_query(hdb, rec, query); + ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r); + MsiCloseHandle(rec); + + /* try column names as markers */ + rec = MsiCreateRecord(2); + MsiRecordSetString(rec, 1, "One"); + MsiRecordSetString(rec, 2, "Two"); + query = "CREATE TABLE `Mable` ( `?` SHORT NOT NULL, `?` CHAR(255) PRIMARY KEY `One`)"; + r = run_query(hdb, rec, query); + ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r); + MsiCloseHandle(rec); + + /* try names with backticks */ + rec = MsiCreateRecord(3); + MsiRecordSetString(rec, 1, "One"); + MsiRecordSetString(rec, 2, "Two"); + MsiRecordSetString(rec, 3, "One"); + query = "CREATE TABLE `Mable` ( `?` SHORT NOT NULL, `?` CHAR(255) PRIMARY KEY `?`)"; + r = run_query(hdb, rec, query); + ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r); + + /* try names with backticks, minus definitions */ + query = "CREATE TABLE `Mable` ( `?`, `?` PRIMARY KEY `?`)"; + r = run_query(hdb, rec, query); + ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r); + + /* try names without backticks */ + query = "CREATE TABLE `Mable` ( ? SHORT NOT NULL, ? CHAR(255) PRIMARY KEY ?)"; + r = run_query(hdb, rec, query); + ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r); + MsiCloseHandle(rec); + + /* try one long marker */ + rec = MsiCreateRecord(1); + MsiRecordSetString(rec, 1, "`One` SHORT NOT NULL, `Two` CHAR(255) PRIMARY KEY `One`"); + query = "CREATE TABLE `Mable` ( ? )"; + r = run_query(hdb, rec, query); + ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r); + MsiCloseHandle(rec); + + /* try all names as markers */ + rec = MsiCreateRecord(4); + MsiRecordSetString(rec, 1, "Mable"); + MsiRecordSetString(rec, 2, "One"); + MsiRecordSetString(rec, 3, "Two"); + MsiRecordSetString(rec, 4, "One"); + query = "CREATE TABLE `?` ( `?` SHORT NOT NULL, `?` CHAR(255) PRIMARY KEY `?`)"; + r = run_query(hdb, rec, query); + ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r); + MsiCloseHandle(rec); + + /* try a legit insert */ + query = "INSERT INTO `Table` ( `One`, `Two` ) VALUES ( 5, 'hello' )"; + r = run_query(hdb, 0, query); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = try_query(hdb, "SELECT * from `Table`"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* try values as markers */ + rec = MsiCreateRecord(2); + MsiRecordSetInteger(rec, 1, 4); + MsiRecordSetString(rec, 2, "hi"); + query = "INSERT INTO `Table` ( `One`, `Two` ) VALUES ( ?, '?' )"; + r = run_query(hdb, rec, query); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + MsiCloseHandle(rec); + + /* try column names and values as markers */ + rec = MsiCreateRecord(4); + MsiRecordSetString(rec, 1, "One"); + MsiRecordSetString(rec, 2, "Two"); + MsiRecordSetInteger(rec, 3, 5); + MsiRecordSetString(rec, 4, "hi"); + query = "INSERT INTO `Table` ( `?`, `?` ) VALUES ( ?, '?' )"; + r = run_query(hdb, rec, query); + ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r); + MsiCloseHandle(rec); + + /* try column names as markers */ + rec = MsiCreateRecord(2); + MsiRecordSetString(rec, 1, "One"); + MsiRecordSetString(rec, 2, "Two"); + query = "INSERT INTO `Table` ( `?`, `?` ) VALUES ( 3, 'yellow' )"; + r = run_query(hdb, rec, query); + ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r); + MsiCloseHandle(rec); + + /* try table name as a marker */ + rec = MsiCreateRecord(1); + MsiRecordSetString(rec, 1, "Table"); + query = "INSERT INTO `?` ( `One`, `Two` ) VALUES ( 2, 'green' )"; + r = run_query(hdb, rec, query); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + MsiCloseHandle(rec); + + /* try table name and values as markers */ + rec = MsiCreateRecord(3); + MsiRecordSetString(rec, 1, "Table"); + MsiRecordSetInteger(rec, 2, 10); + MsiRecordSetString(rec, 3, "haha"); + query = "INSERT INTO `?` ( `One`, `Two` ) VALUES ( ?, '?' )"; + r = run_query(hdb, rec, query); + ok(r == ERROR_FUNCTION_FAILED, "Expected ERROR_FUNCTION_FAILED, got %d\n", r); + MsiCloseHandle(rec); + + /* try all markers */ + rec = MsiCreateRecord(5); + MsiRecordSetString(rec, 1, "Table"); + MsiRecordSetString(rec, 1, "One"); + MsiRecordSetString(rec, 1, "Two"); + MsiRecordSetInteger(rec, 2, 10); + MsiRecordSetString(rec, 3, "haha"); + query = "INSERT INTO `?` ( `?`, `?` ) VALUES ( ?, '?' )"; + r = run_query(hdb, rec, query); + ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r); + MsiCloseHandle(rec); + + /* insert an integer as a string */ + rec = MsiCreateRecord(2); + MsiRecordSetString(rec, 1, "11"); + MsiRecordSetString(rec, 2, "hi"); + query = "INSERT INTO `Table` ( `One`, `Two` ) VALUES ( ?, '?' )"; + r = run_query(hdb, rec, query); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + MsiCloseHandle(rec); + + /* leave off the '' for the string */ + rec = MsiCreateRecord(2); + MsiRecordSetInteger(rec, 1, 12); + MsiRecordSetString(rec, 2, "hi"); + query = "INSERT INTO `Table` ( `One`, `Two` ) VALUES ( ?, ? )"; + r = run_query(hdb, rec, query); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + MsiCloseHandle(rec); + + MsiCloseHandle(hdb); + DeleteFileA(msifile); +} + +#define MY_NVIEWS 4000 /* Largest installer I've seen uses < 2k */ +static void test_handle_limit(void) +{ + int i; + MSIHANDLE hdb; + MSIHANDLE hviews[MY_NVIEWS]; + UINT r; + + /* create an empty db */ + hdb = create_db(); + ok( hdb, "failed to create db\n"); + + memset(hviews, 0, sizeof(hviews)); + + for (i=0; i | D | C | A | E | B | + * --------------------- --------------------- + * + * set primary key `E` + * --------------------- --------------------- + * | D | C | A | E | B | -> | D | E | A | C | B | + * --------------------- --------------------- + */ + + query = "CREATE TABLE `T` ( `B` SHORT NOT NULL, `C` SHORT NOT NULL, " + "`A` CHAR(255), `E` INT, `D` CHAR(255) NOT NULL " + "PRIMARY KEY `D`, `E`)"; + r = run_query(hdb, 0, query); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + query = "SELECT * FROM `T`"; + r = MsiDatabaseOpenView(hdb, query, &view); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 1, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("s255", buf), "Expected \"s255\", got \"%s\"\n", buf); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 2, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("I2", buf), "Expected \"I2\", got \"%s\"\n", buf); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 3, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("S255", buf), "Expected \"S255\", got \"%s\"\n", buf); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 4, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("i2", buf), "Expected \"i2\", got \"%s\"\n", buf); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 5, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("i2", buf), "Expected \"i2\", got \"%s\"\n", buf); + + MsiCloseHandle(rec); + + r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 1, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("D", buf), "Expected \"D\", got \"%s\"\n", buf); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 2, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("E", buf), "Expected \"E\", got \"%s\"\n", buf); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 3, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("A", buf), "Expected \"A\", got \"%s\"\n", buf); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 4, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("C", buf), "Expected \"C\", got \"%s\"\n", buf); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 5, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("B", buf), "Expected \"B\", got \"%s\"\n", buf); + + MsiCloseHandle(rec); + MsiViewClose(view); + MsiCloseHandle(view); + + query = "INSERT INTO `T` ( `B`, `C`, `A`, `E`, `D` ) " + "VALUES ( 1, 2, 'a', 3, 'bc' )"; + r = run_query(hdb, 0, query); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + query = "SELECT * FROM `T`"; + r = do_query(hdb, query, &rec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 1, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("bc", buf), "Expected \"bc\", got \"%s\"\n", buf); + + r = MsiRecordGetInteger(rec, 2); + ok(r == 3, "Expected 3, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 3, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("a", buf), "Expected \"a\", got \"%s\"\n", buf); + + r = MsiRecordGetInteger(rec, 4); + ok(r == 2, "Expected 2, got %d\n", r); + + r = MsiRecordGetInteger(rec, 5); + ok(r == 1, "Expected 1, got %d\n", r); + + MsiCloseHandle(rec); + + query = "SELECT * FROM `_Columns` WHERE `Table` = 'T'"; + r = MsiDatabaseOpenView(hdb, query, &view); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + r = MsiViewExecute(view, 0); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = MsiViewFetch(view, &rec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 1, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf); + + r = MsiRecordGetInteger(rec, 2); + ok(r == 1, "Expected 1, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 3, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("D", buf), "Expected \"D\", got \"%s\"\n", buf); + + MsiCloseHandle(rec); + + r = MsiViewFetch(view, &rec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 1, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf); + + r = MsiRecordGetInteger(rec, 2); + ok(r == 2, "Expected 2, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 3, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("E", buf), "Expected \"E\", got \"%s\"\n", buf); + + MsiCloseHandle(rec); + + r = MsiViewFetch(view, &rec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 1, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf); + + r = MsiRecordGetInteger(rec, 2); + ok(r == 3, "Expected 3, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 3, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("A", buf), "Expected \"A\", got \"%s\"\n", buf); + + MsiCloseHandle(rec); + + r = MsiViewFetch(view, &rec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 1, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf); + + r = MsiRecordGetInteger(rec, 2); + ok(r == 4, "Expected 4, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 3, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("C", buf), "Expected \"C\", got \"%s\"\n", buf); + + MsiCloseHandle(rec); + + r = MsiViewFetch(view, &rec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 1, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf); + + r = MsiRecordGetInteger(rec, 2); + ok(r == 5, "Expected 5, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 3, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("B", buf), "Expected \"B\", got \"%s\"\n", buf); + + MsiCloseHandle(rec); + + r = MsiViewFetch(view, &rec); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + + MsiViewClose(view); + MsiCloseHandle(view); + + query = "CREATE TABLE `Z` ( `B` SHORT NOT NULL, `C` SHORT NOT NULL, " + "`A` CHAR(255), `E` INT, `D` CHAR(255) NOT NULL " + "PRIMARY KEY `C`, `A`, `D`)"; + r = run_query(hdb, 0, query); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + query = "SELECT * FROM `Z`"; + r = MsiDatabaseOpenView(hdb, query, &view); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 1, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("i2", buf), "Expected \"i2\", got \"%s\"\n", buf); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 2, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("S255", buf), "Expected \"S255\", got \"%s\"\n", buf); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 3, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("s255", buf), "Expected \"s255\", got \"%s\"\n", buf); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 4, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("I2", buf), "Expected \"I2\", got \"%s\"\n", buf); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 5, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("i2", buf), "Expected \"i2\", got \"%s\"\n", buf); + + MsiCloseHandle(rec); + + r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 1, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("C", buf), "Expected \"C\", got \"%s\"\n", buf); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 2, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("A", buf), "Expected \"A\", got \"%s\"\n", buf); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 3, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("D", buf), "Expected \"D\", got \"%s\"\n", buf); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 4, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("E", buf), "Expected \"E\", got \"%s\"\n", buf); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 5, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("B", buf), "Expected \"B\", got \"%s\"\n", buf); + + MsiCloseHandle(rec); + MsiViewClose(view); + MsiCloseHandle(view); + + query = "INSERT INTO `Z` ( `B`, `C`, `A`, `E`, `D` ) " + "VALUES ( 1, 2, 'a', 3, 'bc' )"; + r = run_query(hdb, 0, query); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + query = "SELECT * FROM `Z`"; + r = do_query(hdb, query, &rec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = MsiRecordGetInteger(rec, 1); + ok(r == 2, "Expected 2, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 2, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("a", buf), "Expected \"a\", got \"%s\"\n", buf); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 3, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("bc", buf), "Expected \"bc\", got \"%s\"\n", buf); + + r = MsiRecordGetInteger(rec, 4); + ok(r == 3, "Expected 3, got %d\n", r); + + r = MsiRecordGetInteger(rec, 5); + ok(r == 1, "Expected 1, got %d\n", r); + + MsiCloseHandle(rec); + + query = "SELECT * FROM `_Columns` WHERE `Table` = 'T'"; + r = MsiDatabaseOpenView(hdb, query, &view); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + r = MsiViewExecute(view, 0); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = MsiViewFetch(view, &rec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 1, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf); + + r = MsiRecordGetInteger(rec, 2); + ok(r == 1, "Expected 1, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 3, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("D", buf), "Expected \"D\", got \"%s\"\n", buf); + + MsiCloseHandle(rec); + + r = MsiViewFetch(view, &rec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 1, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf); + + r = MsiRecordGetInteger(rec, 2); + ok(r == 2, "Expected 2, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 3, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("E", buf), "Expected \"E\", got \"%s\"\n", buf); + + MsiCloseHandle(rec); + + r = MsiViewFetch(view, &rec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 1, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf); + + r = MsiRecordGetInteger(rec, 2); + ok(r == 3, "Expected 3, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 3, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("A", buf), "Expected \"A\", got \"%s\"\n", buf); + + MsiCloseHandle(rec); + + r = MsiViewFetch(view, &rec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 1, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf); + + r = MsiRecordGetInteger(rec, 2); + ok(r == 4, "Expected 4, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 3, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("C", buf), "Expected \"C\", got \"%s\"\n", buf); + + MsiCloseHandle(rec); + + r = MsiViewFetch(view, &rec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 1, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("T", buf), "Expected \"T\", got \"%s\"\n", buf); + + r = MsiRecordGetInteger(rec, 2); + ok(r == 5, "Expected 5, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "kiwi"); + r = MsiRecordGetString(rec, 3, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA("B", buf), "Expected \"B\", got \"%s\"\n", buf); + + MsiCloseHandle(rec); + + r = MsiViewFetch(view, &rec); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + + MsiViewClose(view); + MsiCloseHandle(view); + + MsiCloseHandle(hdb); + DeleteFileA(msifile); +} + +static void test_createtable(void) +{ + MSIHANDLE hdb, htab = 0, hrec = 0; + LPCSTR query; + UINT res; + DWORD size; + char buffer[0x20]; + + hdb = create_db(); + ok(hdb, "failed to create db\n"); + + query = "CREATE TABLE `blah` (`foo` CHAR(72) NOT NULL PRIMARY KEY `foo`)"; + res = MsiDatabaseOpenView( hdb, query, &htab ); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + if(res == ERROR_SUCCESS ) + { + res = MsiViewExecute( htab, hrec ); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + res = MsiViewGetColumnInfo( htab, MSICOLINFO_NAMES, &hrec ); + todo_wine ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + size = sizeof(buffer); + res = MsiRecordGetString(hrec, 1, buffer, &size ); + todo_wine ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + MsiCloseHandle( hrec ); + + res = MsiViewClose( htab ); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + res = MsiCloseHandle( htab ); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + } + + query = "CREATE TABLE `a` (`b` INT PRIMARY KEY `b`)"; + res = MsiDatabaseOpenView( hdb, query, &htab ); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + if(res == ERROR_SUCCESS ) + { + res = MsiViewExecute( htab, 0 ); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + res = MsiViewClose( htab ); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + res = MsiCloseHandle( htab ); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + query = "SELECT * FROM `a`"; + res = MsiDatabaseOpenView( hdb, query, &htab ); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + res = MsiViewGetColumnInfo( htab, MSICOLINFO_NAMES, &hrec ); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + buffer[0] = 0; + size = sizeof(buffer); + res = MsiRecordGetString(hrec, 1, buffer, &size ); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + ok(!strcmp(buffer,"b"), "b != %s\n", buffer); + MsiCloseHandle( hrec ); + + res = MsiViewClose( htab ); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + res = MsiCloseHandle( htab ); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + res = MsiDatabaseCommit(hdb); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + res = MsiCloseHandle(hdb); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + res = MsiOpenDatabase(msifile, MSIDBOPEN_TRANSACT, &hdb ); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + query = "SELECT * FROM `a`"; + res = MsiDatabaseOpenView( hdb, query, &htab ); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + res = MsiViewGetColumnInfo( htab, MSICOLINFO_NAMES, &hrec ); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + buffer[0] = 0; + size = sizeof(buffer); + res = MsiRecordGetString(hrec, 1, buffer, &size ); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + ok(!strcmp(buffer,"b"), "b != %s\n", buffer); + + res = MsiCloseHandle( hrec ); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + res = MsiViewClose( htab ); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + res = MsiCloseHandle( htab ); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + } + + res = MsiDatabaseCommit(hdb); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + res = MsiCloseHandle(hdb); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + DeleteFileA(msifile); +} + +static void test_embedded_nulls(void) +{ + static const char control_table[] = + "Dialog\tText\n" + "s72\tL0\n" + "Control\tDialog\n" + "LicenseAgreementDlg\ttext\x11\x19text\0text"; + UINT r, sz; + MSIHANDLE hdb, hrec; + char buffer[32]; + + r = MsiOpenDatabaseA( msifile, MSIDBOPEN_CREATE, &hdb ); + ok( r == ERROR_SUCCESS, "failed to open database %u\n", r ); + + GetCurrentDirectoryA( MAX_PATH, CURR_DIR ); + write_file( "temp_file", control_table, sizeof(control_table) ); + r = MsiDatabaseImportA( hdb, CURR_DIR, "temp_file" ); + ok( r == ERROR_SUCCESS, "failed to import table %u\n", r ); + DeleteFileA( "temp_file" ); + + r = do_query( hdb, "SELECT `Text` FROM `Control` WHERE `Dialog` = 'LicenseAgreementDlg'", &hrec ); + ok( r == ERROR_SUCCESS, "query failed %u\n", r ); + + buffer[0] = 0; + sz = sizeof(buffer); + r = MsiRecordGetStringA( hrec, 1, buffer, &sz ); + ok( r == ERROR_SUCCESS, "failed to get string %u\n", r ); + ok( !memcmp( "text\r\ntext\ntext", buffer, sizeof("text\r\ntext\ntext") - 1 ), "wrong buffer contents \"%s\"\n", buffer ); + + MsiCloseHandle( hrec ); + MsiCloseHandle( hdb ); + DeleteFileA( msifile ); +} + +static void test_select_column_names(void) +{ + MSIHANDLE hdb = 0, rec, rec2, view; + char buffer[32]; + UINT r, size; + + DeleteFile(msifile); + + r = MsiOpenDatabase( msifile, MSIDBOPEN_CREATE, &hdb ); + ok( r == ERROR_SUCCESS , "failed to open database: %u\n", r ); + + r = try_query( hdb, "CREATE TABLE `t` (`a` CHAR NOT NULL, `b` CHAR PRIMARY KEY `a`)"); + ok( r == ERROR_SUCCESS , "query failed: %u\n", r ); + + r = try_query( hdb, "SELECT `t`.`b` FROM `t` WHERE `t`.`b` = `x`" ); + ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %u\n", r ); + + r = try_query( hdb, "SELECT '', `t`.`b` FROM `t` WHERE `t`.`b` = 'x'" ); + ok( r == ERROR_SUCCESS , "query failed: %u\n", r ); + + r = try_query( hdb, "SELECT *, `t`.`b` FROM `t` WHERE `t`.`b` = 'x'" ); + todo_wine ok( r == ERROR_SUCCESS, "query failed: %u\n", r ); + + r = try_query( hdb, "SELECT 'b', `t`.`b` FROM `t` WHERE `t`.`b` = 'x'" ); + ok( r == ERROR_SUCCESS , "query failed: %u\n", r ); + + r = try_query( hdb, "SELECT `t`.`b`, '' FROM `t` WHERE `t`.`b` = 'x'" ); + ok( r == ERROR_SUCCESS , "query failed: %u\n", r ); + + r = try_query( hdb, "SELECT `t`.`b`, '' FROM `t` WHERE `t`.`b` = 'x' ORDER BY `b`" ); + ok( r == ERROR_SUCCESS , "query failed: %u\n", r ); + + r = try_query( hdb, "SELECT `t`.`b`, '' FROM `t` WHERE `t`.`b` = 'x' ORDER BY 'b'" ); + ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %u\n", r ); + + r = try_query( hdb, "SELECT 't'.'b' FROM `t` WHERE `t`.`b` = 'x'" ); + ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %u\n", r ); + + r = try_query( hdb, "SELECT 'b' FROM `t` WHERE `t`.`b` = 'x'" ); + ok( r == ERROR_SUCCESS , "query failed: %u\n", r ); + + r = try_query( hdb, "INSERT INTO `t` ( `a`, `b` ) VALUES( '1', '2' )" ); + ok( r == ERROR_SUCCESS , "query failed: %u\n", r ); + + r = try_query( hdb, "INSERT INTO `t` ( `a`, `b` ) VALUES( '3', '4' )" ); + ok( r == ERROR_SUCCESS , "query failed: %u\n", r ); + + r = MsiDatabaseOpenView( hdb, "SELECT '' FROM `t`", &view ); + ok( r == ERROR_SUCCESS, "failed to open database view: %u\n", r ); + + r = MsiViewExecute( view, 0 ); + ok( r == ERROR_SUCCESS, "failed to execute view: %u\n", r ); + + r = MsiViewFetch( view, &rec ); + ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r ); + r = MsiRecordGetFieldCount( rec ); + ok( r == 1, "got %u\n", r ); + r = MsiViewGetColumnInfo( view, MSICOLINFO_NAMES, &rec2 ); + ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r ); + r = MsiRecordGetFieldCount( rec2 ); + ok( r == 1, "got %u\n", r ); + size = sizeof(buffer); + memset( buffer, 0x55, sizeof(buffer) ); + r = MsiRecordGetStringA( rec2, 1, buffer, &size ); + ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r ); + ok( !buffer[0], "got \"%s\"\n", buffer ); + MsiCloseHandle( rec2 ); + r = MsiViewGetColumnInfo( view, MSICOLINFO_TYPES, &rec2 ); + ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r ); + r = MsiRecordGetFieldCount( rec2 ); + ok( r == 1, "got %u\n", r ); + size = sizeof(buffer); + memset( buffer, 0x55, sizeof(buffer) ); + r = MsiRecordGetStringA( rec2, 1, buffer, &size ); + ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r ); + ok( !lstrcmpA( buffer, "f0" ), "got \"%s\"\n", buffer ); + MsiCloseHandle( rec2 ); + + size = sizeof(buffer); + memset( buffer, 0x55, sizeof(buffer) ); + r = MsiRecordGetStringA( rec, 1, buffer, &size ); + ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r ); + ok( !buffer[0], "got \"%s\"\n", buffer ); + MsiCloseHandle( rec ); + + r = MsiViewFetch( view, &rec ); + ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r ); + size = sizeof(buffer); + memset( buffer, 0x55, sizeof(buffer) ); + r = MsiRecordGetStringA( rec, 1, buffer, &size ); + ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r ); + ok( !buffer[0], "got \"%s\"\n", buffer ); + MsiCloseHandle( rec ); + + r = MsiViewFetch( view, &rec ); + ok( r == ERROR_NO_MORE_ITEMS, "unexpected result: %u\n", r ); + MsiCloseHandle( rec ); + + MsiViewClose( view ); + MsiCloseHandle( view ); + + r = MsiDatabaseOpenView( hdb, "SELECT `a`, '' FROM `t`", &view ); + ok( r == ERROR_SUCCESS, "failed to open database view: %u\n", r ); + + r = MsiViewExecute( view, 0 ); + ok( r == ERROR_SUCCESS, "failed to execute view: %u\n", r ); + + r = MsiViewFetch( view, &rec ); + ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r ); + r = MsiRecordGetFieldCount( rec ); + ok( r == 2, "got %u\n", r ); + size = sizeof(buffer); + memset( buffer, 0x55, sizeof(buffer) ); + r = MsiRecordGetStringA( rec, 1, buffer, &size ); + ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r ); + ok( !lstrcmpA( buffer, "1" ), "got \"%s\"\n", buffer ); + MsiCloseHandle( rec ); + + r = MsiViewFetch( view, &rec ); + ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r ); + size = sizeof(buffer); + memset( buffer, 0x55, sizeof(buffer) ); + r = MsiRecordGetStringA( rec, 2, buffer, &size ); + ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r ); + ok( !buffer[0], "got \"%s\"\n", buffer ); + MsiCloseHandle( rec ); + + r = MsiViewFetch( view, &rec ); + ok( r == ERROR_NO_MORE_ITEMS, "unexpected result: %u\n", r ); + MsiCloseHandle( rec ); + + MsiViewClose( view ); + MsiCloseHandle( view ); + + r = MsiDatabaseOpenView( hdb, "SELECT '', `a` FROM `t`", &view ); + ok( r == ERROR_SUCCESS, "failed to open database view: %u\n", r ); + + r = MsiViewExecute( view, 0 ); + ok( r == ERROR_SUCCESS, "failed to execute view: %u\n", r ); + + r = MsiViewFetch( view, &rec ); + ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r ); + r = MsiRecordGetFieldCount( rec ); + ok( r == 2, "got %u\n", r ); + size = sizeof(buffer); + memset( buffer, 0x55, sizeof(buffer) ); + r = MsiRecordGetStringA( rec, 1, buffer, &size ); + ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r ); + ok( !buffer[0], "got \"%s\"\n", buffer ); + size = sizeof(buffer); + memset( buffer, 0x55, sizeof(buffer) ); + r = MsiRecordGetStringA( rec, 2, buffer, &size ); + ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r ); + ok( !lstrcmpA( buffer, "1" ), "got \"%s\"\n", buffer ); + MsiCloseHandle( rec ); + + r = MsiViewFetch( view, &rec ); + ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r ); + size = sizeof(buffer); + memset( buffer, 0x55, sizeof(buffer) ); + r = MsiRecordGetStringA( rec, 1, buffer, &size ); + ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r ); + ok( !buffer[0], "got \"%s\"\n", buffer ); + size = sizeof(buffer); + memset( buffer, 0x55, sizeof(buffer) ); + r = MsiRecordGetStringA( rec, 2, buffer, &size ); + ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r ); + ok( !lstrcmpA( buffer, "3" ), "got \"%s\"\n", buffer ); + MsiCloseHandle( rec ); + + r = MsiViewFetch( view, &rec ); + ok( r == ERROR_NO_MORE_ITEMS, "unexpected result: %u\n", r ); + MsiCloseHandle( rec ); + + MsiViewClose( view ); + MsiCloseHandle( view ); + + r = MsiDatabaseOpenView( hdb, "SELECT `a`, '', `b` FROM `t`", &view ); + ok( r == ERROR_SUCCESS, "failed to open database view: %u\n", r ); + + r = MsiViewExecute( view, 0 ); + ok( r == ERROR_SUCCESS, "failed to execute view: %u\n", r ); + + r = MsiViewFetch( view, &rec ); + ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r ); + r = MsiRecordGetFieldCount( rec ); + ok( r == 3, "got %u\n", r ); + size = sizeof(buffer); + memset( buffer, 0x55, sizeof(buffer) ); + r = MsiRecordGetStringA( rec, 1, buffer, &size ); + ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r ); + ok( !lstrcmpA( buffer, "1" ), "got \"%s\"\n", buffer ); + size = sizeof(buffer); + memset( buffer, 0x55, sizeof(buffer) ); + r = MsiRecordGetStringA( rec, 2, buffer, &size ); + ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r ); + ok( !buffer[0], "got \"%s\"\n", buffer ); + size = sizeof(buffer); + memset( buffer, 0x55, sizeof(buffer) ); + r = MsiRecordGetStringA( rec, 3, buffer, &size ); + ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r ); + ok( !lstrcmpA( buffer, "2" ), "got \"%s\"\n", buffer ); + MsiCloseHandle( rec ); + + r = MsiViewFetch( view, &rec ); + ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r ); + size = sizeof(buffer); + memset( buffer, 0x55, sizeof(buffer) ); + r = MsiRecordGetStringA( rec, 1, buffer, &size ); + ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r ); + ok( !lstrcmpA( buffer, "3" ), "got \"%s\"\n", buffer ); + size = sizeof(buffer); + memset( buffer, 0x55, sizeof(buffer) ); + r = MsiRecordGetStringA( rec, 2, buffer, &size ); + ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r ); + ok( !buffer[0], "got \"%s\"\n", buffer ); + size = sizeof(buffer); + memset( buffer, 0x55, sizeof(buffer) ); + r = MsiRecordGetStringA( rec, 3, buffer, &size ); + ok( r == ERROR_SUCCESS, "unexpected result: %u\n", r ); + ok( !lstrcmpA( buffer, "4" ), "got \"%s\"\n", buffer ); + MsiCloseHandle( rec ); + + r = MsiViewFetch( view, &rec ); + ok( r == ERROR_NO_MORE_ITEMS, "unexpected result: %u\n", r ); + MsiCloseHandle( rec ); + + MsiViewClose( view ); + MsiCloseHandle( view ); + + r = try_query( hdb, "SELECT '' FROM `t` WHERE `t`.`b` = 'x'" ); + ok( r == ERROR_SUCCESS , "query failed: %u\n", r ); + + r = try_query( hdb, "SELECT `` FROM `t` WHERE `t`.`b` = 'x'" ); + todo_wine ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %u\n", r ); + + r = try_query( hdb, "SELECT `b` FROM 't' WHERE `t`.`b` = 'x'" ); + ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %u\n", r ); + + r = try_query( hdb, "SELECT `b` FROM `t` WHERE 'b' = 'x'" ); + ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %u\n", r ); + + r = try_query( hdb, "SELECT `t`.`b`, `` FROM `t` WHERE `t`.`b` = 'x'" ); + todo_wine ok( r == ERROR_BAD_QUERY_SYNTAX, "query failed: %u\n", r ); + + r = MsiCloseHandle( hdb ); + ok(r == ERROR_SUCCESS , "failed to close database: %u\n", r); +} + +void main() +{ + test_msidatabase(); + test_msiinsert(); + test_msibadqueries(); + test_viewmodify(); + test_viewgetcolumninfo(); + test_getcolinfo(); + test_msiexport(); + test_longstrings(); + test_streamtable(); + test_binary(); + test_where_not_in_selected(); + test_where(); + test_msiimport(); + test_binary_import(); + test_markers(); + test_handle_limit(); + test_try_transform(); + test_join(); + test_temporary_table(); + test_alter(); + test_integers(); + test_update(); + test_special_tables(); + test_tables_order(); + test_rows_order(); + test_select_markers(); + test_viewmodify_update(); + test_viewmodify_assign(); + test_stringtable(); + test_viewmodify_delete(); + test_defaultdatabase(); + test_order(); + test_viewmodify_delete_temporary(); + test_deleterow(); + test_quotes(); + test_carriagereturn(); + test_noquotes(); + test_forcecodepage(); + test_viewmodify_refresh(); + test_where_viewmodify(); + test_storages_table(); + test_droptable(); +#if 0 + test_dbmerge(); +#endif + test_select_with_tablenames(); + test_insertorder(); + test_columnorder(); + test_suminfo_import(); + test_createtable(); + test_collation(); + test_embedded_nulls(); + test_select_column_names(); +} diff --git a/tests/testdatabase.ok b/tests/testdatabase.ok new file mode 100644 index 0000000..819f76d --- /dev/null +++ b/tests/testdatabase.ok @@ -0,0 +1,2955 @@ +ok: res == ERROR_OPEN_FAILED +ok: res == ERROR_INVALID_PARAMETER +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: INVALID_FILE_ATTRIBUTES != GetFileAttributes( msifile ) +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: INVALID_FILE_ATTRIBUTES != GetFileAttributes( msifile2 ) +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: INVALID_FILE_ATTRIBUTES == GetFileAttributes( msifile2 ) +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: INVALID_FILE_ATTRIBUTES != GetFileAttributes( msifile2 ) +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: INVALID_FILE_ATTRIBUTES != GetFileAttributes( msifile ) +ok: res == ERROR_SUCCESS +ok: INVALID_FILE_ATTRIBUTES != GetFileAttributes( msifile ) +ok: res == ERROR_SUCCESS +ok: INVALID_FILE_ATTRIBUTES == GetFileAttributes( msifile ) +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: INVALID_FILE_ATTRIBUTES != GetFileAttributes( msifile ) +ok: res == ERROR_SUCCESS +ok: res == TRUE +ok: res == TRUE +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == 3 +ok: r == FALSE +ok: r == 1 +ok: r == ERROR_SUCCESS +ok: !strcmp(buf,"Abe") +ok: r == ERROR_SUCCESS +ok: !strcmp(buf,"8675309") +ok: r == ERROR_SUCCESS +ok: r == ERROR_NO_MORE_ITEMS +ok: hrec == 0 +ok: r == ERROR_SUCCESS +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_INVALID_PARAMETER +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == TRUE +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_SUCCESS +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r != ERROR_SUCCESS +ok: r != ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_SUCCESS +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_SUCCESS +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_SUCCESS +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == TRUE +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: err == MSIDBERROR_INVALIDARG +ok: r == ERROR_SUCCESS +ok: err == MSIDBERROR_INVALIDARG || err == MSIDBERROR_NOERROR +ok: err == MSIDBERROR_INVALIDARG +ok: err == MSIDBERROR_MOREDATA +ok: buffer[0] == 'x' +ok: sz == 0 +ok: err == MSIDBERROR_NOERROR +ok: sz == 0 +ok: err == MSIDBERROR_NOERROR +ok: buffer[0] == 0 +ok: sz == 0 +ok: r == ERROR_SUCCESS +ok: r == ERROR_INVALID_HANDLE +ok: r == ERROR_INVALID_HANDLE +ok: r == ERROR_INVALID_DATA +ok: err == MSIDBERROR_NOERROR +ok: buffer[0] == 0 +ok: sz == 0 +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_INVALID_DATA +ok: err == MSIDBERROR_DUPLICATEKEY +ok: !strcmp(buffer, "id") +ok: sz == 2 +ok: r == ERROR_SUCCESS +ok: r == ERROR_FUNCTION_FAILED +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == 1 +ok: r == ERROR_SUCCESS +ok: !lstrcmp(buffer, "bob") +ok: r == ERROR_SUCCESS +ok: !lstrcmp(buffer, "7654321") +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_FUNCTION_FAILED +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == 1 +ok: r == ERROR_SUCCESS +ok: !lstrcmp(buffer, "bob") +ok: r == ERROR_SUCCESS +ok: !lstrcmp(buffer, "3141592") +ok: r == ERROR_SUCCESS +ok: hrec != 0 +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_FUNCTION_FAILED +ok: r == ERROR_SUCCESS +ok: hrec != 0 +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_FUNCTION_FAILED +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_FUNCTION_FAILED +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_FUNCTION_FAILED +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: hdb +ok: r == ERROR_SUCCESS +ok: rec +ok: check_record( rec, 1, "S255") +ok: check_record( rec, 2, "S1") +ok: check_record( rec, 3, "I2") +ok: check_record( rec, 4, "I2") +ok: check_record( rec, 5, "I2") +ok: check_record( rec, 6, "I4") +ok: check_record( rec, 7, "S0") +ok: 0x3dff == get_columns_table_type(hdb, "Properties", 1 ) +ok: 0x1d01 == get_columns_table_type(hdb, "Properties", 2 ) +ok: 0x1502 == get_columns_table_type(hdb, "Properties", 3 ) +ok: 0x1502 == get_columns_table_type(hdb, "Properties", 4 ) +ok: 0x1502 == get_columns_table_type(hdb, "Properties", 5 ) +ok: 0x1104 == get_columns_table_type(hdb, "Properties", 6 ) +ok: 0x1d00 == get_columns_table_type(hdb, "Properties", 7 ) +ok: rec +ok: check_record( rec, 1, "Property") +ok: check_record( rec, 2, "Value") +ok: check_record( rec, 3, "Intvalue") +ok: check_record( rec, 4, "Integervalue") +ok: check_record( rec, 5, "Shortvalue") +ok: check_record( rec, 6, "Longvalue") +ok: check_record( rec, 7, "Longcharvalue") +ok: r == ERROR_SUCCESS +ok: rec +ok: check_record( rec, 1, "S255") +ok: check_record( rec, 2, "V0") +ok: 0x3dff == get_columns_table_type(hdb, "Binary", 1 ) +ok: 0x1900 == get_columns_table_type(hdb, "Binary", 2 ) +ok: rec +ok: check_record( rec, 1, "Name") +ok: check_record( rec, 2, "Data") +ok: r == ERROR_SUCCESS +ok: 0x2d48 == get_columns_table_type(hdb, "UIText", 1 ) +ok: 0x1fff == get_columns_table_type(hdb, "UIText", 2 ) +ok: rec +ok: check_record( rec, 1, "Key") +ok: check_record( rec, 2, "Text") +ok: rec +ok: check_record( rec, 1, "s72") +ok: check_record( rec, 2, "L255") +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: hdb +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !strcmp(buffer,"Name") +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !strcmp(buffer,"s64") +ok: r == ERROR_SUCCESS +ok: r == ERROR_INVALID_PARAMETER +ok: rec == 0 +ok: r == ERROR_INVALID_PARAMETER +ok: r == ERROR_INVALID_HANDLE +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: length == strlen(expected) +ok: !lstrcmp(buffer, expected) +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: len == STRING_LENGTH +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: hdb +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: rec +ok: check_record( rec, 1, "s62") +ok: check_record( rec, 2, "V0") +ok: rec +ok: check_record( rec, 1, "Name") +ok: check_record( rec, 2, "Data") +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmp(file, "data") +ok: r == ERROR_SUCCESS +ok: !lstrcmp(buf, "test.txt\n") +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmp(file, "data1") +ok: r == ERROR_SUCCESS +ok: !lstrcmp(buf, "test1.txt\n") +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmp(file, "data1") +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmp(file, "Binary.filename1.1") +ok: r == ERROR_SUCCESS +ok: !lstrcmp(buf, "test.txt\n") +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmp(file, "filename1") +ok: r == ERROR_SUCCESS +ok: !lstrcmp(buf, "test.txt\n") +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: hdb +ok: r == S_OK +ok: r == S_OK +ok: r == S_OK +ok: r == S_OK +ok: r == S_OK +ok: r == S_OK +ok: r == S_OK +ok: r == S_OK +ok: r == S_OK +ok: r == S_OK +ok: r == S_OK +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: check_record( rec, 1, "cond2") +ok: r == ERROR_SUCCESS +ok: check_record( rec, 1, "cond3") +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: hdb +ok: r == S_OK +ok: r == S_OK +ok: r == S_OK +ok: r == S_OK +ok: r == ERROR_SUCCESS +ok: check_record( rec, 4, "zero.cab") +ok: r == ERROR_SUCCESS +ok: check_record( rec, 4, "one.cab") +ok: 2 == r +ok: 1 == r +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: count == 1 +ok: r == ERROR_SUCCESS +ok: !lstrcmp( buf, "2" ) +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmp( buf, "3" ) +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_SUCCESS +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_SUCCESS +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_FUNCTION_FAILED +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: count == 9 +ok: check_record(rec, 1, "FirstPrimaryColumn") +ok: check_record(rec, 2, "SecondPrimaryColumn") +ok: check_record(rec, 3, "ShortInt") +ok: check_record(rec, 4, "ShortIntNullable") +ok: check_record(rec, 5, "LongInt") +ok: check_record(rec, 6, "LongIntNullable") +ok: check_record(rec, 7, "String") +ok: check_record(rec, 8, "LocalizableString") +ok: check_record(rec, 9, "LocalizableStringNullable") +ok: r == ERROR_SUCCESS +ok: count == 9 +ok: check_record(rec, 1, "s255") +ok: check_record(rec, 2, "i2") +ok: check_record(rec, 3, "i2") +ok: check_record(rec, 4, "I2") +ok: check_record(rec, 5, "i4") +ok: check_record(rec, 6, "I4") +ok: check_record(rec, 7, "S255") +ok: check_record(rec, 8, "S0") +ok: check_record(rec, 9, "s0") +ok: r == ERROR_SUCCESS +ok: check_record(rec, 1, "stringage") +ok: check_record(rec, 7, "another string") +ok: check_record(rec, 8, "localizable") +ok: check_record(rec, 9, "duh") +ok: i == 5 +ok: i == 2 +ok: i == MSI_NULL_INTEGER +ok: i == 2147483640 +ok: i == -2147483640 +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: count == 2 +ok: check_record(rec, 1, "PrimaryOne") +ok: check_record(rec, 2, "PrimaryTwo") +ok: r == ERROR_SUCCESS +ok: count == 2 +ok: check_record(rec, 1, "s255") +ok: check_record(rec, 2, "s255") +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: check_record(rec, 1, "papaya") +ok: check_record(rec, 2, "leaf") +ok: r == ERROR_SUCCESS +ok: check_record(rec, 1, "papaya") +ok: check_record(rec, 2, "flower") +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: count == 6 +ok: check_record(rec, 1, "A") +ok: check_record(rec, 2, "B") +ok: check_record(rec, 3, "C") +ok: check_record(rec, 4, "D") +ok: check_record(rec, 5, "E") +ok: check_record(rec, 6, "F") +ok: r == ERROR_SUCCESS +ok: count == 6 +ok: check_record(rec, 1, "s72") +ok: check_record(rec, 2, "s72") +ok: check_record(rec, 3, "s72") +ok: check_record(rec, 4, "s72") +ok: check_record(rec, 5, "s72") +ok: check_record(rec, 6, "s72") +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: check_record(rec, 1, "a") +ok: check_record(rec, 2, "b") +ok: check_record(rec, 3, "c") +ok: check_record(rec, 4, "d") +ok: check_record(rec, 5, "e") +ok: check_record(rec, 6, "f") +ok: r == ERROR_SUCCESS +ok: check_record(rec, 1, "g") +ok: check_record(rec, 2, "h") +ok: check_record(rec, 3, "i") +ok: check_record(rec, 4, "j") +ok: check_record(rec, 5, "k") +ok: check_record(rec, 6, "l") +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmp(file, "filename1") +ok: r == ERROR_SUCCESS +ok: !lstrcmp(buf, "just some words") +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: hdb +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_SUCCESS +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_SUCCESS +ok: r == ERROR_FUNCTION_FAILED +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: hdb +ok: i == MY_NVIEWS +ok: i == MY_NVIEWS +ok: r == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: hdb +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == S_OK +ok: r == S_OK +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !memcmp(buffer, "naengmyon", 9) +ok: sz == 9 +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == 1 +ok: r == ERROR_SUCCESS +ok: !lstrcmpA(buffer, "c") +ok: r == 0x80000000 +ok: r == 5 +ok: r == ERROR_SUCCESS +ok: r == 2 +ok: r == ERROR_SUCCESS +ok: !lstrcmpA(buffer, "b") +ok: r == 0x80000000 +ok: r == 0x80000000 +ok: r == ERROR_NO_MORE_ITEMS +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: hdb +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: count == 2 +ok: r == ERROR_SUCCESS +ok: !lstrcmp( buf, join_res_first[i].one ) +ok: r == ERROR_SUCCESS +ok: !lstrcmp( buf, join_res_first[i].two ) +ok: count == 2 +ok: r == ERROR_SUCCESS +ok: !lstrcmp( buf, join_res_first[i].one ) +ok: r == ERROR_SUCCESS +ok: !lstrcmp( buf, join_res_first[i].two ) +ok: count == 2 +ok: r == ERROR_SUCCESS +ok: !lstrcmp( buf, join_res_first[i].one ) +ok: r == ERROR_SUCCESS +ok: !lstrcmp( buf, join_res_first[i].two ) +ok: count == 2 +ok: r == ERROR_SUCCESS +ok: !lstrcmp( buf, join_res_first[i].one ) +ok: r == ERROR_SUCCESS +ok: !lstrcmp( buf, join_res_first[i].two ) +ok: count == 2 +ok: r == ERROR_SUCCESS +ok: !lstrcmp( buf, join_res_first[i].one ) +ok: r == ERROR_SUCCESS +ok: !lstrcmp( buf, join_res_first[i].two ) +ok: i == 5 +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: i == 24 +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: count == 2 +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: count == 2 +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: data_correct +ok: i == 2 +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: count == 2 +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: count == 2 +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: data_correct +ok: i == 2 +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: count == 2 +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: data_correct +ok: i == 1 +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: count == 2 +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: data_correct +ok: i == 1 +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: count == 2 +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: count == 2 +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: count == 2 +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: count == 2 +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: count == 2 +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: count == 2 +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: data_correct +ok: i == 6 +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: count == 2 +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: count == 2 +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: count == 2 +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: data_correct +ok: i == 3 +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: count == 2 +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: count == 2 +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: count == 2 +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: count == 2 +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: count == 2 +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: count == 2 +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: data_correct +ok: i == 6 +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: count == 4 +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: count == 4 +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: count == 4 +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: count == 4 +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: count == 4 +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: count == 4 +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: data_correct +ok: i == 6 +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: count == 6 +ok: count == 6 +ok: count == 6 +ok: count == 6 +ok: count == 6 +ok: count == 6 +ok: data_correct +ok: i == 6 +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_FUNCTION_FAILED +ok: r == ERROR_SUCCESS +ok: r == ERROR_FUNCTION_FAILED +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmp( buf, "epicranius" ) +ok: cond == MSICONDITION_ERROR +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: hdb +ok: cond == MSICONDITION_ERROR +ok: cond == MSICONDITION_NONE +ok: cond == MSICONDITION_NONE +ok: cond == MSICONDITION_NONE +ok: cond == MSICONDITION_NONE +ok: r == ERROR_SUCCESS +ok: cond == MSICONDITION_TRUE +ok: r == ERROR_SUCCESS +ok: cond == MSICONDITION_TRUE +ok: r == ERROR_SUCCESS +ok: cond == MSICONDITION_FALSE +ok: r == ERROR_SUCCESS +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: cond == MSICONDITION_NONE +ok: r == ERROR_SUCCESS +ok: cond == MSICONDITION_TRUE +ok: r == ERROR_FUNCTION_FAILED +ok: cond == MSICONDITION_NONE +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: 0 == strcmp("G255", buf) +ok: r == ERROR_SUCCESS +ok: 0 == strcmp("j2", buf) +ok: r == ERROR_SUCCESS +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_NO_MORE_ITEMS +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: hdb +ok: r == ERROR_SUCCESS +ok: cond == MSICONDITION_FALSE +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_SUCCESS +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: count == 8 +ok: check_record(rec, 1, "one") +ok: check_record(rec, 2, "two") +ok: check_record(rec, 3, "three") +ok: check_record(rec, 4, "four") +ok: check_record(rec, 5, "five") +ok: check_record(rec, 6, "six") +ok: check_record(rec, 7, "seven") +ok: check_record(rec, 8, "eight") +ok: r == ERROR_SUCCESS +ok: count == 8 +ok: check_record(rec, 1, "I2") +ok: check_record(rec, 2, "I2") +ok: check_record(rec, 3, "I2") +ok: check_record(rec, 4, "I4") +ok: check_record(rec, 5, "i2") +ok: check_record(rec, 6, "i2") +ok: check_record(rec, 7, "i2") +ok: check_record(rec, 8, "i4") +ok: r == ERROR_SUCCESS +ok: r == ERROR_FUNCTION_FAILED +ok: r == ERROR_NO_MORE_ITEMS +ok: r == -1 +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == 8 +ok: i == MSI_NULL_INTEGER +ok: i == MSI_NULL_INTEGER +ok: i == 2 +ok: i == 4 +ok: i == 5 +ok: i == 6 +ok: i == 7 +ok: i == 8 +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == TRUE +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmp(result, "this is text") +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrlen(result) +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmp(result, "this is text") +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrlen(result) +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmp(result, "this is text") +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmp(result, "this is text") +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmp(result, "this is text") +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == 8 +ok: r == ERROR_SUCCESS +ok: r == 8 +ok: r == ERROR_SUCCESS +ok: r == 5 +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmp(buffer, "foo") +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmp(buffer, "baz") +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmp(buffer, "bar") +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmp(buffer, "foo") +ok: r == ERROR_SUCCESS +ok: !lstrcmp(buffer, "baz") +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmp(buffer, "baz") +ok: r == ERROR_SUCCESS +ok: !lstrcmp(buffer, "bar") +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmp(buffer, "baz") +ok: r == ERROR_SUCCESS +ok: !lstrcmp(buffer, "baz") +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmp(buffer, "baz") +ok: r == ERROR_SUCCESS +ok: !lstrcmp(buffer, "foo") +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmp(buffer, "bar") +ok: r == ERROR_SUCCESS +ok: !lstrcmp(buffer, "foo") +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmp(buffer, "A") +ok: r == ERROR_SUCCESS +ok: !lstrcmp(buffer, "B") +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmp(buffer, "C") +ok: r == ERROR_SUCCESS +ok: !lstrcmp(buffer, "E") +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmp(buffer, "D") +ok: r == ERROR_SUCCESS +ok: !lstrcmp(buffer, "E") +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmp(buffer, "F") +ok: r == ERROR_SUCCESS +ok: !lstrcmp(buffer, "A") +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: hdb +ok: r == S_OK +ok: r == S_OK +ok: r == S_OK +ok: r == S_OK +ok: r == S_OK +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmp(buf, "apple") +ok: r == ERROR_SUCCESS +ok: !lstrcmp(buf, "two") +ok: r == 1 +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmp(buf, "apple") +ok: r == ERROR_SUCCESS +ok: !lstrcmp(buf, "two") +ok: r == 2 +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmp(buf, "apple") +ok: r == ERROR_SUCCESS +ok: !lstrcmp(buf, "two") +ok: r == 2 +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmp(buf, "banana") +ok: r == ERROR_SUCCESS +ok: !lstrcmp(buf, "three") +ok: r == 3 +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == 1 +ok: r == 0 +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == 3 +ok: r == 4 +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == 5 +ok: r == 6 +ok: r == ERROR_SUCCESS +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == 1 +ok: r == 0 +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == 3 +ok: r == 0 +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == 5 +ok: r == 0 +ok: r == ERROR_SUCCESS +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: count == test_max +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: ( test_max - a + offset) == b +ok: r == ERROR_SUCCESS +ok: count == test_max +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: hrec != 0 +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == 1 +ok: r == 2 +ok: r == ERROR_SUCCESS +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: hrec != 0 +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == 1 +ok: r == 4 +ok: r == ERROR_SUCCESS +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == 2 +ok: r == 1 +ok: r == ERROR_SUCCESS +ok: !lstrcmp(buffer, "one") +ok: r == ERROR_SUCCESS +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == 2 +ok: r == 2 +ok: r == ERROR_SUCCESS +ok: !lstrcmp(buffer, "two") +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == 2 +ok: r == 5 +ok: r == ERROR_SUCCESS +ok: !lstrcmp(buffer, "five") +ok: r == ERROR_SUCCESS +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: hr == S_OK +ok: stg != NULL +ok: hr == S_OK +ok: stm != NULL +ok: hr == S_OK +ok: read == 4 +ok: hr == S_OK +ok: hr == S_OK +ok: stm != NULL +ok: hr == S_OK +ok: read == 8 +ok: hr == S_OK +ok: hr == S_OK +ok: stm != NULL +ok: hr == S_OK +ok: read == 24 +ok: !memcmp(buffer, data12, read) +ok: hr == S_OK +ok: hr == S_OK +ok: stm != NULL +ok: hr == S_OK +ok: hr == S_OK +ok: hr == S_OK +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == 3 +ok: r == ERROR_SUCCESS +ok: !lstrcmp(buffer, "Cindy") +ok: r == ERROR_SUCCESS +ok: !lstrcmp(buffer, "2937550") +ok: r == ERROR_SUCCESS +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: hr == S_OK +ok: stg != NULL +ok: hr == S_OK +ok: !lstrcmpW(stat.pwcsName, database_table_data[n].name) +ok: hr == S_OK +ok: stm != NULL +ok: hr == S_OK +ok: count == database_table_data[n].size +ok: !memcmp(data, check, MAX_PATH) +ok: !lstrcmpW(stat.pwcsName, database_table_data[n].name) +ok: hr == S_OK +ok: stm != NULL +ok: hr == S_OK +ok: count == database_table_data[n].size +ok: !memcmp(data, check, MAX_PATH) +ok: !lstrcmpW(stat.pwcsName, database_table_data[n].name) +ok: hr == S_OK +ok: stm != NULL +ok: hr == S_OK +ok: count == database_table_data[n].size +ok: !memcmp(data, database_table_data[n].data, database_table_data[n].size) +ok: n == 3 +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: hdb +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: val == 3 +ok: val == 4 +ok: r == ERROR_SUCCESS +ok: val == 5 +ok: val == 6 +ok: r == ERROR_SUCCESS +ok: val == 1 +ok: val == 2 +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: val == 1 +ok: val == 12 +ok: r == ERROR_SUCCESS +ok: val == 3 +ok: val == 12 +ok: r == ERROR_SUCCESS +ok: val == 5 +ok: val == 12 +ok: r == ERROR_SUCCESS +ok: val == 1 +ok: val == 14 +ok: r == ERROR_SUCCESS +ok: val == 3 +ok: val == 14 +ok: r == ERROR_SUCCESS +ok: val == 5 +ok: val == 14 +ok: r == ERROR_SUCCESS +ok: val == 1 +ok: val == 10 +ok: r == ERROR_SUCCESS +ok: val == 3 +ok: val == 10 +ok: r == ERROR_SUCCESS +ok: val == 5 +ok: val == 10 +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmp(buffer, "dos") +ok: r == 3 +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == 1 +ok: r == ERROR_SUCCESS +ok: r == 4 +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmpA(buf, "two") +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmp(buf, "This is a \"string\" ok") +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmp(buf, "This is a new 'string' ok") +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_SUCCESS +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmpA(buf, "\rOne") +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmpA(buf, "Tw\ro") +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmpA(buf, "Three\r") +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_SUCCESS +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmpA(buf, "Table") +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmpA(buf, "Table2") +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmpA(buf, "Table3") +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmpA(buf, "Table") +ok: r == 1 +ok: r == ERROR_SUCCESS +ok: !lstrcmpA(buf, "A") +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmpA(buf, "Table2") +ok: r == 1 +ok: r == ERROR_SUCCESS +ok: !lstrcmpA(buf, "A") +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmpA(buf, "Table3") +ok: r == 1 +ok: r == ERROR_SUCCESS +ok: !lstrcmpA(buf, "A") +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_SUCCESS +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmpA(buf, "hi") +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_SUCCESS +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_SUCCESS +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_SUCCESS +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_SUCCESS +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_SUCCESS +ok: !lstrcmpA(buffer, "\r\n\r\n0\t_ForceCodepage\r\n") +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmpA(buffer, "\r\n\r\n850\t_ForceCodepage\r\n") +ok: r == ERROR_FUNCTION_FAILED +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmpA(buffer, "hi") +ok: size == 2 +ok: r == 2 +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmpA(buffer, "hello") +ok: size == 5 +ok: r == 2 +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == 7 +ok: r == 8 +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == 7 +ok: r == 9 +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == 7 +ok: r == 10 +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: hdb +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: hrec +ok: check_record(hrec, 1, "s62") +ok: check_record(hrec, 2, "V0") +ok: hrec +ok: check_record(hrec, 1, "Name") +ok: check_record(hrec, 2, "Data") +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmp(file, "stgname") +ok: r == ERROR_INVALID_DATA +ok: !lstrcmp(buf, "apple") +ok: size == 0 +ok: r == ERROR_NO_MORE_ITEMS +ok: hr == S_OK +ok: stg != NULL +ok: hr == S_OK +ok: inner != NULL +ok: hr == S_OK +ok: stm != NULL +ok: hr == S_OK +ok: size == 8 +ok: !lstrcmpA(buf, "stgdata") +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmpA(buf, "One") +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmpA(buf, "One") +ok: r == 1 +ok: r == ERROR_SUCCESS +ok: !lstrcmpA(buf, "A") +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_FUNCTION_FAILED +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_SUCCESS +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmpA(buf, "One") +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmpA(buf, "One") +ok: r == 1 +ok: r == ERROR_SUCCESS +ok: !lstrcmpA(buf, "B") +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmpA(buf, "One") +ok: r == 2 +ok: r == ERROR_SUCCESS +ok: !lstrcmpA(buf, "C") +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_SUCCESS +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_NO_MORE_ITEMS +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: hdb +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == vals[i][0] +ok: r == vals[i][1] +ok: r == ERROR_SUCCESS +ok: r == vals[i][0] +ok: r == vals[i][1] +ok: r == ERROR_SUCCESS +ok: r == vals[i][0] +ok: r == vals[i][1] +ok: r == ERROR_SUCCESS +ok: r == vals[i][0] +ok: r == vals[i][1] +ok: r == ERROR_NO_MORE_ITEMS +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: hdb +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_FUNCTION_FAILED +ok: r == ERROR_FUNCTION_FAILED +ok: r == ERROR_SUCCESS +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ordervals[i][0] +ok: r == ordervals[i][1] +ok: r == ordervals[i][2] +ok: r == ERROR_SUCCESS +ok: r == ordervals[i][0] +ok: r == ordervals[i][1] +ok: r == ordervals[i][2] +ok: r == ERROR_SUCCESS +ok: r == ordervals[i][0] +ok: r == ordervals[i][1] +ok: r == ordervals[i][2] +ok: r == ERROR_SUCCESS +ok: r == ordervals[i][0] +ok: r == ordervals[i][1] +ok: r == ordervals[i][2] +ok: r == ERROR_SUCCESS +ok: r == ordervals[i][0] +ok: r == ordervals[i][1] +ok: r == ordervals[i][2] +ok: r == ERROR_SUCCESS +ok: r == ordervals[i][0] +ok: r == ordervals[i][1] +ok: r == ordervals[i][2] +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ordervals[i][0] +ok: r == ordervals[i][1] +ok: r == ordervals[i][2] +ok: r == ERROR_SUCCESS +ok: r == ordervals[i][0] +ok: r == ordervals[i][1] +ok: r == ordervals[i][2] +ok: r == ERROR_SUCCESS +ok: r == ordervals[i][0] +ok: r == ordervals[i][1] +ok: r == ordervals[i][2] +ok: r == ERROR_SUCCESS +ok: r == ordervals[i][0] +ok: r == ordervals[i][1] +ok: r == ordervals[i][2] +ok: r == ERROR_SUCCESS +ok: r == ordervals[i][0] +ok: r == ordervals[i][1] +ok: r == ordervals[i][2] +ok: r == ERROR_SUCCESS +ok: r == ordervals[i][0] +ok: r == ordervals[i][1] +ok: r == ordervals[i][2] +ok: r == ERROR_NO_MORE_ITEMS +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: hdb +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmpA("s255", buf) +ok: r == ERROR_SUCCESS +ok: !lstrcmpA("I2", buf) +ok: r == ERROR_SUCCESS +ok: !lstrcmpA("S255", buf) +ok: r == ERROR_SUCCESS +ok: !lstrcmpA("i2", buf) +ok: r == ERROR_SUCCESS +ok: !lstrcmpA("i2", buf) +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmpA("D", buf) +ok: r == ERROR_SUCCESS +ok: !lstrcmpA("E", buf) +ok: r == ERROR_SUCCESS +ok: !lstrcmpA("A", buf) +ok: r == ERROR_SUCCESS +ok: !lstrcmpA("C", buf) +ok: r == ERROR_SUCCESS +ok: !lstrcmpA("B", buf) +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmpA("bc", buf) +ok: r == 3 +ok: r == ERROR_SUCCESS +ok: !lstrcmpA("a", buf) +ok: r == 2 +ok: r == 1 +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmpA("T", buf) +ok: r == 1 +ok: r == ERROR_SUCCESS +ok: !lstrcmpA("D", buf) +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmpA("T", buf) +ok: r == 2 +ok: r == ERROR_SUCCESS +ok: !lstrcmpA("E", buf) +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmpA("T", buf) +ok: r == 3 +ok: r == ERROR_SUCCESS +ok: !lstrcmpA("A", buf) +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmpA("T", buf) +ok: r == 4 +ok: r == ERROR_SUCCESS +ok: !lstrcmpA("C", buf) +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmpA("T", buf) +ok: r == 5 +ok: r == ERROR_SUCCESS +ok: !lstrcmpA("B", buf) +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmpA("i2", buf) +ok: r == ERROR_SUCCESS +ok: !lstrcmpA("S255", buf) +ok: r == ERROR_SUCCESS +ok: !lstrcmpA("s255", buf) +ok: r == ERROR_SUCCESS +ok: !lstrcmpA("I2", buf) +ok: r == ERROR_SUCCESS +ok: !lstrcmpA("i2", buf) +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmpA("C", buf) +ok: r == ERROR_SUCCESS +ok: !lstrcmpA("A", buf) +ok: r == ERROR_SUCCESS +ok: !lstrcmpA("D", buf) +ok: r == ERROR_SUCCESS +ok: !lstrcmpA("E", buf) +ok: r == ERROR_SUCCESS +ok: !lstrcmpA("B", buf) +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == 2 +ok: r == ERROR_SUCCESS +ok: !lstrcmpA("a", buf) +ok: r == ERROR_SUCCESS +ok: !lstrcmpA("bc", buf) +ok: r == 3 +ok: r == 1 +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmpA("T", buf) +ok: r == 1 +ok: r == ERROR_SUCCESS +ok: !lstrcmpA("D", buf) +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmpA("T", buf) +ok: r == 2 +ok: r == ERROR_SUCCESS +ok: !lstrcmpA("E", buf) +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmpA("T", buf) +ok: r == 3 +ok: r == ERROR_SUCCESS +ok: !lstrcmpA("A", buf) +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmpA("T", buf) +ok: r == 4 +ok: r == ERROR_SUCCESS +ok: !lstrcmpA("C", buf) +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmpA("T", buf) +ok: r == 5 +ok: r == ERROR_SUCCESS +ok: !lstrcmpA("B", buf) +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: count == 14 +ok: r == ERROR_SUCCESS +ok: type == VT_I2 +ok: int_value == 1252 +ok: r == ERROR_SUCCESS +ok: type == VT_LPSTR +ok: size == 18 +ok: !strcmp(str_value, "Installer Database") +ok: r == ERROR_SUCCESS +ok: type == VT_LPSTR +ok: !strcmp(str_value, "Installer description") +ok: r == ERROR_SUCCESS +ok: type == VT_LPSTR +ok: !strcmp(str_value, "WineHQ") +ok: r == ERROR_SUCCESS +ok: type == VT_LPSTR +ok: !strcmp(str_value, "Installer") +ok: r == ERROR_SUCCESS +ok: type == VT_LPSTR +ok: !strcmp(str_value, "Installer comments") +ok: r == ERROR_SUCCESS +ok: type == VT_LPSTR +ok: !strcmp(str_value, "Intel;1033,2057") +ok: r == ERROR_SUCCESS +ok: type == VT_LPSTR +ok: !strcmp(str_value, "{12345678-1234-1234-1234-123456789012}") +ok: r == ERROR_SUCCESS +ok: type == VT_FILETIME +ok: r == ERROR_SUCCESS +ok: type == VT_FILETIME +ok: r == ERROR_SUCCESS +ok: type == VT_I4 +ok: int_value == 200 +ok: r == ERROR_SUCCESS +ok: type == VT_I4 +ok: int_value == 2 +ok: r == ERROR_SUCCESS +ok: type == VT_I4 +ok: int_value == 2 +ok: r == ERROR_SUCCESS +ok: type == VT_LPSTR +ok: !strcmp(str_value, "Vim") +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: hdb +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: !strcmp(buffer,"b") +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: !strcmp(buffer,"b") +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: res == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmp(buffer, "\2") +ok: r == ERROR_SUCCESS +ok: !lstrcmp(buffer, "A") +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmp(buffer, "\1") +ok: r == ERROR_SUCCESS +ok: !lstrcmp(buffer, "B") +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !memcmp(bufferW, letter_a_ring, sizeof(letter_a_ring)) +ok: r == ERROR_SUCCESS +ok: !lstrcmpW(bufferW, letter_C) +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !memcmp(bufferW, letter_a_with_ring, sizeof(letter_a_with_ring)) +ok: r == ERROR_SUCCESS +ok: !lstrcmpW(bufferW, letter_D) +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !memcmp(bufferW, letter_a_with_ring, sizeof(letter_a_with_ring)) +ok: r == ERROR_SUCCESS +ok: !lstrcmpW(bufferW, letter_D) +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !memcmp( "text\r\ntext\ntext", buffer, sizeof("text\r\ntext\ntext") - 1 ) +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == 1 +ok: r == ERROR_SUCCESS +ok: r == 1 +ok: r == ERROR_SUCCESS +ok: !buffer[0] +ok: r == ERROR_SUCCESS +ok: r == 1 +ok: r == ERROR_SUCCESS +ok: !lstrcmpA( buffer, "f0" ) +ok: r == ERROR_SUCCESS +ok: !buffer[0] +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !buffer[0] +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == 2 +ok: r == ERROR_SUCCESS +ok: !lstrcmpA( buffer, "1" ) +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !buffer[0] +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == 2 +ok: r == ERROR_SUCCESS +ok: !buffer[0] +ok: r == ERROR_SUCCESS +ok: !lstrcmpA( buffer, "1" ) +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !buffer[0] +ok: r == ERROR_SUCCESS +ok: !lstrcmpA( buffer, "3" ) +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == 3 +ok: r == ERROR_SUCCESS +ok: !lstrcmpA( buffer, "1" ) +ok: r == ERROR_SUCCESS +ok: !buffer[0] +ok: r == ERROR_SUCCESS +ok: !lstrcmpA( buffer, "2" ) +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmpA( buffer, "3" ) +ok: r == ERROR_SUCCESS +ok: !buffer[0] +ok: r == ERROR_SUCCESS +ok: !lstrcmpA( buffer, "4" ) +ok: r == ERROR_NO_MORE_ITEMS +ok: r == ERROR_SUCCESS +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_BAD_QUERY_SYNTAX +ok: r == ERROR_SUCCESS diff --git a/tests/testrecord.c b/tests/testrecord.c new file mode 100644 index 0000000..7dfd4e3 --- /dev/null +++ b/tests/testrecord.c @@ -0,0 +1,621 @@ +/* + * Copyright (C) 2005 Mike McCormack for CodeWeavers + * + * A test program for MSI records + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include + +#include "test.h" + +static const char *msifile = "winetest-record.msi"; + +static BOOL create_temp_file(char *name) +{ + UINT r; + unsigned char buffer[26], i; + DWORD sz; + HANDLE handle; + + r = GetTempFileName(".", "msitest",0,name); + if(!r) + return r; + handle = CreateFile(name, GENERIC_READ|GENERIC_WRITE, + 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if(handle==INVALID_HANDLE_VALUE) + return 0; + for(i=0; i<26; i++) + buffer[i]=i+'a'; + r = WriteFile(handle,buffer,sizeof buffer,&sz,NULL); + CloseHandle(handle); + return r; +} + +static void test_msirecord(void) +{ + DWORD r, sz; + INT i; + MSIHANDLE h; + char buf[10]; + WCHAR bufW[10]; + const char str[] = "hello"; + const WCHAR strW[] = { 'h','e','l','l','o',0}; + char filename[MAX_PATH]; + + /* check behaviour with an invalid record */ + r = MsiRecordGetFieldCount(0); + ok(r==-1, "field count for invalid record not -1\n"); + SetLastError(0); + r = MsiRecordIsNull(0, 0); + ok(r==0, "invalid handle not considered to be non-null...\n"); + ok(GetLastError()==0, "MsiRecordIsNull set LastError\n"); + r = MsiRecordGetInteger(0,0); + ok(r == MSI_NULL_INTEGER, "got integer from invalid record\n"); + r = MsiRecordSetInteger(0,0,0); + ok(r == ERROR_INVALID_HANDLE, "MsiRecordSetInteger returned wrong error\n"); + r = MsiRecordSetInteger(0,-1,0); + ok(r == ERROR_INVALID_HANDLE, "MsiRecordSetInteger returned wrong error\n"); + SetLastError(0); + h = MsiCreateRecord(-1); + ok(h==0, "created record with -1 elements\n"); + h = MsiCreateRecord(0x10000); + ok(h==0, "created record with 0x10000 elements\n"); + /* doesn't set LastError */ + ok(GetLastError()==0, "MsiCreateRecord set last error\n"); + r = MsiRecordClearData(0); + ok(r == ERROR_INVALID_HANDLE, "MsiRecordClearData returned wrong error\n"); + r = MsiRecordDataSize(0,0); + ok(r == 0, "MsiRecordDataSize returned wrong error\n"); + + + /* check behaviour of a record with 0 elements */ + h = MsiCreateRecord(0); + ok(h!=0, "couldn't create record with zero elements\n"); + r = MsiRecordGetFieldCount(h); + ok(r==0, "field count should be zero\n"); + r = MsiRecordIsNull(h,0); + ok(r, "new record wasn't null\n"); + r = MsiRecordIsNull(h,1); + ok(r, "out of range record wasn't null\n"); + r = MsiRecordIsNull(h,-1); + ok(r, "out of range record wasn't null\n"); + r = MsiRecordDataSize(h,0); + ok(r==0, "size of null record is 0\n"); + sz = sizeof buf; + strcpy(buf,"x"); + r = MsiRecordGetString(h, 0, buf, &sz); + ok(r==ERROR_SUCCESS, "failed to get null string\n"); + ok(sz==0, "null string too long\n"); + ok(buf[0]==0, "null string not set\n"); + + /* same record, but add an integer to it */ + r = MsiRecordSetInteger(h, 0, 0); + ok(r == ERROR_SUCCESS, "Failed to set integer at 0 to 0\n"); + r = MsiRecordIsNull(h,0); + ok(r==0, "new record is null after setting an integer\n"); + r = MsiRecordDataSize(h,0); + ok(r==sizeof(DWORD), "size of integer record is 4\n"); + r = MsiRecordSetInteger(h, 0, 1); + ok(r == ERROR_SUCCESS, "Failed to set integer at 0 to 1\n"); + r = MsiRecordSetInteger(h, 1, 1); + ok(r == ERROR_INVALID_PARAMETER, "set integer at 1\n"); + r = MsiRecordSetInteger(h, -1, 0); + ok(r == ERROR_INVALID_PARAMETER, "set integer at -1\n"); + r = MsiRecordIsNull(h,0); + ok(r==0, "new record is null after setting an integer\n"); + r = MsiRecordGetInteger(h, 0); + ok(r == 1, "failed to get integer\n"); + + /* same record, but add a null or empty string to it */ + r = MsiRecordSetString(h, 0, NULL); + ok(r == ERROR_SUCCESS, "Failed to set null string at 0\n"); + r = MsiRecordIsNull(h, 0); + ok(r == TRUE, "null string not null field\n"); + r = MsiRecordDataSize(h, 0); + ok(r == 0, "size of string record is strlen\n"); + buf[0] = 0; + sz = sizeof buf; + r = MsiRecordGetStringA(h, 0, buf, &sz); + ok(r == ERROR_SUCCESS, "Failed to get string at 0\n"); + ok(buf[0] == 0, "MsiRecordGetStringA returned the wrong string\n"); + ok(sz == 0, "MsiRecordGetStringA returned the wrong length\n"); + bufW[0] = 0; + sz = sizeof bufW / sizeof bufW[0]; + r = MsiRecordGetStringW(h, 0, bufW, &sz); + ok(r == ERROR_SUCCESS, "Failed to get string at 0\n"); + ok(bufW[0] == 0, "MsiRecordGetStringW returned the wrong string\n"); + ok(sz == 0, "MsiRecordGetStringW returned the wrong length\n"); + r = MsiRecordSetString(h, 0, ""); + ok(r == ERROR_SUCCESS, "Failed to set empty string at 0\n"); + r = MsiRecordIsNull(h, 0); + ok(r == TRUE, "null string not null field\n"); + r = MsiRecordDataSize(h, 0); + ok(r == 0, "size of string record is strlen\n"); + buf[0] = 0; + sz = sizeof buf; + r = MsiRecordGetStringA(h, 0, buf, &sz); + ok(r == ERROR_SUCCESS, "Failed to get string at 0\n"); + ok(buf[0] == 0, "MsiRecordGetStringA returned the wrong string\n"); + ok(sz == 0, "MsiRecordGetStringA returned the wrong length\n"); + bufW[0] = 0; + sz = sizeof bufW / sizeof bufW[0]; + r = MsiRecordGetStringW(h, 0, bufW, &sz); + ok(r == ERROR_SUCCESS, "Failed to get string at 0\n"); + ok(bufW[0] == 0, "MsiRecordGetStringW returned the wrong string\n"); + ok(sz == 0, "MsiRecordGetStringW returned the wrong length\n"); + + /* same record, but add a string to it */ + r = MsiRecordSetString(h,0,str); + ok(r == ERROR_SUCCESS, "Failed to set string at 0\n"); + r = MsiRecordGetInteger(h, 0); + ok(r == MSI_NULL_INTEGER, "should get invalid integer\n"); + r = MsiRecordDataSize(h,0); + ok(r==sizeof str-1, "size of string record is strlen\n"); + buf[0]=0; + sz = sizeof buf; + r = MsiRecordGetString(h,0,buf,&sz); + ok(r == ERROR_SUCCESS, "Failed to get string at 0\n"); + ok(0==strcmp(buf,str), "MsiRecordGetString returned the wrong string\n"); + ok(sz == sizeof str-1, "MsiRecordGetString returned the wrong length\n"); + buf[0]=0; + sz = sizeof str - 2; + r = MsiRecordGetString(h,0,buf,&sz); + ok(r == ERROR_MORE_DATA, "small buffer should yield ERROR_MORE_DATA\n"); + ok(sz == sizeof str-1, "MsiRecordGetString returned the wrong length\n"); + ok(0==strncmp(buf,str,sizeof str-3), "MsiRecordGetString returned the wrong string\n"); + ok(buf[sizeof str - 3]==0, "string wasn't nul terminated\n"); + + buf[0]=0; + sz = sizeof str; + r = MsiRecordGetString(h,0,buf,&sz); + ok(r == ERROR_SUCCESS, "wrong error\n"); + ok(sz == sizeof str-1, "MsiRecordGetString returned the wrong length\n"); + ok(0==strcmp(buf,str), "MsiRecordGetString returned the wrong string\n"); + + + memset(bufW, 0, sizeof bufW); + sz = 5; + r = MsiRecordGetStringW(h,0,bufW,&sz); + ok(r == ERROR_MORE_DATA, "wrong error\n"); + ok(sz == 5, "MsiRecordGetString returned the wrong length\n"); + ok(0==memcmp(bufW,strW,8), "MsiRecordGetString returned the wrong string\n"); + + sz = 0; + bufW[0] = 'x'; + r = MsiRecordGetStringW(h,0,bufW,&sz); + ok(r == ERROR_MORE_DATA, "wrong error\n"); + ok(sz == 5, "MsiRecordGetString returned the wrong length\n"); + ok('x'==bufW[0], "MsiRecordGetString returned the wrong string\n"); + + memset(buf, 0, sizeof buf); + sz = 5; + r = MsiRecordGetStringA(h,0,buf,&sz); + ok(r == ERROR_MORE_DATA, "wrong error\n"); + ok(sz == 5, "MsiRecordGetString returned the wrong length\n"); + ok(0==memcmp(buf,str,4), "MsiRecordGetString returned the wrong string\n"); + + sz = 0; + buf[0] = 'x'; + r = MsiRecordGetStringA(h,0,buf,&sz); + ok(r == ERROR_MORE_DATA, "wrong error\n"); + ok(sz == 5, "MsiRecordGetString returned the wrong length\n"); + ok('x'==buf[0], "MsiRecordGetString returned the wrong string\n"); + + /* same record, check we can wipe all the data */ + r = MsiRecordClearData(h); + ok(r == ERROR_SUCCESS, "Failed to clear record\n"); + r = MsiRecordClearData(h); + ok(r == ERROR_SUCCESS, "Failed to clear record again\n"); + r = MsiRecordIsNull(h,0); + ok(r, "cleared record wasn't null\n"); + + /* same record, try converting strings to integers */ + i = MsiRecordSetString(h,0,"42"); + ok(i == ERROR_SUCCESS, "Failed to set string at 0\n"); + i = MsiRecordGetInteger(h, 0); + ok(i == 42, "should get invalid integer\n"); + i = MsiRecordSetString(h,0,"-42"); + ok(i == ERROR_SUCCESS, "Failed to set string at 0\n"); + i = MsiRecordGetInteger(h, 0); + ok(i == -42, "should get invalid integer\n"); + i = MsiRecordSetString(h,0," 42"); + ok(i == ERROR_SUCCESS, "Failed to set string at 0\n"); + i = MsiRecordGetInteger(h, 0); + ok(i == MSI_NULL_INTEGER, "should get invalid integer\n"); + i = MsiRecordSetString(h,0,"42 "); + ok(i == ERROR_SUCCESS, "Failed to set string at 0\n"); + i = MsiRecordGetInteger(h, 0); + ok(i == MSI_NULL_INTEGER, "should get invalid integer\n"); + i = MsiRecordSetString(h,0,"42.0"); + ok(i == ERROR_SUCCESS, "Failed to set string at 0\n"); + i = MsiRecordGetInteger(h, 0); + ok(i == MSI_NULL_INTEGER, "should get invalid integer\n"); + i = MsiRecordSetString(h,0,"0x42"); + ok(i == ERROR_SUCCESS, "Failed to set string at 0\n"); + i = MsiRecordGetInteger(h, 0); + ok(i == MSI_NULL_INTEGER, "should get invalid integer\n"); + i = MsiRecordSetString(h,0,"1000000000000000"); + ok(i == ERROR_SUCCESS, "Failed to set string at 0\n"); + i = MsiRecordGetInteger(h, 0); + ok(i == -1530494976, "should get truncated integer\n"); + i = MsiRecordSetString(h,0,"2147483647"); + ok(i == ERROR_SUCCESS, "Failed to set string at 0\n"); + i = MsiRecordGetInteger(h, 0); + ok(i == 2147483647, "should get maxint\n"); + i = MsiRecordSetString(h,0,"-2147483647"); + ok(i == ERROR_SUCCESS, "Failed to set string at 0\n"); + i = MsiRecordGetInteger(h, 0); + ok(i == -2147483647, "should get -maxint-1\n"); + i = MsiRecordSetString(h,0,"4294967297"); + ok(i == ERROR_SUCCESS, "Failed to set string at 0\n"); + i = MsiRecordGetInteger(h, 0); + ok(i == 1, "should get one\n"); + i = MsiRecordSetString(h,0,"foo"); + ok(i == ERROR_SUCCESS, "Failed to set string at 0\n"); + i = MsiRecordGetInteger(h, 0); + ok(i == MSI_NULL_INTEGER, "should get zero\n"); + i = MsiRecordSetString(h,0,""); + ok(i == ERROR_SUCCESS, "Failed to set string at 0\n"); + i = MsiRecordGetInteger(h, 0); + ok(i == MSI_NULL_INTEGER, "should get zero\n"); + i = MsiRecordSetString(h,0,"+1"); + ok(i == ERROR_SUCCESS, "Failed to set string at 0\n"); + i = MsiRecordGetInteger(h, 0); + ok(i == MSI_NULL_INTEGER, "should get zero\n"); + + /* same record, try converting integers to strings */ + r = MsiRecordSetInteger(h, 0, 32); + ok(r == ERROR_SUCCESS, "Failed to set integer at 0 to 32\n"); + sz = 1; + r = MsiRecordGetString(h, 0, NULL, &sz); + ok(r == ERROR_SUCCESS, "failed to get string from integer\n"); + ok(sz == 2, "length wrong\n"); + buf[0]=0; + sz = sizeof buf; + r = MsiRecordGetString(h, 0, buf, &sz); + ok(r == ERROR_SUCCESS, "failed to get string from integer\n"); + ok(0==strcmp(buf,"32"), "failed to get string from integer\n"); + r = MsiRecordSetInteger(h, 0, -32); + ok(r == ERROR_SUCCESS, "Failed to set integer at 0 to 32\n"); + buf[0]=0; + sz = 1; + r = MsiRecordGetString(h, 0, NULL, &sz); + ok(r == ERROR_SUCCESS, "failed to get string from integer\n"); + ok(sz == 3, "length wrong\n"); + sz = sizeof buf; + r = MsiRecordGetString(h, 0, buf, &sz); + ok(r == ERROR_SUCCESS, "failed to get string from integer\n"); + ok(0==strcmp(buf,"-32"), "failed to get string from integer\n"); + buf[0]=0; + + /* same record, now try streams */ + r = MsiRecordSetStream(h, 0, NULL); + ok(r == ERROR_INVALID_PARAMETER, "set NULL stream\n"); + sz = sizeof buf; + r = MsiRecordReadStream(h, 0, buf, &sz); + ok(r == ERROR_INVALID_DATATYPE, "read non-stream type\n"); + ok(sz == sizeof buf, "set sz\n"); + r = MsiRecordDataSize( h, -1); + ok(r == 0,"MsiRecordDataSize returned wrong size\n"); + r = MsiRecordDataSize( h, 0); + ok(r == 4,"MsiRecordDataSize returned wrong size\n"); + + /* same record, now close it */ + r = MsiCloseHandle(h); + ok(r == ERROR_SUCCESS, "Failed to close handle\n"); + + /* now try streams in a new record - need to create a file to play with */ + r = create_temp_file(filename); + if(!r) + return; + + /* streams can't be inserted in field 0 for some reason */ + h = MsiCreateRecord(2); + ok(h, "couldn't create a two field record\n"); + r = MsiRecordSetStream(h, 0, filename); + ok(r == ERROR_INVALID_PARAMETER, "added stream to field 0\n"); + r = MsiRecordSetStream(h, 1, filename); + ok(r == ERROR_SUCCESS, "failed to add stream to record\n"); + r = MsiRecordReadStream(h, 1, buf, NULL); + ok(r == ERROR_INVALID_PARAMETER, "should return error\n"); + DeleteFile(filename); /* Windows 98 doesn't like this at all, so don't check return. */ + r = MsiRecordReadStream(h, 1, NULL, NULL); + ok(r == ERROR_INVALID_PARAMETER, "should return error\n"); + sz = sizeof buf; + r = MsiRecordReadStream(h, 1, NULL, &sz); + ok(r == ERROR_SUCCESS, "failed to read stream\n"); + ok(sz==26,"couldn't get size of stream\n"); + sz = 0; + r = MsiRecordReadStream(h, 1, buf, &sz); + ok(r == ERROR_SUCCESS, "failed to read stream\n"); + ok(sz==0,"short read\n"); + sz = sizeof buf; + r = MsiRecordReadStream(h, 1, buf, &sz); + ok(r == ERROR_SUCCESS, "failed to read stream\n"); + ok(sz==sizeof buf,"short read\n"); + ok(!strncmp(buf,"abcdefghij",10), "read the wrong thing\n"); + sz = sizeof buf; + r = MsiRecordReadStream(h, 1, buf, &sz); + ok(r == ERROR_SUCCESS, "failed to read stream\n"); + ok(sz==sizeof buf,"short read\n"); + ok(!strncmp(buf,"klmnopqrst",10), "read the wrong thing\n"); + memset(buf,0,sizeof buf); + sz = sizeof buf; + r = MsiRecordReadStream(h, 1, buf, &sz); + ok(r == ERROR_SUCCESS, "failed to read stream\n"); + ok(sz==6,"short read\n"); + ok(!strcmp(buf,"uvwxyz"), "read the wrong thing\n"); + memset(buf,0,sizeof buf); + sz = sizeof buf; + r = MsiRecordReadStream(h, 1, buf, &sz); + ok(r == ERROR_SUCCESS, "failed to read stream\n"); + ok(sz==0,"size non-zero at end of stream\n"); + ok(buf[0]==0, "read something at end of the stream\n"); + r = MsiRecordSetStream(h, 1, NULL); + ok(r == ERROR_SUCCESS, "failed to reset stream\n"); + sz = 0; + r = MsiRecordReadStream(h, 1, NULL, &sz); + ok(r == ERROR_SUCCESS, "bytes left wrong after reset\n"); + ok(sz==26,"couldn't get size of stream\n"); + r = MsiRecordDataSize(h,1); + ok(r == 26,"MsiRecordDataSize returned wrong size\n"); + + /* now close the stream record */ + r = MsiCloseHandle(h); + ok(r == ERROR_SUCCESS, "Failed to close handle\n"); + DeleteFile(filename); /* Delete it for sure, when everything else is closed. */ +} + +static void test_MsiRecordGetString(void) +{ + MSIHANDLE rec; + CHAR buf[MAX_PATH]; + DWORD sz; + UINT r; + + rec = MsiCreateRecord(2); + ok(rec != 0, "Expected a valid handle\n"); + + sz = MAX_PATH; + r = MsiRecordGetString(rec, 1, NULL, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n",r); + ok(sz == 0, "Expected 0, got %d\n",sz); + + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiRecordGetString(rec, 1, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); + ok(sz == 0, "Expected 0, got %d\n", sz); + + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiRecordGetString(rec, 10, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); + ok(sz == 0, "Expected 0, got %d\n", sz); + + MsiCloseHandle(rec); + + rec = MsiCreateRecord(1); + ok(rec != 0, "Expected a valid handle\n"); + + r = MsiRecordSetInteger(rec, 1, 5); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + sz = MAX_PATH; + r = MsiRecordGetString(rec, 1, NULL, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n",r); + ok(sz == 1, "Expected 1, got %d\n",sz); + + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiRecordGetString(rec, 1, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "5"), "Expected \"5\", got \"%s\"\n", buf); + ok(sz == 1, "Expectd 1, got %d\n", sz); + + r = MsiRecordSetInteger(rec, 1, -5); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiRecordGetString(rec, 1, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "-5"), "Expected \"-5\", got \"%s\"\n", buf); + ok(sz == 2, "Expectd 2, got %d\n", sz); + + MsiCloseHandle(rec); +} + +static void test_MsiRecordGetInteger(void) +{ + MSIHANDLE rec; + INT val; + UINT r; + + rec = MsiCreateRecord(1); + ok(rec != 0, "Expected a valid handle\n"); + + r = MsiRecordSetString(rec, 1, "5"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + val = MsiRecordGetInteger(rec, 1); + ok(val == 5, "Expected 5, got %d\n", val); + + r = MsiRecordSetString(rec, 1, "-5"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + val = MsiRecordGetInteger(rec, 1); + ok(val == -5, "Expected -5, got %d\n", val); + + r = MsiRecordSetString(rec, 1, "5apple"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + val = MsiRecordGetInteger(rec, 1); + ok(val == MSI_NULL_INTEGER, "Expected MSI_NULL_INTEGER, got %d\n", val); + + MsiCloseHandle(rec); +} + +static void test_fieldzero(void) +{ + MSIHANDLE hdb, hview, rec; + CHAR buf[MAX_PATH]; + LPCSTR query; + DWORD sz; + UINT r; + + rec = MsiCreateRecord(1); + ok(rec != 0, "Expected a valid handle\n"); + + r = MsiRecordGetInteger(rec, 0); + ok(r == MSI_NULL_INTEGER, "Expected MSI_NULL_INTEGER, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiRecordGetString(rec, 0, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); + ok(sz == 0, "Expectd 0, got %d\n", sz); + + r = MsiRecordIsNull(rec, 0); + ok(r == TRUE, "Expected TRUE, got %d\n", r); + + r = MsiRecordGetInteger(rec, 1); + ok(r == MSI_NULL_INTEGER, "Expected MSI_NULL_INTEGER, got %d\n", r); + + r = MsiRecordSetInteger(rec, 1, 42); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = MsiRecordGetInteger(rec, 0); + ok(r == MSI_NULL_INTEGER, "Expected MSI_NULL_INTEGER, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiRecordGetString(rec, 0, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); + ok(sz == 0, "Expectd 0, got %d\n", sz); + + r = MsiRecordIsNull(rec, 0); + ok(r == TRUE, "Expected TRUE, got %d\n", r); + + r = MsiRecordGetInteger(rec, 1); + ok(r == 42, "Expected 42, got %d\n", r); + + r = MsiRecordSetString(rec, 1, "bologna"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = MsiRecordGetInteger(rec, 0); + ok(r == MSI_NULL_INTEGER, "Expected MSI_NULL_INTEGER, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiRecordGetString(rec, 0, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); + ok(sz == 0, "Expectd 0, got %d\n", sz); + + r = MsiRecordIsNull(rec, 0); + ok(r == TRUE, "Expected TRUE, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiRecordGetString(rec, 1, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "bologna"), "Expected \"bologna\", got \"%s\"\n", buf); + ok(sz == 7, "Expectd 7, got %d\n", sz); + + MsiCloseHandle(rec); + + r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb); + ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n"); + + query = "CREATE TABLE `drone` ( " + "`id` INT, `name` CHAR(32), `number` CHAR(32) " + "PRIMARY KEY `id`)"; + r = MsiDatabaseOpenView(hdb, query, &hview); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + r = MsiViewExecute(hview, 0); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + r = MsiViewClose(hview); + ok(r == ERROR_SUCCESS, "MsiViewClose failed\n"); + r = MsiCloseHandle(hview); + ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n"); + + query = "INSERT INTO `drone` ( `id`, `name`, `number` )" + "VALUES('1', 'Abe', '8675309')"; + r = MsiDatabaseOpenView(hdb, query, &hview); + ok(r == ERROR_SUCCESS, "MsiDatabaseOpenView failed\n"); + r = MsiViewExecute(hview, 0); + ok(r == ERROR_SUCCESS, "MsiViewExecute failed\n"); + r = MsiViewClose(hview); + ok(r == ERROR_SUCCESS, "MsiViewClose failed\n"); + r = MsiCloseHandle(hview); + ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n"); + + r = MsiDatabaseGetPrimaryKeysA(hdb, "drone", &rec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = MsiRecordGetInteger(rec, 0); + ok(r == MSI_NULL_INTEGER, "Expected MSI_NULL_INTEGER, got %d\n", r); + + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiRecordGetString(rec, 0, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "drone"), "Expected \"drone\", got \"%s\"\n", buf); + ok(sz == 5, "Expectd 5, got %d\n", sz); + + r = MsiRecordIsNull(rec, 0); + ok(r == FALSE, "Expected FALSE, got %d\n", r); + + MsiCloseHandle(rec); + + r = MsiDatabaseGetPrimaryKeysA(hdb, "nosuchtable", &rec); + ok(r == ERROR_INVALID_TABLE, "Expected ERROR_INVALID_TABLE, got %d\n", r); + + query = "SELECT * FROM `drone` WHERE `id` = 1"; + r = MsiDatabaseOpenView(hdb, query, &hview); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + r = MsiViewExecute(hview, 0); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + r = MsiViewFetch(hview, &rec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = MsiRecordGetInteger(rec, 0); + ok(r != MSI_NULL_INTEGER && r != 0, "Expected non-NULL value, got %d\n", r); + + r = MsiRecordIsNull(rec, 0); + ok(r == FALSE, "Expected FALSE, got %d\n", r); + + r = MsiCloseHandle(hview); + ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n"); + MsiCloseHandle(rec); + MsiCloseHandle(hdb); + DeleteFileA(msifile); +} + +void main() +{ + test_msirecord(); + test_MsiRecordGetString(); + test_MsiRecordGetInteger(); + test_fieldzero(); +} diff --git a/tests/testrecord.ok b/tests/testrecord.ok new file mode 100644 index 0000000..2b9aa76 --- /dev/null +++ b/tests/testrecord.ok @@ -0,0 +1,214 @@ +ok: r==-1 +ok: r==0 +ok: GetLastError()==0 +ok: r == MSI_NULL_INTEGER +ok: r == ERROR_INVALID_HANDLE +ok: r == ERROR_INVALID_HANDLE +ok: h==0 +ok: h==0 +ok: GetLastError()==0 +ok: r == ERROR_INVALID_HANDLE +ok: r == 0 +ok: h!=0 +ok: r==0 +ok: r +ok: r +ok: r +ok: r==0 +ok: r==ERROR_SUCCESS +ok: sz==0 +ok: buf[0]==0 +ok: r == ERROR_SUCCESS +ok: r==0 +ok: r==sizeof(DWORD) +ok: r == ERROR_SUCCESS +ok: r == ERROR_INVALID_PARAMETER +ok: r == ERROR_INVALID_PARAMETER +ok: r==0 +ok: r == 1 +ok: r == ERROR_SUCCESS +ok: r == TRUE +ok: r == 0 +ok: r == ERROR_SUCCESS +ok: buf[0] == 0 +ok: sz == 0 +ok: r == ERROR_SUCCESS +ok: bufW[0] == 0 +ok: sz == 0 +ok: r == ERROR_SUCCESS +ok: r == TRUE +ok: r == 0 +ok: r == ERROR_SUCCESS +ok: buf[0] == 0 +ok: sz == 0 +ok: r == ERROR_SUCCESS +ok: bufW[0] == 0 +ok: sz == 0 +ok: r == ERROR_SUCCESS +ok: r == MSI_NULL_INTEGER +ok: r==sizeof str-1 +ok: r == ERROR_SUCCESS +ok: 0==strcmp(buf,str) +ok: sz == sizeof str-1 +ok: r == ERROR_MORE_DATA +ok: sz == sizeof str-1 +ok: 0==strncmp(buf,str,sizeof str-3) +ok: buf[sizeof str - 3]==0 +ok: r == ERROR_SUCCESS +ok: sz == sizeof str-1 +ok: 0==strcmp(buf,str) +ok: r == ERROR_MORE_DATA +ok: sz == 5 +ok: 0==memcmp(bufW,strW,8) +ok: r == ERROR_MORE_DATA +ok: sz == 5 +ok: 'x'==bufW[0] +ok: r == ERROR_MORE_DATA +ok: sz == 5 +ok: 0==memcmp(buf,str,4) +ok: r == ERROR_MORE_DATA +ok: sz == 5 +ok: 'x'==buf[0] +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r +ok: i == ERROR_SUCCESS +ok: i == 42 +ok: i == ERROR_SUCCESS +ok: i == -42 +ok: i == ERROR_SUCCESS +ok: i == MSI_NULL_INTEGER +ok: i == ERROR_SUCCESS +ok: i == MSI_NULL_INTEGER +ok: i == ERROR_SUCCESS +ok: i == MSI_NULL_INTEGER +ok: i == ERROR_SUCCESS +ok: i == MSI_NULL_INTEGER +ok: i == ERROR_SUCCESS +ok: i == -1530494976 +ok: i == ERROR_SUCCESS +ok: i == 2147483647 +ok: i == ERROR_SUCCESS +ok: i == -2147483647 +ok: i == ERROR_SUCCESS +ok: i == 1 +ok: i == ERROR_SUCCESS +ok: i == MSI_NULL_INTEGER +ok: i == ERROR_SUCCESS +ok: i == MSI_NULL_INTEGER +ok: i == ERROR_SUCCESS +ok: i == MSI_NULL_INTEGER +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: sz == 2 +ok: r == ERROR_SUCCESS +ok: 0==strcmp(buf,"32") +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: sz == 3 +ok: r == ERROR_SUCCESS +ok: 0==strcmp(buf,"-32") +ok: r == ERROR_INVALID_PARAMETER +ok: r == ERROR_INVALID_DATATYPE +ok: sz == sizeof buf +ok: r == 0 +ok: r == 4 +ok: r == ERROR_SUCCESS +ok: h +ok: r == ERROR_INVALID_PARAMETER +ok: r == ERROR_SUCCESS +ok: r == ERROR_INVALID_PARAMETER +ok: r == ERROR_INVALID_PARAMETER +ok: r == ERROR_SUCCESS +ok: sz==26 +ok: r == ERROR_SUCCESS +ok: sz==0 +ok: r == ERROR_SUCCESS +ok: sz==sizeof buf +ok: !strncmp(buf,"abcdefghij",10) +ok: r == ERROR_SUCCESS +ok: sz==sizeof buf +ok: !strncmp(buf,"klmnopqrst",10) +ok: r == ERROR_SUCCESS +ok: sz==6 +ok: !strcmp(buf,"uvwxyz") +ok: r == ERROR_SUCCESS +ok: sz==0 +ok: buf[0]==0 +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: sz==26 +ok: r == 26 +ok: r == ERROR_SUCCESS +ok: rec != 0 +ok: r == ERROR_SUCCESS +ok: sz == 0 +ok: r == ERROR_SUCCESS +ok: !lstrcmpA(buf, "") +ok: sz == 0 +ok: r == ERROR_SUCCESS +ok: !lstrcmpA(buf, "") +ok: sz == 0 +ok: rec != 0 +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: sz == 1 +ok: r == ERROR_SUCCESS +ok: !lstrcmpA(buf, "5") +ok: sz == 1 +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmpA(buf, "-5") +ok: sz == 2 +ok: rec != 0 +ok: r == ERROR_SUCCESS +ok: val == 5 +ok: r == ERROR_SUCCESS +ok: val == -5 +ok: r == ERROR_SUCCESS +ok: val == MSI_NULL_INTEGER +ok: rec != 0 +ok: r == MSI_NULL_INTEGER +ok: r == ERROR_SUCCESS +ok: !lstrcmpA(buf, "") +ok: sz == 0 +ok: r == TRUE +ok: r == MSI_NULL_INTEGER +ok: r == ERROR_SUCCESS +ok: r == MSI_NULL_INTEGER +ok: r == ERROR_SUCCESS +ok: !lstrcmpA(buf, "") +ok: sz == 0 +ok: r == TRUE +ok: r == 42 +ok: r == ERROR_SUCCESS +ok: r == MSI_NULL_INTEGER +ok: r == ERROR_SUCCESS +ok: !lstrcmpA(buf, "") +ok: sz == 0 +ok: r == TRUE +ok: r == ERROR_SUCCESS +ok: !lstrcmpA(buf, "bologna") +ok: sz == 7 +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == MSI_NULL_INTEGER +ok: r == ERROR_SUCCESS +ok: !lstrcmpA(buf, "drone") +ok: sz == 5 +ok: r == FALSE +ok: r == ERROR_INVALID_TABLE +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r != MSI_NULL_INTEGER && r != 0 +ok: r == FALSE +ok: r == ERROR_SUCCESS diff --git a/tests/testsuminfo.c b/tests/testsuminfo.c new file mode 100644 index 0000000..650f416 --- /dev/null +++ b/tests/testsuminfo.c @@ -0,0 +1,429 @@ +/* + * Copyright (C) 2005 Mike McCormack for CodeWeavers + * + * A test program for MSI database files. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#define COBJMACROS + +#include +#include +#include +#include + +#include "test.h" + +static const char *msifile = "winetest-suminfo.msi"; +static const WCHAR msifileW[] = { + 'w','i','n','e','t','e','s','t','-','s','u','m','i','n','f','o','.','m','s','i',0 }; + +static void test_suminfo(void) +{ + MSIHANDLE hdb = 0, hsuminfo; + UINT r, count, type; + DWORD sz; + INT val; + FILETIME ft; + char buf[0x10]; + + DeleteFile(msifile); + + /* just MsiOpenDatabase should not create a file */ + r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb); + ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n"); + + r = MsiGetSummaryInformation(hdb, NULL, 0, NULL); + ok(r == ERROR_INVALID_PARAMETER, "MsiGetSummaryInformation wrong error\n"); + + r = MsiGetSummaryInformation(hdb, NULL, 0, &hsuminfo); + ok(r == ERROR_SUCCESS, "MsiGetSummaryInformation failed %u\n", r); + + r = MsiCloseHandle(hsuminfo); + ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n"); + + r = MsiGetSummaryInformation(0, "", 0, &hsuminfo); + todo_wine + ok(r == ERROR_INSTALL_PACKAGE_INVALID || r == ERROR_INSTALL_PACKAGE_OPEN_FAILED, + "MsiGetSummaryInformation failed %u\n", r); + + r = MsiGetSummaryInformation(hdb, "", 0, &hsuminfo); + ok(r == ERROR_SUCCESS, "MsiGetSummaryInformation failed %u\n", r); + + r = MsiSummaryInfoGetPropertyCount(0, NULL); + ok(r == ERROR_INVALID_HANDLE, "getpropcount failed\n"); + + r = MsiSummaryInfoGetPropertyCount(hsuminfo, NULL); + ok(r == ERROR_SUCCESS, "getpropcount failed\n"); + + count = -1; + r = MsiSummaryInfoGetPropertyCount(hsuminfo, &count); + ok(r == ERROR_SUCCESS, "getpropcount failed\n"); + ok(count == 0, "count should be zero\n"); + + r = MsiSummaryInfoGetProperty(hsuminfo, 0, NULL, NULL, NULL, 0, NULL); + ok(r == ERROR_SUCCESS, "getpropcount failed\n"); + + r = MsiSummaryInfoGetProperty(hsuminfo, -1, NULL, NULL, NULL, 0, NULL); + ok(r == ERROR_UNKNOWN_PROPERTY, "MsiSummaryInfoGetProperty wrong error\n"); + + r = MsiSummaryInfoGetProperty(hsuminfo, MSI_PID_SECURITY+1, NULL, NULL, NULL, 0, NULL); + ok(r == ERROR_UNKNOWN_PROPERTY, "MsiSummaryInfoGetProperty wrong error\n"); + + type = -1; + r = MsiSummaryInfoGetProperty(hsuminfo, 0, &type, NULL, NULL, 0, NULL); + ok(r == ERROR_SUCCESS, "getpropcount failed\n"); + ok(type == 0, "wrong type\n"); + + type = -1; + val = 1234; + r = MsiSummaryInfoGetProperty(hsuminfo, 0, &type, &val, NULL, 0, NULL); + ok(r == ERROR_SUCCESS, "getpropcount failed\n"); + ok(type == 0, "wrong type\n"); + ok(val == 1234, "wrong val\n"); + + buf[0]='x'; + buf[1]=0; + sz = 0x10; + r = MsiSummaryInfoGetProperty(hsuminfo, MSI_PID_REVNUMBER, &type, &val, NULL, buf, &sz); + ok(r == ERROR_SUCCESS, "getpropcount failed\n"); + ok(buf[0]=='x', "cleared buffer\n"); + ok(sz == 0x10, "count wasn't zero\n"); + ok(type == VT_EMPTY, "should be empty\n"); + + r = MsiSummaryInfoSetProperty(hsuminfo, MSI_PID_TITLE, VT_LPSTR, 0, NULL, "Mike"); + ok(r == ERROR_FUNCTION_FAILED, "MsiSummaryInfoSetProperty wrong error\n"); + + r = MsiSummaryInfoSetProperty(hsuminfo, MSI_PID_TITLE, VT_LPSTR, 1, NULL, "JungAh"); + ok(r == ERROR_FUNCTION_FAILED, "MsiSummaryInfoSetProperty wrong error\n"); + + r = MsiSummaryInfoSetProperty(hsuminfo, MSI_PID_TITLE, VT_LPSTR, 1, &ft, "Mike"); + ok(r == ERROR_FUNCTION_FAILED, "MsiSummaryInfoSetProperty wrong error\n"); + + r = MsiSummaryInfoSetProperty(hsuminfo, MSI_PID_CODEPAGE, VT_I2, 1, &ft, "JungAh"); + ok(r == ERROR_FUNCTION_FAILED, "MsiSummaryInfoSetProperty wrong error\n"); + + r = MsiCloseHandle(hsuminfo); + ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n"); + + /* try again with the update count set */ + r = MsiGetSummaryInformation(hdb, NULL, 1, &hsuminfo); + ok(r == ERROR_SUCCESS, "MsiGetSummaryInformation failed\n"); + + r = MsiSummaryInfoSetProperty(hsuminfo, 0, VT_LPSTR, 1, NULL, NULL); + ok(r == ERROR_DATATYPE_MISMATCH, "MsiSummaryInfoSetProperty wrong error\n"); + + r = MsiSummaryInfoSetProperty(hsuminfo, MSI_PID_CODEPAGE, VT_LPSTR, 1, NULL, NULL); + ok(r == ERROR_DATATYPE_MISMATCH, "MsiSummaryInfoSetProperty wrong error\n"); + + r = MsiSummaryInfoSetProperty(hsuminfo, MSI_PID_TITLE, VT_I4, 0, NULL, "Mike"); + ok(r == ERROR_DATATYPE_MISMATCH, "MsiSummaryInfoSetProperty wrong error\n"); + + r = MsiSummaryInfoSetProperty(hsuminfo, MSI_PID_AUTHOR, VT_I4, 0, NULL, "JungAh"); + ok(r == ERROR_DATATYPE_MISMATCH, "MsiSummaryInfoSetProperty wrong error\n"); + + r = MsiSummaryInfoSetProperty(hsuminfo, MSI_PID_KEYWORDS, VT_I2, 0, NULL, "Mike"); + ok(r == ERROR_DATATYPE_MISMATCH, "MsiSummaryInfoSetProperty wrong error\n"); + + r = MsiSummaryInfoSetProperty(hsuminfo, MSI_PID_COMMENTS, VT_FILETIME, 0, NULL, "JungAh"); + ok(r == ERROR_DATATYPE_MISMATCH, "MsiSummaryInfoSetProperty wrong error\n"); + + r = MsiSummaryInfoSetProperty(hsuminfo, MSI_PID_TEMPLATE, VT_I2, 0, NULL, "Mike"); + ok(r == ERROR_DATATYPE_MISMATCH, "MsiSummaryInfoSetProperty wrong error\n"); + + r = MsiSummaryInfoSetProperty(hsuminfo, MSI_PID_LASTAUTHOR, VT_LPSTR, 0, NULL, NULL); + ok(r == ERROR_INVALID_PARAMETER, "MsiSummaryInfoSetProperty wrong error\n"); + + r = MsiSummaryInfoSetProperty(hsuminfo, MSI_PID_LASTSAVE_DTM, VT_FILETIME, 0, NULL, NULL); + ok(r == ERROR_INVALID_PARAMETER, "MsiSummaryInfoSetProperty wrong error\n"); + + r = MsiSummaryInfoSetProperty(hsuminfo, MSI_PID_LASTAUTHOR, VT_LPWSTR, 0, NULL, "h\0i\0\0"); + ok(r == ERROR_DATATYPE_MISMATCH, "MsiSummaryInfoSetProperty wrong error\n"); + + r = MsiSummaryInfoSetProperty(hsuminfo, MSI_PID_REVNUMBER, VT_I4, 0, NULL, "Jungah"); + ok(r == ERROR_DATATYPE_MISMATCH, "MsiSummaryInfoSetProperty wrong error\n"); + + r = MsiSummaryInfoSetProperty(hsuminfo, MSI_PID_PAGECOUNT, VT_LPSTR, 1, NULL, NULL); + ok(r == ERROR_DATATYPE_MISMATCH, "MsiSummaryInfoSetProperty wrong error\n"); + + r = MsiSummaryInfoSetProperty(hsuminfo, MSI_PID_TITLE, VT_LPSTR, 0, NULL, "Mike"); + ok(r == ERROR_SUCCESS, "MsiSummaryInfoSetProperty failed\n"); + + sz = 2; + strcpy(buf,"x"); + r = MsiSummaryInfoGetProperty(hsuminfo, MSI_PID_TITLE, &type, NULL, NULL, buf, &sz ); + ok(r == ERROR_MORE_DATA, "MsiSummaryInfoSetProperty failed\n"); + ok(sz == 4, "count was wrong\n"); + ok(type == VT_LPSTR, "type was wrong\n"); + ok(!strcmp(buf,"M"), "buffer was wrong\n"); + + sz = 4; + strcpy(buf,"x"); + r = MsiSummaryInfoGetProperty(hsuminfo, MSI_PID_TITLE, &type, NULL, NULL, buf, &sz ); + ok(r == ERROR_MORE_DATA, "MsiSummaryInfoSetProperty failed\n"); + ok(sz == 4, "count was wrong\n"); + ok(type == VT_LPSTR, "type was wrong\n"); + ok(!strcmp(buf,"Mik"), "buffer was wrong\n"); + + r = MsiSummaryInfoSetProperty(hsuminfo, MSI_PID_TITLE, VT_LPSTR, 0, NULL, "JungAh"); + ok(r == ERROR_SUCCESS, "MsiSummaryInfoSetProperty failed\n"); + + r = MsiSummaryInfoSetProperty(hsuminfo, MSI_PID_CODEPAGE, VT_I2, 1, &ft, "Mike"); + ok(r == ERROR_FUNCTION_FAILED, "MsiSummaryInfoSetProperty wrong error\n"); + + r = MsiCloseHandle(hsuminfo); + ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n"); + + /* try again with a higher update count */ + r = MsiGetSummaryInformation(hdb, NULL, 10, &hsuminfo); + ok(r == ERROR_SUCCESS, "MsiGetSummaryInformation failed\n"); + + r = MsiSummaryInfoSetProperty(hsuminfo, MSI_PID_TITLE, VT_LPSTR, 0, NULL, "JungAh"); + ok(r == ERROR_SUCCESS, "MsiSummaryInfoSetProperty failed\n"); + + r = MsiSummaryInfoSetProperty(hsuminfo, MSI_PID_CODEPAGE, VT_LPSTR, 1, NULL, NULL); + ok(r == ERROR_DATATYPE_MISMATCH, "MsiSummaryInfoSetProperty wrong error\n"); + + r = MsiSummaryInfoSetProperty(hsuminfo, MSI_PID_CODEPAGE, VT_I2, 1, NULL, NULL); + ok(r == ERROR_SUCCESS, "MsiSummaryInfoSetProperty wrong error\n"); + + r = MsiSummaryInfoSetProperty(hsuminfo, MSI_PID_CODEPAGE, VT_I2, 1, &ft, "Mike"); + ok(r == ERROR_SUCCESS, "MsiSummaryInfoSetProperty wrong error\n"); + + r = MsiSummaryInfoSetProperty(hsuminfo, MSI_PID_AUTHOR, VT_LPSTR, 1, &ft, "Mike"); + ok(r == ERROR_SUCCESS, "MsiSummaryInfoSetProperty wrong error\n"); + + r = MsiSummaryInfoPersist(hsuminfo); + ok(r == ERROR_SUCCESS, "MsiSummaryInfoPersist failed\n"); + + MsiDatabaseCommit(hdb); + + r = MsiCloseHandle(hsuminfo); + ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n"); + + r = MsiCloseHandle(hdb); + ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n"); + + /* filename, non-zero update count */ + r = MsiGetSummaryInformation(0, msifile, 1, &hsuminfo); + ok(r == ERROR_SUCCESS, "MsiGetSummaryInformation failed\n"); + + r = MsiSummaryInfoSetProperty(hsuminfo, MSI_PID_AUTHOR, VT_LPSTR, 1, &ft, "Mike"); + ok(r == ERROR_SUCCESS, "MsiSummaryInfoSetProperty wrong error\n"); + + r = MsiSummaryInfoPersist(hsuminfo); + ok(r == ERROR_SUCCESS, "MsiSummaryInfoPersist failed %u\n", r); + + r = MsiCloseHandle(hsuminfo); + ok(r == ERROR_SUCCESS, "MsiCloseHandle failed %u\n", r); + + /* filename, zero update count */ + r = MsiGetSummaryInformation(0, msifile, 0, &hsuminfo); + ok(r == ERROR_SUCCESS, "MsiGetSummaryInformation failed %u\n", r); + + r = MsiSummaryInfoSetProperty(hsuminfo, MSI_PID_AUTHOR, VT_LPSTR, 1, &ft, "Mike"); + todo_wine ok(r == ERROR_FUNCTION_FAILED, "MsiSummaryInfoSetProperty wrong error, %u\n", r); + + r = MsiSummaryInfoPersist(hsuminfo); + ok(r == ERROR_FUNCTION_FAILED, "MsiSummaryInfoPersist wrong error %u\n", r); + + r = MsiCloseHandle(hsuminfo); + ok(r == ERROR_SUCCESS, "MsiCloseHandle failed\n"); + + r = DeleteFile(msifile); + ok(r, "DeleteFile failed\n"); +} + +static const WCHAR tb[] = { 0x4840, 0x3f7f, 0x4164, 0x422f, 0x4836, 0 }; /* _Tables */ +static const WCHAR sd[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0 }; /* _StringData */ +static const WCHAR sp[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0 }; /* _StringPool */ + +#define LOSE_CONST(x) ((LPSTR)(UINT_PTR)(x)) + +static void test_create_database_binary(void) +{ + static const CLSID CLSID_MsiDatabase = + { 0xc1084, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46 } }; + static const CLSID IID_IPropertySetStorage = + { 0x13a, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46 } }; + static const CLSID FMTID_SummaryInformation = + { 0xf29f85e0, 0x4ff9, 0x1068, {0xab, 0x91, 0x08, 0x00, 0x2b, 0x27, 0xb3, 0xd9}}; + DWORD mode = STGM_CREATE | STGM_READWRITE | STGM_DIRECT | STGM_SHARE_EXCLUSIVE; + IPropertySetStorage *pss = NULL; + IPropertyStorage *ps = NULL; + IStorage *stg = NULL; + IStream *stm = NULL; + HRESULT r; + PROPSPEC propspec[10]; + PROPVARIANT propvar[10]; + USHORT data[2] = { 0, 0 }; + + r = StgCreateDocfile( msifileW, mode, 0, &stg ); + ok( r == S_OK, "failed to create database\n"); + + r = IStorage_SetClass( stg, &CLSID_MsiDatabase ); + ok( r == S_OK, "failed to set clsid\n"); + + /* create the _StringData stream */ + r = IStorage_CreateStream( stg, sd, STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stm ); + ok( r == S_OK, "failed to create stream\n"); + + IStream_Release( stm ); + + /* create the _StringPool stream */ + r = IStorage_CreateStream( stg, sp, STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stm ); + ok( r == S_OK, "failed to create stream\n"); + + r = IStream_Write( stm, data, sizeof data, NULL ); + ok( r == S_OK, "failed to write stream\n"); + + IStream_Release( stm ); + + /* create the _Tables stream */ + r = IStorage_CreateStream( stg, tb, STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stm ); + ok( r == S_OK, "failed to create stream\n"); + + IStream_Release( stm ); + + r = IStorage_QueryInterface( stg, &IID_IPropertySetStorage, (void**) &pss ); + ok( r == S_OK, "failed to set clsid\n"); + + r = IPropertySetStorage_Create( pss, &FMTID_SummaryInformation, NULL, 0, mode, &ps ); + ok( r == S_OK, "failed to create property set\n"); + + r = IPropertyStorage_SetClass( ps, &FMTID_SummaryInformation ); + ok( r == S_OK, "failed to set class\n"); + + propspec[0].ulKind = PRSPEC_PROPID; + propspec[0].propid = MSI_PID_TITLE; + propvar[0].vt = VT_LPSTR; + propvar[0].pszVal = LOSE_CONST("test title"); + + propspec[1].ulKind = PRSPEC_PROPID; + propspec[1].propid = MSI_PID_SUBJECT; + propvar[1].vt = VT_LPSTR; + propvar[1].pszVal = LOSE_CONST("msi suminfo / property storage test"); + + propspec[2].ulKind = PRSPEC_PROPID; + propspec[2].propid = MSI_PID_AUTHOR; + propvar[2].vt = VT_LPSTR; + propvar[2].pszVal = LOSE_CONST("mike_m"); + + propspec[3].ulKind = PRSPEC_PROPID; + propspec[3].propid = MSI_PID_TEMPLATE; + propvar[3].vt = VT_LPSTR; + propvar[3].pszVal = LOSE_CONST(";1033"); /* actually the string table's codepage */ + + propspec[4].ulKind = PRSPEC_PROPID; + propspec[4].propid = MSI_PID_REVNUMBER; + propvar[4].vt = VT_LPSTR; + propvar[4].pszVal = LOSE_CONST("{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}"); + + propspec[5].ulKind = PRSPEC_PROPID; + propspec[5].propid = MSI_PID_PAGECOUNT; + propvar[5].vt = VT_I4; + propvar[5].lVal = 100; + + propspec[6].ulKind = PRSPEC_PROPID; + propspec[6].propid = MSI_PID_WORDCOUNT; + propvar[6].vt = VT_I4; + propvar[6].lVal = 0; + + /* MSDN says that MSI_PID_LASTPRINTED should be a VT_FILETIME... */ + propspec[7].ulKind = PRSPEC_PROPID; + propspec[7].propid = MSI_PID_LASTPRINTED; + propvar[7].vt = VT_LPSTR; + propvar[7].pszVal = LOSE_CONST("7/1/1999 5:17"); + + r = IPropertyStorage_WriteMultiple( ps, 8, propspec, propvar, MSI_PID_FIRST_USABLE ); + ok( r == S_OK, "failed to write properties\n"); + + IPropertyStorage_Commit( ps, STGC_DEFAULT ); + + IPropertyStorage_Release( ps ); + IPropertySetStorage_Release( pss ); + + IStorage_Commit( stg, STGC_DEFAULT ); + IStorage_Release( stg ); +} + +static void test_summary_binary(void) +{ + MSIHANDLE hdb = 0, hsuminfo = 0; + UINT r, type, count; + INT ival; + DWORD sz; + char sval[20]; + + DeleteFile( msifile ); + + test_create_database_binary(); + + ok( INVALID_FILE_ATTRIBUTES != GetFileAttributes(msifile), "file doesn't exist!\n"); + + /* just MsiOpenDatabase should not create a file */ + r = MsiOpenDatabase(msifile, MSIDBOPEN_READONLY, &hdb); + ok(r == ERROR_SUCCESS, "MsiOpenDatabase failed\n"); + + r = MsiGetSummaryInformation(hdb, NULL, 0, &hsuminfo); + ok(r == ERROR_SUCCESS, "MsiGetSummaryInformation failed\n"); + + /* + * Check what reading MSI_PID_LASTPRINTED does... + * The string value is written to the msi file + * but it appears that we're not allowed to read it back again. + * We can still read its type though...? + */ + sz = sizeof sval; + sval[0] = 0; + type = 0; + r = MsiSummaryInfoGetProperty(hsuminfo, MSI_PID_LASTPRINTED, &type, NULL, NULL, sval, &sz); + ok(r == ERROR_SUCCESS, "MsiSummaryInfoGetProperty failed\n"); + ok(!lstrcmpA(sval, "") || !lstrcmpA(sval, "7"), + "Expected empty string or \"7\", got \"%s\"\n", sval); + todo_wine { + ok(type == VT_LPSTR, "Expected VT_LPSTR, got %d\n", type); + ok(sz == 0 || sz == 1, "Expected 0 or 1, got %d\n", sz); + } + + ival = -1; + r = MsiSummaryInfoGetProperty(hsuminfo, MSI_PID_WORDCOUNT, &type, &ival, NULL, NULL, NULL); + ok(r == ERROR_SUCCESS, "MsiSummaryInfoGetProperty failed\n"); + todo_wine ok( ival == 0, "value incorrect\n"); + + /* looks like msi adds some of its own values in here */ + count = 0; + r = MsiSummaryInfoGetPropertyCount( hsuminfo, &count ); + ok(r == ERROR_SUCCESS, "getpropcount failed\n"); + todo_wine ok(count == 10, "prop count incorrect\n"); + + r = MsiSummaryInfoSetProperty( hsuminfo, MSI_PID_TITLE, VT_LPSTR, 0, NULL, "Mike" ); + ok(r == ERROR_FUNCTION_FAILED, "MsiSummaryInfoSetProperty failed %u\n", r); + + r = MsiSummaryInfoPersist( hsuminfo ); + ok(r == ERROR_FUNCTION_FAILED, "MsiSummaryInfoPersist failed %u\n", r); + + MsiCloseHandle( hsuminfo ); + MsiCloseHandle( hdb ); + + DeleteFile( msifile ); +} + +void main() +{ + test_suminfo(); + test_summary_binary(); +} diff --git a/tests/testsuminfo.ok b/tests/testsuminfo.ok new file mode 100644 index 0000000..19a53ea --- /dev/null +++ b/tests/testsuminfo.ok @@ -0,0 +1,87 @@ +ok: r == ERROR_SUCCESS +ok: r == ERROR_INVALID_PARAMETER +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_INVALID_HANDLE +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: count == 0 +ok: r == ERROR_SUCCESS +ok: r == ERROR_UNKNOWN_PROPERTY +ok: r == ERROR_UNKNOWN_PROPERTY +ok: r == ERROR_SUCCESS +ok: type == 0 +ok: r == ERROR_SUCCESS +ok: type == 0 +ok: val == 1234 +ok: r == ERROR_SUCCESS +ok: buf[0]=='x' +ok: sz == 0x10 +ok: type == VT_EMPTY +ok: r == ERROR_FUNCTION_FAILED +ok: r == ERROR_FUNCTION_FAILED +ok: r == ERROR_FUNCTION_FAILED +ok: r == ERROR_FUNCTION_FAILED +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_DATATYPE_MISMATCH +ok: r == ERROR_DATATYPE_MISMATCH +ok: r == ERROR_DATATYPE_MISMATCH +ok: r == ERROR_DATATYPE_MISMATCH +ok: r == ERROR_DATATYPE_MISMATCH +ok: r == ERROR_DATATYPE_MISMATCH +ok: r == ERROR_DATATYPE_MISMATCH +ok: r == ERROR_INVALID_PARAMETER +ok: r == ERROR_INVALID_PARAMETER +ok: r == ERROR_DATATYPE_MISMATCH +ok: r == ERROR_DATATYPE_MISMATCH +ok: r == ERROR_DATATYPE_MISMATCH +ok: r == ERROR_SUCCESS +ok: r == ERROR_MORE_DATA +ok: sz == 4 +ok: type == VT_LPSTR +ok: !strcmp(buf,"M") +ok: r == ERROR_MORE_DATA +ok: sz == 4 +ok: type == VT_LPSTR +ok: !strcmp(buf,"Mik") +ok: r == ERROR_SUCCESS +ok: r == ERROR_FUNCTION_FAILED +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_DATATYPE_MISMATCH +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_FUNCTION_FAILED +ok: r == ERROR_SUCCESS +ok: r +ok: r == S_OK +ok: r == S_OK +ok: r == S_OK +ok: r == S_OK +ok: r == S_OK +ok: r == S_OK +ok: r == S_OK +ok: r == S_OK +ok: r == S_OK +ok: r == S_OK +ok: INVALID_FILE_ATTRIBUTES != GetFileAttributes(msifile) +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: !lstrcmpA(sval, "") || !lstrcmpA(sval, "7") +ok: r == ERROR_SUCCESS +ok: r == ERROR_SUCCESS +ok: r == ERROR_FUNCTION_FAILED +ok: r == ERROR_FUNCTION_FAILED -- cgit