Esempio n. 1
0
unsigned int odbc_db_version_int(void)
{
	unsigned int h, l;
	if (sscanf(odbc_db_version(), "%u.%u.", &h, &l) != 2) {
		fprintf(stderr, "Wrong db version: %s\n", odbc_db_version());
		odbc_disconnect();
		exit(1);
	}

	return (h << 24) | ((l & 0xFFu) << 16);
}
Esempio n. 2
0
static void
AllTests(void)
{
    struct tm *ltime;
    char buf[80];
    time_t curr_time;

    SQLINTEGER y, m, d;
    char date[128];

    printf("use_cursors %d exec_direct %d prepare_before %d\n", use_cursors, exec_direct, prepare_before);

    /* test some NULLs */
    NullInput(SQL_C_CHAR, SQL_VARCHAR, "VARCHAR(100)");
    NullInput(SQL_C_CHAR, SQL_LONGVARCHAR, "TEXT");
    NullInput(SQL_C_LONG, SQL_INTEGER, "INTEGER");
    NullInput(SQL_C_LONG, SQL_LONGVARCHAR, "TEXT");
    NullInput(SQL_C_TYPE_TIMESTAMP, SQL_TYPE_TIMESTAMP, "DATETIME");
    NullInput(SQL_C_FLOAT,  SQL_REAL, "FLOAT");
    NullInput(SQL_C_NUMERIC, SQL_LONGVARCHAR, "TEXT");
    if (odbc_db_is_microsoft() && odbc_db_version_int() >= 0x08000000u)
        NullInput(SQL_C_BIT, SQL_BIT, "BIT");
    NullInput(SQL_C_DOUBLE, SQL_DOUBLE, "MONEY");

    /* FIXME why should return 38 0 as precision and scale ?? correct ?? */
    precision = 18;
    TestOutput("NUMERIC(18,2)", "123", SQL_C_NUMERIC, SQL_NUMERIC, "18 0 1 7B");
    TestOutput("DECIMAL(18,2)", "123", SQL_C_NUMERIC, SQL_DECIMAL, "18 0 1 7B");
    precision = 38;
    TestOutput("NUMERIC(18,2)", "123", SQL_C_NUMERIC, SQL_NUMERIC, "38 0 1 7B");
    TestInput(SQL_C_LONG, "INTEGER", SQL_VARCHAR, "VARCHAR(20)", "12345");
    TestInput(SQL_C_LONG, "INTEGER", SQL_LONGVARCHAR, "TEXT", "12345");
    /*
     * MS driver behavior for output parameters is different
     * former returns "313233" while newer "333133323333"
     */
    if (odbc_driver_is_freetds())
        TestOutput("VARCHAR(20)", "313233", SQL_C_BINARY, SQL_VARCHAR, "333133323333");

    only_test = 1;
    precision = 3;
    if (TestOutput("DATETIME", "2004-02-24 15:16:17", SQL_C_BINARY, SQL_TIMESTAMP, pack("ssssssl", 2004, 2, 24, 15, 16, 17, 0))) {
        /* FIXME our driver ignore precision for date */
        precision = 3;
        /* Some MS driver incorrectly prepare with smalldatetime*/
        if (!use_cursors || odbc_driver_is_freetds()) {
            TestOutput("DATETIME", "2004-02-24 15:16:17", SQL_C_BINARY, SQL_TIMESTAMP, pack("ll", 0x9497, 0xFBAA2C));
        }
        TestOutput("SMALLDATETIME", "2004-02-24 15:16:17", SQL_C_BINARY, SQL_TIMESTAMP, pack("ll", 0x9497, 0xFB9640));
    } else {
        TestOutput("SMALLDATETIME", "2004-02-24 15:16:17", SQL_C_BINARY, SQL_TIMESTAMP, pack("ssssssl", 2004, 2, 24, 15, 16, 0, 0));
    }
    TestInput(SQL_C_TYPE_TIMESTAMP, "DATETIME", SQL_TYPE_TIMESTAMP, "DATETIME", "2005-07-22 09:51:34");

    /* test timestamp millisecond round off */
    TestInput(SQL_C_TYPE_TIMESTAMP, "DATETIME", SQL_TYPE_TIMESTAMP, "DATETIME", "2005-07-22 09:51:34.001 -> 2005-07-22 09:51:34.000");
    TestInput(SQL_C_TYPE_TIMESTAMP, "DATETIME", SQL_TYPE_TIMESTAMP, "DATETIME", "2005-07-22 09:51:34.002 -> 2005-07-22 09:51:34.003");
    TestInput(SQL_C_TYPE_TIMESTAMP, "DATETIME", SQL_TYPE_TIMESTAMP, "DATETIME", "2005-07-22 09:51:34.003 -> 2005-07-22 09:51:34.003");
    TestInput(SQL_C_TYPE_TIMESTAMP, "DATETIME", SQL_TYPE_TIMESTAMP, "DATETIME", "2005-07-22 09:51:34.004 -> 2005-07-22 09:51:34.003");
    TestInput(SQL_C_TYPE_TIMESTAMP, "DATETIME", SQL_TYPE_TIMESTAMP, "DATETIME", "2005-07-22 09:51:34.005 -> 2005-07-22 09:51:34.007");
    TestInput(SQL_C_TYPE_TIMESTAMP, "DATETIME", SQL_TYPE_TIMESTAMP, "DATETIME", "2005-07-22 09:51:34.006 -> 2005-07-22 09:51:34.007");

    /* FIXME on ms driver first SQLFetch return SUCCESS_WITH_INFO for truncation error */
    TestInput(SQL_C_TYPE_DATE, "DATETIME", SQL_TYPE_TIMESTAMP, "DATETIME", "2005-07-22 13:02:03 -> 2005-07-22 00:00:00");

    /* replace date information with current date */
    time(&curr_time);
    ltime = localtime(&curr_time);
    y = ltime->tm_year + 1900;
    m = ltime->tm_mon + 1;
    d = ltime->tm_mday;
    /* server concept of data can be different so try ask to server */
    odbc_command("SELECT GETDATE()");
    SQLBindCol(odbc_stmt, 1, SQL_C_CHAR, date, sizeof(date), NULL);
    if (SQLFetch(odbc_stmt) == SQL_SUCCESS) {
        int a, b, c;
        if (sscanf(date, "%d-%d-%d", &a, &b, &c) == 3) {
            y = a;
            m = b;
            d = c;
        }
    }
    SQLFetch(odbc_stmt);
    SQLMoreResults(odbc_stmt);
    SQLFreeStmt(odbc_stmt, SQL_UNBIND);
    sprintf(buf, "2003-07-22 13:02:03 -> %04d-%02d-%02d 13:02:03", (int) y, (int) m, (int) d);
    TestInput(SQL_C_TYPE_TIME, "DATETIME", SQL_TYPE_TIMESTAMP, "DATETIME", buf);

    TestInput(SQL_C_FLOAT,  "FLOAT", SQL_REAL, "FLOAT", "1234.25");
    TestInput(SQL_C_DOUBLE, "REAL", SQL_REAL, "FLOAT", "-1234.25");
    TestInput(SQL_C_FLOAT,  "REAL", SQL_REAL, "FLOAT", "1234.25");
    TestInput(SQL_C_DOUBLE, "FLOAT", SQL_REAL, "FLOAT", "-1234.25");
    TestInput(SQL_C_FLOAT,  "FLOAT", SQL_FLOAT, "FLOAT", "1234.25");
    TestInput(SQL_C_DOUBLE, "REAL", SQL_FLOAT, "FLOAT", "-1234.25");
    TestInput(SQL_C_FLOAT,  "FLOAT", SQL_DOUBLE, "FLOAT", "1234.25");
    TestInput(SQL_C_DOUBLE, "REAL", SQL_DOUBLE, "FLOAT", "-1234.25");

    TestInput(SQL_C_UTINYINT, "TINYINT", SQL_TINYINT, "TINYINT", "231");

    TestInput(SQL_C_NUMERIC, "NUMERIC(20,3)", SQL_NUMERIC, "NUMERIC(20,3)", "765432.2 -> 765432");
    TestInput(SQL_C_NUMERIC, "NUMERIC(20,3)", SQL_VARCHAR, "VARCHAR(20)", "578246.234 -> 578246");
    TestInput(SQL_C_NUMERIC, "NUMERIC(20,3)", SQL_LONGVARCHAR, "TEXT", "578246.234 -> 578246");

    TestInput(SQL_C_CHAR, "VARCHAR(100)", SQL_VARBINARY, "VARBINARY(20)", "4145544F -> AETO");
    TestInput(SQL_C_CHAR, "TEXT", SQL_VARBINARY, "VARBINARY(20)", "4145544F -> AETO");
    TestInput(SQL_C_CHAR, "VARCHAR(100)", SQL_LONGVARBINARY, "IMAGE", "4145544F -> AETO");
    TestInput(SQL_C_BINARY, "VARBINARY(100)", SQL_VARCHAR, "VARCHAR(20)", "0x4145544F -> AETO");
    TestInput(SQL_C_BINARY, "IMAGE", SQL_VARCHAR, "VARCHAR(20)", "0x4145544F -> AETO");

    TestInput(SQL_C_BIT, "BIT", SQL_BIT, "BIT", "0");
    TestInput(SQL_C_BIT, "BIT", SQL_BIT, "BIT", "1");

    TestInput(SQL_C_DOUBLE, "MONEY", SQL_DOUBLE, "MONEY", "123.34");

    TestInput(SQL_C_CHAR, "VARCHAR(20)", SQL_VARCHAR, "VARCHAR(20)", "1EasyTest");
    TestInput(SQL_C_CHAR, "VARCHAR(20)", SQL_LONGVARCHAR, "TEXT", "1EasyTest");
    TestInput(SQL_C_WCHAR, "VARCHAR(10)", SQL_VARCHAR, "VARCHAR(10)", "Test 12345");
    TestInput(SQL_C_WCHAR, "VARCHAR(10)", SQL_LONGVARCHAR, "TEXT", "Test 12345");
    /* TODO use collate in syntax if available */
    TestInput(SQL_C_CHAR, "VARCHAR(20)", SQL_VARCHAR, "VARCHAR(20)", "me\xf4");
    TestInput(SQL_C_CHAR, "VARCHAR(20)", SQL_LONGVARCHAR, "TEXT", "me\xf4");

    precision = 6;
    /* output from char with conversions */
    TestOutput("VARCHAR(20)", "foo test", SQL_C_CHAR, SQL_VARCHAR, "6 foo te");
    /* TODO use collate in sintax if available */
    TestOutput("VARCHAR(20)", "0xf8f9", SQL_C_CHAR, SQL_VARCHAR, "2 \xf8\xf9");

    if ((odbc_db_is_microsoft() && odbc_db_version_int() >= 0x08000000u && odbc_tds_version() > 0x700)
            || (!odbc_db_is_microsoft() && strncmp(odbc_db_version(), "15.00.", 6) >= 0)) {
        TestOutput("BIGINT", "-987654321065432", SQL_C_BINARY, SQL_BIGINT, big_endian ? "FFFC7DBBCF083228" : "283208CFBB7DFCFF");
        TestInput(SQL_C_SBIGINT, "BIGINT", SQL_BIGINT, "BIGINT", "-12345678901234");
    }
    if (odbc_db_is_microsoft() && odbc_db_version_int() >= 0x08000000u) {
        TestInput(SQL_C_CHAR, "NVARCHAR(100)", SQL_WCHAR, "NVARCHAR(100)", "test");
        TestInput(SQL_C_CHAR, "NVARCHAR(100)", SQL_WLONGVARCHAR, "NTEXT", "test");
        /* test for invalid stream due to truncation*/
        TestInput(SQL_C_CHAR, "NVARCHAR(100)", SQL_WCHAR, "NVARCHAR(100)", "01234567890");
        TestInput(SQL_C_CHAR, "NVARCHAR(100)", SQL_WLONGVARCHAR, "NTEXT", "01234567890");
#ifdef ENABLE_DEVELOPING
        check_truncation = 1;
        TestInput(SQL_C_CHAR, "NVARCHAR(100)", SQL_WCHAR, "NVARCHAR(100)", "012345678901234567890");
        check_truncation = 1;
        TestInput(SQL_C_CHAR, "NVARCHAR(100)", SQL_WLONGVARCHAR, "NTEXT", "012345678901234567890");
#endif
        TestInput(SQL_C_CHAR, "NVARCHAR(100)", SQL_WCHAR, "NVARCHAR(100)", "\xa3h\xf9 -> 0xA3006800f900");
        TestInput(SQL_C_CHAR, "NVARCHAR(100)", SQL_WLONGVARCHAR, "NTEXT", "\xa3h\xf9 -> 0xA3006800f900");
        TestInput(SQL_C_CHAR, "NVARCHAR(100)", SQL_WCHAR, "NVARCHAR(100)", "0xA3006800f900 -> \xa3h\xf9");
        TestInput(SQL_C_CHAR, "NVARCHAR(100)", SQL_WLONGVARCHAR, "NTEXT", "0xA3006800f900 -> \xa3h\xf9");

        TestInput(SQL_C_LONG, "INT", SQL_WVARCHAR, "NVARCHAR(100)", "45236");
        TestInput(SQL_C_LONG, "INT", SQL_WLONGVARCHAR, "NTEXT", "45236");

        precision = 6;
        TestOutput("NVARCHAR(20)", "foo test", SQL_C_CHAR, SQL_WVARCHAR, "6 foo te");
        precision = 12;
        TestOutput("NVARCHAR(20)", "foo test", SQL_C_CHAR, SQL_WVARCHAR, "8 foo test");
        /* TODO use collate in sintax if available */
        TestOutput("NVARCHAR(20)", "0xf800f900", SQL_C_CHAR, SQL_WVARCHAR, "2 \xf8\xf9");

        TestInput(SQL_C_WCHAR, "NVARCHAR(10)", SQL_WVARCHAR, "NVARCHAR(10)", "1EasyTest2");
        TestInput(SQL_C_WCHAR, "NVARCHAR(10)", SQL_WLONGVARCHAR, "NTEXT", "1EasyTest2");
        use_nts = 1;
        TestInput(SQL_C_WCHAR, "NVARCHAR(10)", SQL_WVARCHAR, "NVARCHAR(10)", "1EasyTest3");
        use_nts = 1;
        TestInput(SQL_C_WCHAR, "NVARCHAR(10)", SQL_WLONGVARCHAR, "NTEXT", "1EasyTest3");
        TestInput(SQL_C_WCHAR, "NVARCHAR(3)", SQL_WVARCHAR, "NVARCHAR(3)", "0xf800a300bc06");
        TestInput(SQL_C_WCHAR, "NVARCHAR(3)", SQL_WLONGVARCHAR, "NTEXT", "0xf800a300bc06");

        TestInput(SQL_C_WCHAR, "NVARCHAR(10)", SQL_INTEGER, "INT", " -423785  -> -423785");

        TestInput(SQL_C_CHAR, "NVARCHAR(100)", SQL_VARBINARY, "VARBINARY(20)", "4145544F -> AETO");
        TestInput(SQL_C_CHAR, "NTEXT", SQL_VARBINARY, "VARBINARY(20)", "4145544F -> AETO");

        TestInput(SQL_C_BINARY, "VARBINARY(100)", SQL_WVARCHAR, "NVARCHAR(20)", "0x4100450054004F00 -> AETO");
        TestInput(SQL_C_BINARY, "IMAGE", SQL_WVARCHAR, "NVARCHAR(20)", "0x4100450054004F00 -> AETO");
    }
    if (odbc_db_is_microsoft() && odbc_db_version_int() >= 0x09000000u) {
        TestInput(SQL_C_CHAR, "VARCHAR(20)", SQL_LONGVARCHAR, "VARCHAR(MAX)", "1EasyTest");
        TestInput(SQL_C_BINARY, "VARBINARY(20)", SQL_LONGVARBINARY, "VARBINARY(MAX)", "Anything will suite!");
    }
}
Esempio n. 3
0
static void
DoTest(int version3)
{
	char name[128], params[128];
	SQLSMALLINT type, is_unsigned;
	SQLINTEGER col_size, min_scale;
	SQLLEN ind1, ind2, ind3, ind4, ind5, ind6;
	int date_time_supported = 0;
	int name_version3;

	odbc_use_version3 = version3;
	name_version3 = version3;
	odbc_connect();

	printf("Using ODBC version %d\n", version3 ? 3 : 2);

	/* test column name */
	/* MS ODBC use always ODBC 3 names even in ODBC 2 mode */
	if (!odbc_driver_is_freetds())
		name_version3 = 1;
	CHKGetTypeInfo(SQL_ALL_TYPES, "SI");
	TestName(1, "TYPE_NAME");
	TestName(2, "DATA_TYPE");
	TestName(3, name_version3 ? "COLUMN_SIZE" : "PRECISION");
	TestName(4, "LITERAL_PREFIX");
	TestName(5, "LITERAL_SUFFIX");
	TestName(6, "CREATE_PARAMS");
	TestName(7, "NULLABLE");
	TestName(8, "CASE_SENSITIVE");
	TestName(9, "SEARCHABLE");
	TestName(10, "UNSIGNED_ATTRIBUTE");
	TestName(11, name_version3 ? "FIXED_PREC_SCALE" : "MONEY");
	TestName(12, name_version3 ? "AUTO_UNIQUE_VALUE" : "AUTO_INCREMENT");
	TestName(13, "LOCAL_TYPE_NAME");
	TestName(14, "MINIMUM_SCALE");
	TestName(15, "MAXIMUM_SCALE");

	/* TODO test these column for ODBC 3 */
	/* ODBC 3.0 SQL_DATA_TYPE SQL_DATETIME_SUB NUM_PREC_RADIX INTERVAL_PRECISION */

	Flushodbc_stmt();

	/* TODO test if SQL_ALL_TYPES returns right numeric type for timestamp */

	/* numeric type for data */

	/* test for date/time support */
	if (odbc_command_with_result(odbc_stmt, "select cast(getdate() as date)") == SQL_SUCCESS)
		date_time_supported = 1;
	SQLCloseCursor(odbc_stmt);

#define CHECK_TYPE(in,out) CheckType(in, out, #in, __LINE__)

	/* under Sybase this type require extra handling, check it */
	CHECK_TYPE(SQL_VARCHAR, SQL_VARCHAR);

	CHECK_TYPE(SQL_DATE, date_time_supported && !version3 ? SQL_DATE : SQL_UNKNOWN_TYPE);
	CHECK_TYPE(SQL_TIME, date_time_supported && !version3 ? SQL_TIME : SQL_UNKNOWN_TYPE);
	/* MS ODBC returns S1004 (HY004), TODO support it */
	if (odbc_driver_is_freetds() || version3) {
		CHECK_TYPE(SQL_TYPE_DATE, date_time_supported && version3 ? SQL_TYPE_DATE : SQL_UNKNOWN_TYPE);
		CHECK_TYPE(SQL_TYPE_TIME, date_time_supported && version3 ? SQL_TYPE_TIME : SQL_UNKNOWN_TYPE);
	}
	/* TODO MS ODBC handle SQL_TIMESTAMP even for ODBC 3 */
	if (odbc_driver_is_freetds())
		CHECK_TYPE(SQL_TIMESTAMP, version3 ? SQL_UNKNOWN_TYPE : SQL_TIMESTAMP);
	else
		CHECK_TYPE(SQL_TIMESTAMP, version3 ? SQL_TYPE_TIMESTAMP : SQL_TIMESTAMP);
	/* MS ODBC returns S1004 (HY004), TODO support it */
	if (odbc_driver_is_freetds() || version3) {
		CHECK_TYPE(SQL_TYPE_TIMESTAMP, version3 ? SQL_TYPE_TIMESTAMP : SQL_UNKNOWN_TYPE);
	}

	/* TODO implement this part of test */
	/* varchar/nvarchar before sysname */

	/* test binding (not all column, required for Oracle) */
	CHKGetTypeInfo(SQL_ALL_TYPES, "SI");
	CHKBindCol(1, SQL_C_CHAR, name, sizeof(name), &ind1, "SI");
	CHKBindCol(2, SQL_C_SSHORT, &type, 0, &ind2, "SI");
	CHKBindCol(3, SQL_C_SLONG, &col_size, 0, &ind3, "SI");
	CHKBindCol(6, SQL_C_CHAR, params, sizeof(params), &ind4, "SI");
	CHKBindCol(10, SQL_C_SSHORT, &is_unsigned, 0, &ind5, "SI");
	CHKBindCol(14, SQL_C_SSHORT, &min_scale, 0, &ind6, "SI");
	while (CHKFetch("SNo") == SQL_SUCCESS)
		;
	SQLFreeStmt(odbc_stmt, SQL_UNBIND);
	Flushodbc_stmt();

	/* check WVARCHAR for no pending data */
	if (odbc_db_is_microsoft() || strncmp(odbc_db_version(), "15.00.", 6) >= 0) {
		CHKGetTypeInfo(SQL_WVARCHAR, "SI");
		CHKFetch("S");
		if (odbc_db_is_microsoft())
			CHKFetch("S");
		CHKFetch("No");
		CHKGetTypeInfo(SQL_BINARY, "SI");
	}

	odbc_disconnect();
}
Esempio n. 4
0
int
main(int argc, char *argv[])
{
	int big_endian = 1;
	int test_2008_date_to_binary = 0;

	odbc_connect();

	if (((char *) &big_endian)[0] == 1)
		big_endian = 0;

	Test("NUMERIC(18,2)", "123", SQL_C_NUMERIC, "38 0 1 7B");

	/* all binary results */
	/* cases (2) */
	Test("CHAR(7)", "pippo", SQL_C_BINARY, "706970706F2020");
	Test("TEXT", "mickey", SQL_C_BINARY, "6D69636B6579");
	Test("VARCHAR(20)", "foo", SQL_C_BINARY, "666F6F");

	Test("BINARY(5)", "qwer", SQL_C_BINARY, "7177657200");
	Test("IMAGE", "cricetone", SQL_C_BINARY, "6372696365746F6E65");
	Test("VARBINARY(20)", "teo", SQL_C_BINARY, "74656F");
	/* TODO only MS ?? */
	if (odbc_db_is_microsoft())
		Test("TIMESTAMP", "abcdefghi", SQL_C_BINARY, "6162636465666768");

	Test("DATETIME", "2004-02-24 15:16:17", SQL_C_BINARY, big_endian ? "0000949700FBAA2C" : "979400002CAAFB00");
	Test("SMALLDATETIME", "2004-02-24 15:16:17", SQL_C_BINARY, big_endian ? "94970394" : "97949403");

	Test("BIT", "1", SQL_C_BINARY, "01");
	Test("BIT", "0", SQL_C_BINARY, "00");
	Test("TINYINT", "231", SQL_C_BINARY, "E7");
	Test("SMALLINT", "4321", SQL_C_BINARY, big_endian ? "10E1" : "E110");
	Test("INT", "1234567", SQL_C_BINARY, big_endian ? "0012D687" : "87D61200");
	if ((odbc_db_is_microsoft() && odbc_db_version_int() >= 0x08000000u)
	    || (!odbc_db_is_microsoft() && strncmp(odbc_db_version(), "15.00.", 6) >= 0)) {
		int old_result = result;

		Test("BIGINT", "123456789012345", SQL_C_BINARY, big_endian ? "00007048860DDF79" : "79DF0D8648700000");
		if (result && strcmp(sbuf, "13000179DF0D86487000000000000000000000") == 0) {
			fprintf(stderr, "Ignore previous error. You should configure TDS 7.1 for this!!!\n");
			if (!old_result)
				result = 0;
		}
	}

	Test("INT", "-123", SQL_C_CHAR, "4 -123");
	Test("INT", "78654", SQL_C_WCHAR, "5 78654");
	Test("VARCHAR(10)", "  51245  ", SQL_C_LONG, "51245");
	Test("VARCHAR(20)", "  15.1245  ", SQL_C_NUMERIC, "38 0 1 0F");
	Test("VARCHAR(20)", "  15  ", SQL_C_NUMERIC, "38 0 1 0F");
	if (odbc_db_is_microsoft() && (strncmp(odbc_db_version(), "08.00.", 6) == 0 || strncmp(odbc_db_version(), "09.00.", 6) == 0)) {
		/* nvarchar without extended characters */
		Test("NVARCHAR(20)", "test", SQL_C_CHAR, "4 test");
		/* nvarchar with extended characters */
		/* don't test with MS which usually have a not compatible encoding */
		if (odbc_driver_is_freetds())
			Test("NVARCHAR(20)", "0x830068006900f200", SQL_C_CHAR, "4 \x83hi\xf2");

		Test("VARCHAR(20)", "test", SQL_C_WCHAR, "4 test");
		/* nvarchar with extended characters */
		Test("NVARCHAR(20)", "0x830068006900f200", SQL_C_WCHAR, "4 \x83hi\xf2");
		Test("NVARCHAR(20)", "0xA406A5FB", SQL_C_WCHAR, "2 \\u06a4\\ufba5");
		/* NVARCHAR -> SQL_C_LONG */
		Test("NVARCHAR(20)", "-24785  ", SQL_C_LONG, "-24785");
	}

	ignore_select_error = 1;
	Test("UNIVARCHAR(10)", "u&'\\06A4\\FBA5'", SQL_C_WCHAR, "2 \\u06a4\\ufba5");

	/* case (1) */
	Test("DECIMAL", "1234.5678", SQL_C_BINARY, "120001D3040000000000000000000000000000");
	Test("NUMERIC", "8765.4321", SQL_C_BINARY, "1200013D220000000000000000000000000000");

	Test("FLOAT", "1234.5678", SQL_C_BINARY, big_endian ? "40934A456D5CFAAD" : "ADFA5C6D454A9340");
	Test("REAL", "8765.4321", SQL_C_BINARY, big_endian ? "4608F5BA" : "BAF50846");

	Test("SMALLMONEY", "765.4321", SQL_C_BINARY, big_endian ? "0074CBB1" : "B1CB7400");
	Test("MONEY", "4321234.5678", SQL_C_BINARY, big_endian ? "0000000A0FA8114E" : "0A0000004E11A80F");

	/* behavior is different from MS ODBC */
	if (odbc_db_is_microsoft()) {
		Test("NCHAR(7)", "donald", SQL_C_BINARY, "64006F006E0061006C0064002000");
		Test("NTEXT", "duck", SQL_C_BINARY, "6400750063006B00");
		Test("NVARCHAR(20)", "daffy", SQL_C_BINARY, "64006100660066007900");
	}

	if (odbc_db_is_microsoft())
		Test("UNIQUEIDENTIFIER", "0DDF3B64-E692-11D1-AB06-00AA00BDD685", SQL_C_BINARY,
		     big_endian ? "0DDF3B64E69211D1AB0600AA00BDD685" : "643BDF0D92E6D111AB0600AA00BDD685");

	/* case (4) */
	Test("DATETIME", "2006-06-09 11:22:44", SQL_C_CHAR, "23 2006-06-09 11:22:44.000");
	Test("SMALLDATETIME", "2006-06-12 22:37:21", SQL_C_CHAR, "19 2006-06-12 22:37:00");
	Test("DATETIME", "2006-06-09 11:22:44", SQL_C_WCHAR, "23 2006-06-09 11:22:44.000");
	Test("SMALLDATETIME", "2006-06-12 22:37:21", SQL_C_WCHAR, "19 2006-06-12 22:37:00");

	if (odbc_db_is_microsoft() && odbc_db_version_int() >= 0x08000000u) {
		Test("SQL_VARIANT", "CAST('123' AS INT)", SQL_C_CHAR, "3 123");
		Test("SQL_VARIANT", "CAST('hello' AS CHAR(6))", SQL_C_CHAR, "6 hello ");
		Test("SQL_VARIANT", "CAST('ciao' AS VARCHAR(10))", SQL_C_CHAR, "4 ciao");
		Test("SQL_VARIANT", "CAST('foo' AS NVARCHAR(10))", SQL_C_CHAR, "3 foo");
		Test("SQL_VARIANT", "CAST('Super' AS NCHAR(8))", SQL_C_CHAR, "8 Super   ");
		Test("SQL_VARIANT", "CAST('321' AS VARBINARY(10))", SQL_C_CHAR, "6 333231");
		/* for some reasons MS ODBC seems to convert -123.4 to -123.40000000000001 */
		Test("SQL_VARIANT", "CAST('-123.5' AS FLOAT)", SQL_C_CHAR, "6 -123.5");
		Test("SQL_VARIANT", "CAST('-123.4' AS NUMERIC(10,2))", SQL_C_CHAR, "7 -123.40");
		Test("SQL_VARIANT", "CAST('0DDF3B64-E692-11D1-AB06-00AA00BDD685' AS UNIQUEIDENTIFIER)", SQL_C_CHAR, "36 0DDF3B64-E692-11D1-AB06-00AA00BDD685");
	}

	if (odbc_db_is_microsoft() && odbc_db_version_int() >= 0x09000000u) {
		Test("VARCHAR(MAX)", "goodbye!", SQL_C_CHAR, "8 goodbye!");
		Test("NVARCHAR(MAX)", "Micio mao", SQL_C_CHAR, "9 Micio mao");
		Test("VARBINARY(MAX)", "ciao", SQL_C_BINARY, "6369616F");
		Test("XML", "<a b=\"aaa\"><b>ciao</b>hi</a>", SQL_C_CHAR, "28 <a b=\"aaa\"><b>ciao</b>hi</a>");

		/* XML with schema */
		odbc_command("IF EXISTS(SELECT * FROM sys.xml_schema_collections WHERE [name] = 'test_schema') DROP XML SCHEMA COLLECTION test_schema");
		odbc_command("CREATE XML SCHEMA COLLECTION test_schema AS '<schema xmlns=\"http://www.w3.org/2001/XMLSchema\"><element name=\"test\" type=\"string\"/></schema>'");
		Test("XML(test_schema)", "<test>ciao</test>", SQL_C_CHAR, "17 <test>ciao</test>");
		odbc_command("DROP XML SCHEMA COLLECTION test_schema");
	}

	/* MSSQL 2008*/
	if (odbc_db_is_microsoft() && odbc_db_version_int() >= 0x0A000000u) {
		int save_result = result;

		/* check right protocol */
		result = 0;
		test_2008_date_to_binary = 1;
		Test("DATE", "1923-12-02", SQL_C_BINARY, big_endian ? "0783000C0002" : "83070C000200");
		if (result) {
			result = 0;
			Test("DATE", "1923-12-02", SQL_C_BINARY, "31003900320033002D00310032002D0030003200");
			if (!result) {
				printf("previous error expected: wrong protocol used\n");
				test_2008_date_to_binary = 0;
			}
		}
		if (save_result)
			result = 1;

		Test("DATE", "1923-12-02", SQL_C_CHAR, "10 1923-12-02");

		Test("TIME", "12:23:45", SQL_C_CHAR, "16 12:23:45.0000000");
		Test("TIME(4)", "12:23:45.765", SQL_C_CHAR, "13 12:23:45.7650");
		Test("TIME(0)", "12:23:45.765", SQL_C_CHAR, "8 12:23:46");

		Test("DATETIME2", "2011-08-10 12:23:45", SQL_C_CHAR, "27 2011-08-10 12:23:45.0000000");
		Test("DATETIME2(4)", "12:23:45.345888", SQL_C_CHAR, "24 1900-01-01 12:23:45.3459");
		Test("DATETIME2(0)", "2011-08-10 12:23:45.93", SQL_C_CHAR, "19 2011-08-10 12:23:46");

		Test("DATETIMEOFFSET", "12:23:45 -02:30", SQL_C_CHAR, "34 1900-01-01 12:23:45.0000000 -02:30");
		Test("DATETIMEOFFSET(4)", "12:23:45", SQL_C_CHAR, "31 1900-01-01 12:23:45.0000 +00:00");
	}

	if (test_2008_date_to_binary) {
		Test("DATE", "1923-12-02", SQL_C_BINARY, big_endian ? "0783000C0002" : "83070C000200");
		Test("TIME", "12:23:45", SQL_C_BINARY, big_endian ? "000C0017002D000000000000" : "0C0017002D00000000000000");
		Test("TIME(4)", "12:23:45.765", SQL_C_BINARY, big_endian ? "000C0017002D00002D98F940" : "0C0017002D00000040F9982D");
		Test("DATETIME2", "2011-08-10 12:23:45", SQL_C_BINARY, big_endian ? "07DB0008000A000C0017002D00000000" : "DB0708000A000C0017002D0000000000");
		Test("DATETIME2(4)", "12:23:45", SQL_C_BINARY, big_endian ? "076C00010001000C0017002D00000000" : "6C07010001000C0017002D0000000000");
		Test("DATETIMEOFFSET", "12:23:45 -08:30", SQL_C_BINARY, big_endian ? "076C00010001000C0017002D00000000FFF8FFE2" : "6C07010001000C0017002D0000000000F8FFE2FF");
		Test("DATETIMEOFFSET(4)", "12:23:45", SQL_C_BINARY, big_endian ? "076C00010001000C0017002D0000000000000000" : "6C07010001000C0017002D000000000000000000");
	}

	if (!odbc_db_is_microsoft() && strncmp(odbc_db_version(), "15.00.", 6) >= 0) {
		/* FIXME sure ?? with date and time always ?? */
		Test("DATE", "1923-12-02", SQL_C_CHAR, "23 1923-12-02 00:00:00.000");
		Test("TIME", "12:23:45", SQL_C_CHAR, "23 1900-01-01 12:23:45.000");
	}

	odbc_disconnect();

	if (!result)
		printf("Done successfully!\n");
	return result;
}