Ejemplo n.º 1
0
static void
insert_test_man(void)
{
	SQLLEN sql_nts = SQL_NTS;
	SQLINTEGER commit_off = SQL_AUTOCOMMIT_OFF;
	SQLINTEGER commit_on = SQL_AUTOCOMMIT_ON;
	SQLINTEGER id = 0;

	char string[64];

	CHKSetConnectAttr(SQL_ATTR_AUTOCOMMIT, int2ptr(commit_off), SQL_IS_INTEGER, "SI");

	odbc_reset_statement();

	CHKBindParameter(1, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, sizeof(id), 0, &id, 0, &sql_nts, "SI");
	CHKBindParameter(2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, sizeof(string), 0, string, 0, &sql_nts, "SI");

	CHKPrepare(T("insert into test values (?, ?)"), SQL_NTS, "SI");
	for (id = 0; id < 20; id++) {
		sprintf(string, "This is a test (%d)", (int) id);
		CHKExecute("SI");
	}

	SQLEndTran(SQL_HANDLE_DBC, odbc_conn, SQL_COMMIT);
	SQLSetConnectAttr(odbc_conn, SQL_ATTR_AUTOCOMMIT, int2ptr(commit_on), SQL_IS_INTEGER);
	odbc_reset_statement();
}
Ejemplo n.º 2
0
/* stripped down version of TestInput for NULLs */
static void
NullInput(SQLSMALLINT out_c_type, SQLSMALLINT out_sql_type, const char *param_type)
{
    char sbuf[1024];
    SQLLEN out_len = SQL_NULL_DATA;

    odbc_reset_statement();

    /* create a table with a column of that type */
    odbc_reset_statement();
    sprintf(sbuf, "CREATE TABLE #tmp_insert (col %s NULL)", param_type);
    odbc_command(sbuf);

    if (use_cursors) {
        odbc_reset_statement();
        CHKSetStmtAttr(SQL_ATTR_CURSOR_SCROLLABLE, (SQLPOINTER) SQL_SCROLLABLE, 0, "S");
        CHKSetStmtAttr(SQL_ATTR_CURSOR_TYPE, (SQLPOINTER) SQL_CURSOR_DYNAMIC, 0, "S");
    }

    /* insert data using prepared statements */
    sprintf(sbuf, "INSERT INTO #tmp_insert VALUES(?)");
    if (exec_direct) {
        CHKBindParameter(1, SQL_PARAM_INPUT, out_c_type, out_sql_type, 20, 0, NULL, 1, &out_len, "S");

        CHKExecDirect(T(sbuf), SQL_NTS, "SNo");
    } else {
        if (prepare_before)
            CHKPrepare(T(sbuf), SQL_NTS, "S");

        CHKBindParameter(1, SQL_PARAM_INPUT, out_c_type, out_sql_type, 20, 0, NULL, 1, &out_len, "S");

        if (!prepare_before)
            CHKPrepare(T(sbuf), SQL_NTS, "S");

        CHKExecute("SNo");
    }

    /* check if row is present */
    odbc_reset_statement();
    if (!odbc_db_is_microsoft() && strcmp(param_type, "TEXT") == 0)
        odbc_command("SELECT * FROM #tmp_insert WHERE col LIKE ''");
    else
        odbc_command("SELECT * FROM #tmp_insert WHERE col IS NULL");

    CHKFetch("S");
    CHKFetch("No");
    CHKMoreResults("No");
    odbc_command("DROP TABLE #tmp_insert");
    ODBC_FREE();
}
Ejemplo n.º 3
0
int
main(int argc, char *argv[])
{
	SQLLEN cb = SQL_NTS;

	odbc_use_version3 = 1;

	odbc_connect();

	odbc_command_with_result(odbc_stmt, "drop proc sp_paramcore_test");
	odbc_command("create proc sp_paramcore_test @s varchar(100) output as select @s = '12345'");

	/* here we pass a NULL buffer for input SQL_NTS */
	CHKBindParameter(1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, OUTSTRING_LEN, 0, NULL, OUTSTRING_LEN, &cb, "S");

	cb = SQL_NTS;
	CHKExecDirect(T(SP_TEXT), SQL_NTS, "E");
	odbc_reset_statement();

	/* here we pass a NULL buffer for input */
	CHKBindParameter(1, SQL_PARAM_INPUT, SQL_C_LONG, SQL_VARCHAR, 18, 0, NULL, OUTSTRING_LEN, &cb, "S");

	cb = 1;
	CHKExecDirect(T(SP_TEXT), SQL_NTS, "E");
	odbc_reset_statement();

	odbc_command("drop proc sp_paramcore_test");
	odbc_command("create proc sp_paramcore_test @s numeric(10,2) output as select @s = 12345.6");
	odbc_reset_statement();

#if 0	/* this fails even on native platforms */
	/* here we pass a NULL buffer for output */
	cb = sizeof(SQL_NUMERIC_STRUCT);
	SQLBindParameter(odbc_stmt, 1, SQL_PARAM_OUTPUT, SQL_C_NUMERIC, SQL_NUMERIC, 18, 0, NULL, OUTSTRING_LEN, &cb);
	odbc_read_error();

	cb = 1;
	odbc_command_with_result(odbc_stmt, SP_TEXT);
	odbc_read_error();
	odbc_reset_statement();
#endif

	odbc_command("drop proc sp_paramcore_test");

	odbc_disconnect();

	printf("Done successfully!\n");
	return 0;
}
Ejemplo n.º 4
0
int
main(int argc, char *argv[])
{
    odbc_use_version3 = 1;
    odbc_connect();

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

    for (use_cursors = 0; use_cursors <= 1; ++use_cursors) {
        if (use_cursors) {
            if (!tds_no_dm || !odbc_driver_is_freetds())
                odbc_reset_statement();
            odbc_check_cursor();
        }

        exec_direct = 1;
        AllTests();

        exec_direct = 0;
        prepare_before = 1;
        AllTests();

        prepare_before = 0;
        AllTests();
    }

    odbc_disconnect();

    printf("Done successfully!\n");
    return 0;
}
Ejemplo n.º 5
0
static void
Test(const char *query)
{
    CHKPrepare(T(query), SQL_NTS, "S");

    CHKExecute("S");

    CHKFetch("SI");

    CHKFetch("No");

    /*
     * Microsoft SQL Server 2000 provides a diagnostic record
     * associated with the second SQLFetch (which returns
     * SQL_NO_DATA) saying "Warning: Null value is eliminated by
     * an aggregate or other SET operation."
     * We check for "NO DM" cause unixODBC till 2.2.11 do not read
     * errors on SQL_NO_DATA
     */
    if (odbc_db_is_microsoft() && tds_no_dm) {
        SQLTCHAR output[256];

        CHKGetDiagRec(SQL_HANDLE_STMT, odbc_stmt, 1, NULL, NULL, output, ODBC_VECTOR_SIZE(output), NULL, "SI");
        printf("Message: %s\n", C(output));
    }

    odbc_reset_statement();
}
Ejemplo n.º 6
0
int
main(int argc, char **argv)
{
	if (tds_mutex_init(&mtx))
		return 1;

	if (odbc_read_login_info())
		exit(1);

	/*
	 * prepare our odbcinst.ini
	 * is better to do it before connect cause uniODBC cache INIs
	 * the name must be odbcinst.ini cause unixODBC accept only this name
	 */
	if (odbc_driver[0]) {
		FILE *f = fopen("odbcinst.ini", "w");

		if (f) {
			fprintf(f, "[FreeTDS]\nDriver = %s\nThreading = 0\n", odbc_driver);
			fclose(f);
			/* force iODBC */
			setenv("ODBCINSTINI", "./odbcinst.ini", 1);
			setenv("SYSODBCINSTINI", "./odbcinst.ini", 1);
			/* force unixODBC (only directory) */
			setenv("ODBCSYSINI", ".", 1);
		}
	}

	odbc_use_version3 = 1;
	odbc_connect();

	odbc_command("IF OBJECT_ID('tab1') IS NOT NULL DROP TABLE tab1");
	odbc_command("CREATE TABLE tab1 ( k INT, vc VARCHAR(200) )");

	printf(">> Creating tab1...\n");
	odbc_command("DECLARE @i INT\n"
		"SET @i = 1\n"
		"WHILE @i <= 2000 BEGIN\n"
		"INSERT INTO tab1 VALUES ( @i, 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' )\n"
		"SET @i = @i + 1\n"
		"END");
	while (CHKMoreResults("SNo") == SQL_SUCCESS)
		continue;
	printf(">> ...done.\n");

	odbc_reset_statement();

	Test(0, 0);
	Test(1, 0);
	Test(0, 1);
	Test(1, 1);

	odbc_command("DROP TABLE tab1");

	odbc_disconnect();
	return 0;
}
Ejemplo n.º 7
0
static void
test_params(void)
{
#define ARRAY_SIZE 2
	const rows_set_t *p;
	SQLULEN len;
	SQLUINTEGER *ids = MALLOC_N(SQLUINTEGER,ARRAY_SIZE);
	SQLLEN *id_lens = MALLOC_N(SQLLEN,ARRAY_SIZE);
	unsigned long int h, l;
	unsigned int n;

	for (n = 0; n < ARRAY_SIZE; ++n) {
		ids[n] = n;
		id_lens[n] = 0;
	}

	/* test setting just some test pointers */
	set_ipd_params1(int2ptr(0x01020304));
	check_ipd_params();
	set_ipd_params2(int2ptr(0xabcdef12));
	check_ipd_params();
	set_ipd_params3(int2ptr(0x87654321));
	check_ipd_params();

	/* now see results */
	for (p = param_set; *p != NULL; ++p) {
		odbc_reset_statement();
		len = 0xdeadbeef;
		len <<= 16;
		len <<= 16;
		len |= 12345678;

		(*p)(&len);
		check_ipd_params();

		CHKSetStmtAttr(SQL_ATTR_PARAMSET_SIZE, (void *) int2ptr(ARRAY_SIZE), 0, "S");
		CHKBindParameter(1, SQL_PARAM_INPUT, SQL_C_ULONG, SQL_INTEGER, 5, 0, ids, 0, id_lens, "S");

		odbc_command("INSERT INTO #tmp1(i) VALUES(?)");
		SQLMoreResults(odbc_stmt);
		for (n = 0; n < ARRAY_SIZE; ++n)
			SQLMoreResults(odbc_stmt);
		l = len;
		len >>= 16;
		h = len >> 16;
		l &= 0xfffffffflu;
		if (h != 0 || l != 2) {
			fprintf(stderr, "Wrong number returned in param rows high %lu low %lu\n", h, l);
			exit(1);
		}
	}

	free(ids);
	free(id_lens);
}
Ejemplo n.º 8
0
static void
insert_test_auto(void)
{
	SQLLEN sql_nts = SQL_NTS;
	SQLINTEGER id = 0;
	char string[64];

	odbc_reset_statement();

	CHKBindParameter(1, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, sizeof(id), 0, &id, 0, &sql_nts, "SI");
	CHKBindParameter(2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, sizeof(string), 0, string, 0, &sql_nts, "SI");

	CHKPrepare(T("insert into test values (?, ?)"), SQL_NTS, "SI");
	for (id = 0; id < 20; id++) {
		sprintf(string, "This is a test (%d)", (int) id);
		CHKExecute("SI");
	}

	odbc_reset_statement();
}
Ejemplo n.º 9
0
int
main(int argc, char **argv)
{
#define ARRAY_SIZE 10
	SQLCHAR v_dec[ARRAY_SIZE][21];
	SQLLEN v_ind[ARRAY_SIZE];
	SQLULEN nrows;

	odbc_use_version3 = 1;
	odbc_connect();
	odbc_check_cursor();

	odbc_command("IF OBJECT_ID('mytab1') IS NOT NULL DROP TABLE mytab1");
	odbc_command("CREATE TABLE mytab1 ( k INT, d DECIMAL(10,2))");
	odbc_command("INSERT INTO mytab1 VALUES ( 201, 111.11 )");
	/*SQLExecDirect(m_hstmt, (SQLCHAR *) "insert into mytab1 values ( 202, 222.22 )", SQL_NTS); */
	odbc_command("INSERT INTO mytab1 VALUES ( 202, null )");

	odbc_reset_statement();

	CHKSetStmtAttr(SQL_ATTR_CURSOR_SCROLLABLE, (SQLPOINTER) SQL_NONSCROLLABLE, SQL_IS_UINTEGER, "S");
	CHKSetStmtAttr(SQL_ATTR_CURSOR_SENSITIVITY, (SQLPOINTER) SQL_SENSITIVE, SQL_IS_UINTEGER, "S");

	CHKSetStmtAttr(SQL_ATTR_ROW_BIND_TYPE, (SQLPOINTER) SQL_BIND_BY_COLUMN, SQL_IS_UINTEGER, "S");
	CHKSetStmtAttr(SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER) ARRAY_SIZE, SQL_IS_UINTEGER, "S");
	CHKSetStmtAttr(SQL_ATTR_ROWS_FETCHED_PTR, (SQLPOINTER) & (nrows), SQL_IS_UINTEGER, "S");

	CHKPrepare(T("SELECT SUM(d) FROM mytab1"), SQL_NTS, "S");

	CHKExecute("I");

#if 0
	CHKMoreResults("S");	/* skip warning*/
#endif

	CHKBindCol(1, SQL_C_CHAR, v_dec, 21, v_ind, "S");

	CHKFetch("S");

	printf("fetch 1: rows fetched = %d\n", (int) nrows);
	printf("fetch 1: value = [%s]\n", v_dec[0]);

	CHKFetch("No");

	CHKMoreResults("No");

	odbc_command("drop table mytab1");

	odbc_disconnect();

	return 0;
}
Ejemplo n.º 10
0
int
main(int argc, char **argv)
{
	char buff[64];
	SQLLEN ind;

	odbc_use_version3 = 1;
	odbc_connect();

	odbc_check_cursor();

	exec_direct("CREATE TABLE #t1 ( k INT, c VARCHAR(20))");
	exec_direct("INSERT INTO #t1 VALUES (1, 'aaa')");

	odbc_reset_statement();

	CHKSetStmtAttr(SQL_ATTR_CONCURRENCY, (SQLPOINTER) SQL_CONCUR_LOCK, SQL_IS_UINTEGER, "S");

	CHKSetCursorName(T("c112"), SQL_NTS, "S");

	CHKSetConnectAttr(SQL_ATTR_AUTOCOMMIT, int2ptr(SQL_AUTOCOMMIT_OFF), 0, "S");

	CHKPrepare(T("SELECT * FROM #t1 FOR UPDATE"), SQL_NTS, "S");

	CHKExecute("S");

	CHKFetch("S");

	exec_direct("UPDATE #t1 SET c = 'xxx' WHERE CURRENT OF c112");

	CHKCloseCursor("SI");

	CHKEndTran(SQL_HANDLE_DBC, odbc_conn, SQL_COMMIT, "S");

	CHKSetConnectAttr(SQL_ATTR_AUTOCOMMIT, int2ptr(SQL_AUTOCOMMIT_ON), 0, "S");

	CHKExecDirect(T("SELECT c FROM #t1 WHERE k = 1"), SQL_NTS, "S");

	CHKFetch("S");

	CHKGetData(1, SQL_C_CHAR, buff, sizeof(buff), &ind, "S");

	printf(">> New value after update = [%s] (should be [xxx]) \n", buff);

	CHKFreeHandle(SQL_HANDLE_STMT, (SQLHANDLE) odbc_stmt, "S");
	odbc_stmt = SQL_NULL_HSTMT;

	odbc_disconnect();

	return 0;
}
Ejemplo n.º 11
0
static void
test_with_conversions(void)
{
	SQLLEN ind, ind2, ind3;
	char out2[30];

	/*
	 * test from Bower, Wayne
	 * Cfr ML 2012-03-02 "[freetds] [unixODBC][Driver Manager]Function sequence error (SQL-HY010)"
	 */
	odbc_use_version3 = 1;
	odbc_connect();

	odbc_command("IF OBJECT_ID('TMP_SP_Test_ODBC') IS NOT NULL DROP PROC TMP_SP_Test_ODBC");
	odbc_command("create proc TMP_SP_Test_ODBC @i int,\n@o int output\nas\nset nocount on\nselect @o = 55\nreturn 9\n");
	odbc_reset_statement();

	CHKPrepare(T("{ ? = call TMP_SP_Test_ODBC (?, ?) }"), SQL_NTS, "S");

	ind2 = 2;
	CHKBindParameter(2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, 80, 0, "10", 2, &ind2, "S");
	ind3 = SQL_NULL_DATA;
	strcpy(out2, " ");
	CHKBindParameter(3, SQL_PARAM_INPUT_OUTPUT, SQL_C_CHAR, SQL_VARCHAR, 0, 1, out2, 29, &ind3, "S");
	ind = 1;
	CHKBindParameter(1, SQL_PARAM_INPUT_OUTPUT, SQL_C_CHAR, SQL_VARCHAR, 0, 1, out2, 29, &ind, "S");

	/* mssql returns SUCCESS */
	CHKExecute("No");

	ODBC_CHECK_COLS(0);

	odbc_reset_statement();
	odbc_command("drop proc TMP_SP_Test_ODBC");


	odbc_disconnect();
}
Ejemplo n.º 12
0
static void
Test(int use_threads, int return_data)
{
	tds_thread wait_thread;

#if !HAVE_ALARM
	if (!use_threads) return;
#endif

	printf("testing with %s\n", use_threads ? "threads" : "signals");
	printf(">> Wait 5 minutes...\n");
	if (!use_threads) {
		alarm(4);
		signal(SIGALRM, sigalrm_handler);
	} else {
		int err;

		exit_thread = 0;
		err = tds_thread_create(&wait_thread, wait_thread_proc, NULL);
		if (err != 0) {
			perror("tds_thread_create");
			exit(1);
		}
	}
	if (!return_data)
		CHKExecDirect(T("WAITFOR DELAY '000:05:00'"), SQL_NTS, "E");
	else
		odbc_command2("SELECT MAX(p1.k) FROM tab1 p1, tab1 p2, tab1 p3, tab1 p4", "E");

	tds_mutex_lock(&mtx);
	exit_thread = 1;
	tds_mutex_unlock(&mtx);
	if (!use_threads) {
		alarm(0);
	} else {
		tds_thread_join(wait_thread, NULL);
	}
	getErrorInfo(SQL_HANDLE_STMT, odbc_stmt);
	if (strcmp(C(sqlstate), "HY008") != 0) {
		fprintf(stderr, "Unexpected sql state returned\n");
		odbc_disconnect();
		exit(1);
	}

	odbc_reset_statement();

	odbc_command("SELECT name FROM sysobjects WHERE 0=1");
}
Ejemplo n.º 13
0
int
main(int argc, char *argv[])
{
    int i;

    odbc_use_version3 = 1;
    odbc_connect();

    odbc_command("CREATE TABLE #odbc_test(i INT, t TEXT)");
    for (i = 0; i < 10; ++i) {
        char buf[128];

        sprintf(buf, "INSERT INTO #odbc_test(i, t) VALUES(%d, '%crow number %d')", i + 1, 'a' + i, i * 13);
        odbc_command(buf);
    }

    odbc_reset_statement();

    test_query = "SELECT * FROM #odbc_test ORDER BY i";
    printf("test line %d\n", __LINE__);
    query_test("S", "VVVVVVVVVV");

    test_query = "SELECT * FROM #odbc_test WHERE i < 7 ORDER BY i";
    printf("test line %d\n", __LINE__);
    query_test("S", "VVVVVV");

    /* binding row */
    test_query = "SELECT * FROM #odbc_test ORDER BY i";
    record_bind = 1;
    printf("test line %d\n", __LINE__);
    query_test("S", "VVVVVVVVVV");

    /* row and truncation */
    trunc = 1;
    printf("test line %d\n", __LINE__);
    query_test("I", "!!!!!!!!!!");

    /* TODO bind offset, SQLGetData, no bind, error */

    odbc_disconnect();

    printf("Success!.\n");
    return 0;
}
Ejemplo n.º 14
0
static void
Test(const char *type, const char *value_to_convert, SQLSMALLINT out_c_type, const char *expected)
{
	char sbuf[1024];
	unsigned char out_buf[256];
	SQLLEN out_len = 0;

	SQLFreeStmt(odbc_stmt, SQL_UNBIND);
	SQLFreeStmt(odbc_stmt, SQL_RESET_PARAMS);

	/* execute a select to get data as wire */
	sprintf(sbuf, "SELECT CONVERT(%s, '%s') AS data", type, value_to_convert);
	if (strncmp(value_to_convert, "0x", 2) == 0)
		sprintf(sbuf, "SELECT CONVERT(%s, %s) COLLATE Latin1_General_CI_AS AS data", type, value_to_convert);
	else if (strcmp(type, "SQL_VARIANT") == 0)
		sprintf(sbuf, "SELECT CONVERT(SQL_VARIANT, %s) AS data", value_to_convert);
	else if (strncmp(value_to_convert, "u&'", 3) == 0)
		sprintf(sbuf, "SELECT CONVERT(%s, %s) AS data", type, value_to_convert);
	if (ignore_select_error) {
		if (odbc_command2(sbuf, "SENo") == SQL_ERROR) {
			odbc_reset_statement();
			ignore_select_error = 0;
			ignore_result = 0;
			return;
		}
	} else {
		odbc_command(sbuf);
	}
	SQLBindCol(odbc_stmt, 1, out_c_type, out_buf, sizeof(out_buf), &out_len);
	CHKFetch("S");
	CHKFetch("No");
	CHKMoreResults("No");

	/* test results */
	odbc_c2string(sbuf, out_c_type, out_buf, out_len);

	if (!ignore_result && strcmp(sbuf, expected) != 0) {
		fprintf(stderr, "Wrong result\n  Got:      %s\n  Expected: %s\n", sbuf, expected);
		result = 1;
	}
	ignore_select_error = 0;
	ignore_result = 0;
}
Ejemplo n.º 15
0
static void
TestBinding(int minimun)
{
	const char * const*p;
	SQLINTEGER n;
	SQLLEN n_len;

	sprintf(tmp, "DELETE FROM %s", table_name);
	odbc_command(tmp);

	/* insert with SQLPrepare/SQLBindParameter/SQLExecute */
	sprintf(tmp, "INSERT INTO %s VALUES(?,?,?)", table_name);
	CHKPrepare(T(tmp), SQL_NTS, "S");
	CHKBindParameter(1, SQL_PARAM_INPUT, SQL_C_LONG,
		SQL_INTEGER, 0, 0, &n, 0, &n_len, "S");
	n_len = sizeof(n);
	
	for (n = 1, p = strings; p[0] && p[1]; p += 2, ++n) {
		SQLLEN s1_len, s2_len;
		unsigned int len;

		len = minimun ? (strlen(strings_hex[p-strings]) - 2) /4 : 40;
		CHKBindParameter(2, SQL_PARAM_INPUT, SQL_C_CHAR,
			SQL_WCHAR, len, 0, (void *) p[0], 0, &s1_len, "S");
		len = minimun ? (strlen(strings_hex[p+1-strings]) - 2) /4 : 40;
		/* FIXME this with SQL_VARCHAR produce wrong protocol data */
		CHKBindParameter(3, SQL_PARAM_INPUT, SQL_C_CHAR,
			SQL_WVARCHAR, len, 0, (void *) p[1], 0, &s2_len, "S");
		s1_len = strlen(p[0]);
		s2_len = strlen(p[1]);
		printf("insert #%d\n", (int) n);
		CHKExecute("S");
	}

	/* check rows */
	for (n = 1, p = strings_hex; p[0] && p[1]; p += 2, ++n) {
		sprintf(tmp, "IF NOT EXISTS(SELECT * FROM %s WHERE k = %d AND c = %s AND vc = %s) SELECT 1", table_name, (int) n, p[0], p[1]);
		CheckNoRow(tmp);
	}

	odbc_reset_statement();
}
Ejemplo n.º 16
0
void
odbc_check_cursor(void)
{
    SQLRETURN retcode;

    retcode = SQLSetStmtAttr(odbc_stmt, SQL_ATTR_CONCURRENCY, (SQLPOINTER) SQL_CONCUR_ROWVER, 0);
    if (retcode != SQL_SUCCESS) {
        char output[256];
        unsigned char sqlstate[6];

        CHKGetDiagRec(SQL_HANDLE_STMT, odbc_stmt, 1, sqlstate, NULL, (SQLCHAR *) output, sizeof(output), NULL, "S");
        sqlstate[5] = 0;
        if (strcmp((const char*) sqlstate, "01S02") == 0) {
            printf("Your connection seems to not support cursors, probably you are using wrong protocol version or Sybase\n");
            odbc_disconnect();
            exit(0);
        }
        ReportODBCError("SQLSetStmtAttr", SQL_HANDLE_STMT, odbc_stmt, retcode, __LINE__, __FILE__);
    }
    odbc_reset_statement();
}
Ejemplo n.º 17
0
static void
test_err(const char *data, int c_type, const char *state)
{
	char sql[128];
	SQLLEN ind;
	const unsigned int buf_size = 128;
	char *buf = (char *) malloc(buf_size);

	sprintf(sql, "SELECT '%s'", data);
	odbc_command(sql);
	SQLFetch(odbc_stmt);
	CHKGetData(1, c_type, buf, buf_size, &ind, "E");
	free(buf);
	odbc_read_error();
	if (strcmp(odbc_sqlstate, state) != 0) {
		fprintf(stderr, "Unexpected sql state returned\n");
		odbc_disconnect();
		exit(1);
	}
	odbc_reset_statement();
}
Ejemplo n.º 18
0
void
odbc_check_cursor(void)
{
	SQLRETURN retcode;
	ODBC_BUF *odbc_buf = NULL;

	retcode = SQLSetStmtAttr(odbc_stmt, SQL_ATTR_CONCURRENCY, (SQLPOINTER) SQL_CONCUR_ROWVER, 0);
	if (retcode != SQL_SUCCESS) {
		SQLTCHAR output[256];
		SQLTCHAR sqlstate[6];

		CHKGetDiagRec(SQL_HANDLE_STMT, odbc_stmt, 1, sqlstate, NULL, output, ODBC_VECTOR_SIZE(output), NULL, "S");
		sqlstate[5] = 0;
		if (strcmp(C(sqlstate), "01S02") == 0) {
			printf("Your connection seems to not support cursors, probably you are using wrong protocol version or Sybase\n");
			odbc_disconnect();
			ODBC_FREE();
			exit(0);
		}
		ReportODBCError("SQLSetStmtAttr", SQL_HANDLE_STMT, odbc_stmt, retcode, __LINE__, __FILE__);
	}
	odbc_reset_statement();
	ODBC_FREE();
}
Ejemplo n.º 19
0
static void
test_rows(void)
{
	const rows_set_t *p;
	SQLULEN len;
	SQLUINTEGER *ids = MALLOC_N(SQLUINTEGER,ARRAY_SIZE);
	SQLLEN *id_lens = MALLOC_N(SQLLEN,ARRAY_SIZE);
	unsigned long int h, l;
	unsigned int n;

	for (n = 0; n < ARRAY_SIZE; ++n) {
		ids[n] = n;
		id_lens[n] = 0;
	}

	/* test setting just some test pointers */
	set_ird_params1(int2ptr(0x01020304));
	check_ird_params();
	set_ird_params2(int2ptr(0xabcdef12));
	check_ird_params();

	/* now see results */
	for (p = row_set; ; ++p) {
		const char *test_name = NULL;

		odbc_reset_statement();
		len = 0xdeadbeef;
		len <<= 16;
		len <<= 16;
		len |= 12345678;
		if (*p)
			(*p)(&len);
		check_ird_params();

#if 0
		CHKSetStmtAttr(SQL_ATTR_PARAMSET_SIZE, (void *) int2ptr(ARRAY_SIZE), 0, "S");
		CHKBindParameter(1, SQL_PARAM_INPUT, SQL_C_ULONG, SQL_INTEGER, 5, 0, ids, 0, id_lens, "S");
#endif

		CHKBindCol(1, SQL_C_ULONG, ids, 0, id_lens, "S");
		if (*p) {
			CHKSetStmtAttr(SQL_ATTR_ROW_ARRAY_SIZE, (void *) int2ptr(ARRAY_SIZE), 0, "S");

			odbc_command("SELECT DISTINCT i FROM #tmp1");
			SQLFetch(odbc_stmt);
			test_name = "SQLSetStmtAttr";
		} else {
			CHKSetStmtAttr(SQL_ROWSET_SIZE, (void *) int2ptr(ARRAY_SIZE), 0, "S");
			odbc_command("SELECT DISTINCT i FROM #tmp1");
			CHKExtendedFetch(SQL_FETCH_NEXT, 0, &len, NULL, "S");
			test_name = "SQLExtendedFetch";
		}
		SQLMoreResults(odbc_stmt);

		l = len;
		len >>= 16;
		h = len >> 16;
		l &= 0xfffffffflu;
		if (h != 0 || l != 2) {
			fprintf(stderr, "Wrong number returned in rows high %lu(0x%lx) low %lu(0x%lx) test %s\n", h, h, l, l, test_name);
			exit(1);
		}

		if (!*p)
			break;
	}

	free(ids);
	free(id_lens);
}
Ejemplo n.º 20
0
static void
test_split(const char *n_flag)
{
#define CheckLen(x) do { \
	if (len != (x)) { \
		fprintf(stderr, "Wrong len %ld at line %d expected %d\n", (long int) len, __LINE__, (x)); \
		exit(1); \
	} \
	} while(0)

	char sql[80];
	char *buf = NULL;
	SQLLEN len;

	/* TODO test with VARCHAR too */
	sprintf(sql, "SELECT CONVERT(%sTEXT,'Prova' + REPLICATE('x',500))", n_flag);
	odbc_command(sql);

	CHKFetch("S");

	/* these 2 tests test an old severe BUG in FreeTDS */
	buf = ODBC_GET(1);
	CHKGetData(1, type, buf, 0, &len, "I");
	if (len != SQL_NO_TOTAL)
		CheckLen(505*lc);
	CHKGetData(1, type, buf, 0, &len, "I");
	if (len != SQL_NO_TOTAL)
		CheckLen(505*lc);
	buf = ODBC_GET(3*lc);
	CHKGetData(1, type, buf, 3 * lc, &len, "I");
	if (len != SQL_NO_TOTAL)
		CheckLen(505*lc);
	if (mycmp(buf, "Pr") != 0) {
		printf("Wrong data result 1\n");
		exit(1);
	}

	buf = ODBC_GET(16*lc);
	CHKGetData(1, type, buf, 16 * lc, &len, "I");
	if (len != SQL_NO_TOTAL)
		CheckLen(503*lc);
	if (mycmp(buf, "ovaxxxxxxxxxxxx") != 0) {
		printf("Wrong data result 2 res = '%s'\n", buf);
		exit(1);
	}

	buf = ODBC_GET(256*lc);
	CHKGetData(1, type, buf, 256 * lc, &len, "I");
	if (len != SQL_NO_TOTAL)
		CheckLen(488*lc);
	CHKGetData(1, type, buf, 256 * lc, &len, "S");
	CheckLen(233*lc);
	CHKGetData(1, type, buf, 256 * lc, &len, "No");

	odbc_reset_statement();

	/* test with varchar, not blob but variable */
	sprintf(sql, "SELECT CONVERT(%sVARCHAR(100), 'Other test')", n_flag);
	odbc_command(sql);

	CHKFetch("S");

	buf = ODBC_GET(7*lc);
	CHKGetData(1, type, buf, 7 * lc, NULL, "I");
	if (mycmp(buf, "Other ") != 0) {
		printf("Wrong data result 1\n");
		exit(1);
	}

	buf = ODBC_GET(5*lc);
	CHKGetData(1, type, buf, 20, NULL, "S");
	if (mycmp(buf, "test") != 0) {
		printf("Wrong data result 2 res = '%s'\n", buf);
		exit(1);
	}
	ODBC_FREE();

	odbc_reset_statement();
}
Ejemplo n.º 21
0
int
main(int argc, char *argv[])
{
	char buf[32];
	SQLINTEGER int_buf;
	SQLLEN len;
	SQLRETURN rc;

	odbc_connect();

	lc = 1;
	type = SQL_C_CHAR;
	test_split("");

	lc = sizeof(SQLWCHAR);
	type = SQL_C_WCHAR;
	test_split("");

	if (odbc_db_is_microsoft() && odbc_db_version_int() >= 0x07000000u) {
		lc = 1;
		type = SQL_C_CHAR;
		test_split("N");

		lc = sizeof(SQLWCHAR);
		type = SQL_C_WCHAR;
		test_split("N");
	}

	/* test with fixed length */
	odbc_command("SELECT CONVERT(INT, 12345)");

	CHKFetch("S");

	int_buf = 0xdeadbeef;
	CHKGetData(1, SQL_C_SLONG, &int_buf, 0, NULL, "S");
	if (int_buf != 12345) {
		printf("Wrong data result\n");
		exit(1);
	}

	CHKGetData(1, SQL_C_SLONG, &int_buf, 0, NULL, "No");
	if (int_buf != 12345) {
		printf("Wrong data result 2 res = %d\n", (int) int_buf);
		exit(1);
	}

	odbc_reset_statement();

	/* test with numeric */
	odbc_command("SELECT CONVERT(NUMERIC(18,5), 1850000000000)");

	CHKFetch("S");

	memset(buf, 'x', sizeof(buf));
	CHKGetData(1, SQL_C_CHAR, buf, 14, NULL, "S");
	buf[sizeof(buf)-1] = 0;
	if (strcmp(buf, "1850000000000") != 0) {
		printf("Wrong data result: %s\n", buf);
		exit(1);
	}

	/* should give NO DATA */
	CHKGetData(1, SQL_C_CHAR, buf, 14, NULL, "No");
	buf[sizeof(buf)-1] = 0;
	if (strcmp(buf, "1850000000000") != 0) {
		printf("Wrong data result 3 res = %s\n", buf);
		exit(1);
	}

	odbc_reset_statement();


	/* test int to truncated string */
	odbc_command("SELECT CONVERT(INTEGER, 12345)");
	CHKFetch("S");

	/* error 22003 */
	memset(buf, 'x', sizeof(buf));
	CHKGetData(1, SQL_C_CHAR, buf, 4, NULL, "E");
#ifdef ENABLE_DEVELOPING
	buf[4] = 0;
	if (strcmp(buf, "xxxx") != 0) {
		fprintf(stderr, "Wrong buffer result buf = %s\n", buf);
		exit(1);
	}
#endif
	odbc_read_error();
	if (strcmp(odbc_sqlstate, "22003") != 0) {
		fprintf(stderr, "Unexpected sql state %s returned\n", odbc_sqlstate);
		odbc_disconnect();
		exit(1);
	}
	CHKGetData(1, SQL_C_CHAR, buf, 2, NULL, "No");
	odbc_reset_statement();

	/* test unique identifier to truncated string */
	rc = odbc_command2("SELECT CONVERT(UNIQUEIDENTIFIER, 'AA7DF450-F119-11CD-8465-00AA00425D90')", "SENo");
	if (rc != SQL_ERROR) {
		CHKFetch("S");

		/* error 22003 */
		CHKGetData(1, SQL_C_CHAR, buf, 17, NULL, "E");
		odbc_read_error();
		if (strcmp(odbc_sqlstate, "22003") != 0) {
			fprintf(stderr, "Unexpected sql state %s returned\n", odbc_sqlstate);
			odbc_disconnect();
			exit(1);
		}
		CHKGetData(1, SQL_C_CHAR, buf, 2, NULL, "No");
	}
	odbc_reset_statement();


	odbc_disconnect();

	odbc_use_version3 = 1;
	odbc_connect();

	/* test error from SQLGetData */
	/* wrong constant, SQL_VARCHAR is invalid as C type */
	test_err("prova 123",           SQL_VARCHAR,     "HY003");
	/* use ARD but no ARD data column */
	test_err("prova 123",           SQL_ARD_TYPE,    "07009");
	/* wrong conversion, int */
	test_err("prova 123",           SQL_C_LONG,      "22018");
	/* wrong conversion, date */
	test_err("prova 123",           SQL_C_TIMESTAMP, "22018");
	/* overflow */
	test_err("1234567890123456789", SQL_C_LONG,      "22003");

	/* test for empty string from mssql */
	if (odbc_db_is_microsoft()) {
		lc = 1;
		type = SQL_C_CHAR;

		for (;;) {
			void *buf = ODBC_GET(lc);

			odbc_command("SELECT CONVERT(TEXT,'')");

			CHKFetch("S");

			len = 1234;
			CHKGetData(1, type, buf, lc, &len, "S");

			if (len != 0) {
				fprintf(stderr, "Wrong len returned, returned %ld\n", (long) len);
				return 1;
			}

			CHKGetData(1, type, buf, lc, NULL, "No");
			odbc_reset_statement();
			ODBC_FREE();

			buf = ODBC_GET(4096*lc);

			odbc_command("SELECT CONVERT(TEXT,'')");

			CHKFetch("S");

			len = 1234;
			CHKGetData(1, type, buf, lc*4096, &len, "S");

			if (len != 0) {
				fprintf(stderr, "Wrong len returned, returned %ld\n", (long) len);
				return 1;
			}

			CHKGetData(1, type, buf, lc*4096, NULL, "No");
			odbc_reset_statement();
			ODBC_FREE();

			if (type != SQL_C_CHAR)
				break;
			lc = sizeof(SQLWCHAR);
			type = SQL_C_WCHAR;
		}	

		odbc_command("SELECT CONVERT(TEXT,'')");

		CHKFetch("S");

		len = 1234;
		CHKGetData(1, SQL_C_BINARY, buf, 1, &len, "S");

		if (len != 0) {
			fprintf(stderr, "Wrong len returned, returned %ld\n", (long) len);
			return 1;
		}

		CHKGetData(1, SQL_C_BINARY, buf, 1, NULL, "No");
	}

	odbc_disconnect();

	printf("Done.\n");
	return 0;
}
Ejemplo n.º 22
0
int
main(int argc, char *argv[])
{
	int i;
	SQLLEN len;
#ifdef HAVE_SQLROWSETSIZE
	SQLROWSETSIZE row_count;
#else
	SQLULEN row_count;
#endif
	SQLUSMALLINT statuses[10];
	char buf[32];

	odbc_use_version3 = 1;
	odbc_connect();

	/* initial value should be 1 */
	CHKGetStmtAttr(SQL_ROWSET_SIZE, &len, sizeof(len), NULL, "S");
	if (len != 1) {
		fprintf(stderr, "len should be 1\n");
		odbc_disconnect();
		return 1;
	}

	/* check invalid parameter values */
	test_err(-123);
	test_err(-1);
	test_err(0);

	odbc_check_cursor();

	/* set some correct values */
	CHKSetStmtAttr(SQL_ROWSET_SIZE, (SQLPOINTER) int2ptr(2), 0, "S");
	CHKSetStmtAttr(SQL_ROWSET_SIZE, (SQLPOINTER) int2ptr(1), 0, "S");

	/* now check that SQLExtendedFetch works as expected */
	odbc_command("CREATE TABLE #rowset(n INTEGER, c VARCHAR(20))");
	for (i = 0; i < 10; ++i) {
		char s[10];
		char sql[128];

		memset(s, 'a' + i, 9);
		s[9] = 0;
		sprintf(sql, "INSERT INTO #rowset(n,c) VALUES(%d,'%s')", i+1, s);
		odbc_command(sql);
	}

	odbc_reset_statement();
	CHKSetStmtOption(SQL_ATTR_CURSOR_TYPE, SQL_CURSOR_DYNAMIC, "S");
	CHKExecDirect((SQLCHAR *) "SELECT * FROM #rowset ORDER BY n", SQL_NTS, "SI");

	CHKBindCol(2, SQL_C_CHAR, buf, sizeof(buf), &len, "S");

	row_count = 0xdeadbeef;
	memset(statuses, 0x55, sizeof(statuses));
	CHKExtendedFetch(SQL_FETCH_NEXT, 1, &row_count, statuses, "S");

	if (row_count != 1 || statuses[0] != SQL_ROW_SUCCESS || strcmp(buf, "aaaaaaaaa") != 0) {
		fprintf(stderr, "Invalid result\n");
		odbc_disconnect();
		return 1;
	}

	odbc_disconnect();

	printf("Done.\n");
	return 0;
}
Ejemplo n.º 23
0
int
main(int argc, char *argv[])
{
	SQLLEN ind;
	int len = strlen(test_text), n, i;
	const char *p;
	char *pp;
	SQLPOINTER ptr;
	unsigned char buf[256], *pb;
	SQLRETURN RetCode;
	int type, lc, sql_type;

	odbc_connect();

	/* create table to hold data */
	odbc_command("CREATE TABLE #putdata (c TEXT NULL, b IMAGE NULL)");

	sql_type = SQL_LONGVARCHAR;
	type = SQL_C_CHAR;
	lc = 1;
	for (;;) {
		CHKBindParameter(1, SQL_PARAM_INPUT, type, sql_type, 0, 0, (SQLPOINTER) 123, 0, &ind, "S");
		/* length required */
		ind = SQL_LEN_DATA_AT_EXEC(len * lc);

		/* 
		 * test for char 
		 */

		CHKPrepare(T("INSERT INTO #putdata(c) VALUES(?)"), SQL_NTS, "S");

		CHKExecute("Ne");

		p = test_text;
		n = 5;
		CHKParamData(&ptr, "Ne");
		if (ptr != (SQLPOINTER) 123)
			ODBC_REPORT_ERROR("Wrong pointer from SQLParamData");
		while (*p) {
			int l = strlen(p);

			if (l < n)
				n = l;
			if (type == SQL_C_CHAR) {
				CHKPutData((char *) p, n, "S");
			} else {
				SQLWCHAR buf[256];
				CHKPutData((char *) buf, to_sqlwchar(buf, p, n), "S");
			}
			p += n;
			n *= 2;
		}
		CHKParamData(&ptr, "S");

		CHKParamData(&ptr, "E");

		/* check state  and reset some possible buffers */
		odbc_command("DECLARE @i INT");

		/* use server ntext if available */
		if (sql_type == SQL_LONGVARCHAR && odbc_db_is_microsoft() && odbc_db_version_int() >= 0x08000000u) {
			sql_type = SQL_WLONGVARCHAR;
			continue;
		}

		if (type != SQL_C_CHAR)
			break;
		sql_type = SQL_LONGVARCHAR;
		type = SQL_C_WCHAR;
		lc = sizeof(SQLWCHAR);
	}

	/* update row setting binary field */
	for (i = 0; i < 255; ++i)
		buf[i] = BYTE_AT(i);

	/* 
	 * test for binary 
	 */

	CHKBindParameter(1, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, 0, 0, (SQLPOINTER) 4567, 0, &ind, "S");
	ind = SQL_LEN_DATA_AT_EXEC(254);

	CHKPrepare(T("UPDATE #putdata SET b = ?"), SQL_NTS, "S");

	CHKExecute("Ne");

	pb = buf;
	n = 7;
	CHKParamData(&ptr, "Ne");
	if (ptr != (SQLPOINTER) 4567)
		ODBC_REPORT_ERROR("Wrong pointer from SQLParamData");
	while (pb != (buf + 254)) {
		int l = buf + 254 - pb;

		if (l < n)
			n = l;
		CHKPutData((char *) pb, n, "S");
		pb += n;
		n *= 2;
	}
	CHKParamData(&ptr, "S");

	CHKParamData(&ptr, "E");

	/* check state  and reset some possible buffers */
	odbc_command("DECLARE @i2 INT");


	CHKFreeStmt(SQL_RESET_PARAMS, "S");

	/* check inserts ... there should be all equal rows */
	strcpy(sql, "IF EXISTS(SELECT * FROM #putdata WHERE CONVERT(VARBINARY(255),b) <> 0x");
	/* append binary */
	for (i = 0; i < 254; ++i)
		sprintf(strchr(sql, 0), "%02x", buf[i]);
	strcat(sql, " OR CONVERT(VARCHAR(255),c) <> '");
	/* append string */
	pp = strchr(sql, 0);
	p = test_text;
	do {
		*pp++ = *p;
		if (*p == '\'')
			*pp++ = *p;
	} while(*p++);
	strcat(sql, "') SELECT 1");
	odbc_check_no_row(sql);

	odbc_command("DELETE FROM #putdata");

	/* test len == 0 case from ML */
	type = SQL_C_CHAR;
	for (;;) {
		CHKPrepare(T("INSERT INTO #putdata(c) VALUES(?)"), SQL_NTS, "S");

		CHKBindParameter(1, SQL_PARAM_INPUT, type, SQL_LONGVARCHAR, 0, 0, (PTR) 2, 0, &ind, "S");

		ind = SQL_LEN_DATA_AT_EXEC(0);

		RetCode = CHKExecute("Ne");
		while (RetCode == SQL_NEED_DATA) {
			RetCode = SQLParamData(odbc_stmt, &ptr);
			if (RetCode == SQL_NEED_DATA) {
				if (type == SQL_C_CHAR) {
					CHKPutData("abc", 3, "S");
				} else {
					SQLWCHAR buf[10];
					CHKPutData(buf, to_sqlwchar(buf, "abc", 3), "S");
				}
			}
		}
		if (type != SQL_C_CHAR)
			break;
		type = SQL_C_WCHAR;
		odbc_reset_statement();
	}

	/* check inserts ... */
	odbc_check_no_row("IF EXISTS(SELECT * FROM #putdata WHERE c NOT LIKE 'abc') SELECT 1");

	odbc_command("DELETE FROM #putdata");

	/* test putting 0 bytes from Sebastien Flaesch */
	if (odbc_db_is_microsoft()) {
		type = SQL_C_CHAR;
		for (;;) {
			CHKPrepare(T("INSERT INTO #putdata(c) VALUES(?)"), SQL_NTS, "S");

			CHKBindParameter(1, SQL_PARAM_INPUT, type, SQL_LONGVARCHAR, 10, 0, (PTR) 2, 10, &ind, "S");

			ind = SQL_DATA_AT_EXEC;

			RetCode = CHKExecute("Ne");
			while (RetCode == SQL_NEED_DATA) {
				RetCode = SQLParamData(odbc_stmt, &ptr);
				if (RetCode == SQL_NEED_DATA)
					CHKPutData("", 0, "S");
			}
			if (type != SQL_C_CHAR)
				break;
			type = SQL_C_WCHAR;
			odbc_reset_statement();
		}

		/* check inserts ... */
		odbc_check_no_row("IF EXISTS(SELECT * FROM #putdata WHERE c NOT LIKE '') SELECT 1");
	}

	/* TODO test cancel inside SQLExecute */

	odbc_disconnect();

	printf("Done.\n");
	return 0;
}
Ejemplo n.º 24
0
int
main(int argc, char *argv[])
{
#define TEST_FILE "describecol.in"
    const char *in_file = FREETDS_SRCDIR "/" TEST_FILE;
    FILE *f;
    char buf[256];
    SQLINTEGER i;
    SQLLEN len;
    check_attr_t check_attr_p = check_attr_none;

    odbc_connect();
    odbc_command("SET TEXTSIZE 4096");

    SQLBindCol(odbc_stmt, 1, SQL_C_SLONG, &i, sizeof(i), &len);

    f = fopen(in_file, "r");
    if (!f)
        fopen(TEST_FILE, "r");
    if (!f) {
        fprintf(stderr, "error opening test file\n");
        exit(1);
    }

    line_num = 0;
    while (fgets(buf, sizeof(buf), f)) {
        char *p = buf, *cmd;

        ++line_num;

        while (isspace((unsigned char) *p))
            ++p;
        cmd = strtok(p, SEP);

        /* skip comments */
        if (!cmd || cmd[0] == '#' || cmd[0] == 0 || cmd[0] == '\n')
            continue;

        if (strcmp(cmd, "odbc") == 0) {
            int odbc3 = get_int(strtok(NULL, SEP)) == 3 ? 1 : 0;

            if (odbc_use_version3 != odbc3) {
                odbc_use_version3 = odbc3;
                odbc_disconnect();
                odbc_connect();
                odbc_command("SET TEXTSIZE 4096");
                SQLBindCol(odbc_stmt, 1, SQL_C_SLONG, &i, sizeof(i), &len);
            }
        }

        /* select type */
        if (strcmp(cmd, "select") == 0) {
            const char *type = strtok(NULL, SEP);
            const char *value = strtok(NULL, SEP);
            char sql[sizeof(buf) + 40];

            SQLMoreResults(odbc_stmt);
            odbc_reset_statement();

            sprintf(sql, "SELECT CONVERT(%s, %s) AS col", type, value);

            /* ignore error, we only need precision of known types */
            check_attr_p = check_attr_none;
            if (odbc_command_with_result(odbc_stmt, sql) != SQL_SUCCESS) {
                odbc_reset_statement();
                SQLBindCol(odbc_stmt, 1, SQL_C_SLONG, &i, sizeof(i), &len);
                continue;
            }

            CHKFetch("SI");
            SQLBindCol(odbc_stmt, 1, SQL_C_SLONG, &i, sizeof(i), &len);
            check_attr_p = check_attr_ird;
        }

        /* set attribute */
        if (strcmp(cmd, "set") == 0) {
            const struct attribute *attr = lookup_attr(strtok(NULL, SEP));
            char *value = strtok(NULL, SEP);
            SQLHDESC desc;
            SQLRETURN ret;
            SQLINTEGER ind;

            if (!value)
                fatal("Line %u: value not defined\n", line_num);

            /* get ARD */
            SQLGetStmtAttr(odbc_stmt, SQL_ATTR_APP_ROW_DESC, &desc, sizeof(desc), &ind);

            ret = SQL_ERROR;
            switch (attr->type) {
            case type_INTEGER:
                ret = SQLSetDescField(desc, 1, attr->value, int2ptr(lookup(value, attr->lookup)),
                                      sizeof(SQLINTEGER));
                break;
            case type_SMALLINT:
                ret = SQLSetDescField(desc, 1, attr->value, int2ptr(lookup(value, attr->lookup)),
                                      sizeof(SQLSMALLINT));
                break;
            case type_LEN:
                ret = SQLSetDescField(desc, 1, attr->value, int2ptr(lookup(value, attr->lookup)),
                                      sizeof(SQLLEN));
                break;
            case type_CHARP:
                ret = SQLSetDescField(desc, 1, attr->value, (SQLPOINTER) value, SQL_NTS);
                break;
            }
            if (!SQL_SUCCEEDED(ret))
                fatal("Line %u: failure not expected setting ARD attribute\n", line_num);
            check_attr_p = check_attr_ard;
        }

        /* test attribute */
        if (strcmp(cmd, "attr") == 0) {
            const struct attribute *attr = lookup_attr(strtok(NULL, SEP));
            char *expected = strtok(NULL, SEP);

            if (!expected)
                fatal("Line %u: value not defined\n", line_num);

            check_attr_p(attr, expected);
        }
    }

    fclose(f);
    odbc_disconnect();

    printf("Done.\n");
    return g_result;
}
Ejemplo n.º 25
0
static void
Test0(int use_sql, const char *create_sql, const char *insert_sql, const char *select_sql)
{
#define ROWS 4
#define C_LEN 10

	SQLUINTEGER n[ROWS];
	char c[ROWS][C_LEN];
	SQLLEN c_len[ROWS], n_len[ROWS];

	SQLUSMALLINT statuses[ROWS];
	SQLUSMALLINT i;
	SQLULEN num_row;
	SQLHSTMT stmt2;

	/* create test table */
	odbc_command("IF OBJECT_ID('tempdb..#test') IS NOT NULL DROP TABLE #test");
	odbc_command(create_sql);
	for (i = 1; i <= 6; ++i) {
		char sql_buf[80], data[10];
		memset(data, 'a' + (i - 1), sizeof(data));
		data[i] = 0;
		sprintf(sql_buf, insert_sql, data, i);
		odbc_command(sql_buf);
	}

	/* set cursor options */
	odbc_reset_statement();
	CHKSetStmtAttr(SQL_ATTR_CONCURRENCY, (SQLPOINTER) SQL_CONCUR_ROWVER, 0, "S");
	CHKSetStmtAttr(SQL_ATTR_CURSOR_TYPE, (SQLPOINTER) SQL_CURSOR_DYNAMIC, 0, "S");
	CHKSetStmtAttr(SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER) ROWS, 0, "S");
	CHKSetStmtAttr(SQL_ATTR_ROW_STATUS_PTR, (SQLPOINTER) statuses, 0, "S");
	CHKSetStmtAttr(SQL_ATTR_ROWS_FETCHED_PTR, &num_row, 0, "S");
	CHKSetCursorName(T("C1"), SQL_NTS, "S");

	/* */
	CHKExecDirect(T(select_sql), SQL_NTS, "S");

	/* bind some rows at a time */
	CHKBindCol(1, SQL_C_ULONG, n, 0, n_len, "S");
	CHKBindCol(2, SQL_C_CHAR, c, C_LEN, c_len, "S");

	/* allocate an additional statement */
	CHKAllocStmt(&stmt2, "S");

	while (CHKFetchScroll(SQL_FETCH_NEXT, 0, "SNo") == SQL_SUCCESS) {
		/* print, just for debug */
		for (i = 0; i < num_row; ++i)
			printf("row %d i %d c %s\n", (int) (i + 1), (int) n[i], c[i]);
		printf("---\n");

		/* delete a row */
		i = 1;
		if (i > 0 && i <= num_row) {
			if (mssql2005)
				CHKSetPos(i, use_sql ? SQL_POSITION : SQL_DELETE, SQL_LOCK_NO_CHANGE, "SI");
			else
				CHKSetPos(i, use_sql ? SQL_POSITION : SQL_DELETE, SQL_LOCK_NO_CHANGE, "S");
			if (use_sql) {
				SWAP_STMT(stmt2);
				CHKPrepare(T("DELETE FROM #test WHERE CURRENT OF C1"), SQL_NTS, "S");
				CHKExecute("S");
				SWAP_STMT(stmt2);
			}
		}

		/* update another row */
		i = 2;
		if (i > 0 && i <= num_row) {
			strcpy(c[i - 1], "foo");
			c_len[i - 1] = 3;
			if (strstr(select_sql, "#a") == NULL || use_sql) {
				CHKSetPos(i, use_sql ? SQL_POSITION : SQL_UPDATE, SQL_LOCK_NO_CHANGE, "S");
			} else {
				SQLTCHAR sqlstate[6];
				SQLTCHAR msg[256];

				n[i - 1] = 321;
				CHKSetPos(i, use_sql ? SQL_POSITION : SQL_UPDATE, SQL_LOCK_NO_CHANGE, "E");

				CHKGetDiagRec(SQL_HANDLE_STMT, odbc_stmt, 1, sqlstate, NULL, msg, ODBC_VECTOR_SIZE(msg), NULL, "S");
				if (strstr(C(msg), "Invalid column name 'c'") == NULL) {
					fprintf(stderr, "Expected message not found at line %d\n", __LINE__);
					exit(1);
				}
			}
			if (use_sql) {
				SWAP_STMT(stmt2);
				CHKPrepare(T("UPDATE #test SET c=? WHERE CURRENT OF C1"), SQL_NTS, "S");
				CHKBindParameter(1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, C_LEN, 0, c[i - 1], 0, NULL, "S");
				CHKExecute("S");
				/* FIXME this is not necessary for mssql driver */
				SQLMoreResults(odbc_stmt);
				SWAP_STMT(stmt2);
			}
		}
	}

	SWAP_STMT(stmt2);
	CHKFreeStmt(SQL_DROP, "S");
	SWAP_STMT(stmt2);

	odbc_reset_statement();

	/* test values */
	CheckNoRow("IF (SELECT COUNT(*) FROM #test) <> 4 SELECT 1");
	CheckNoRow("IF NOT EXISTS(SELECT * FROM #test WHERE i = 3 AND c = 'ccc') SELECT 1");
	CheckNoRow("IF NOT EXISTS(SELECT * FROM #test WHERE i = 4 AND c = 'dddd') SELECT 1");
	if (strstr(select_sql, "#a") == NULL || use_sql) {
		CheckNoRow("IF NOT EXISTS(SELECT * FROM #test WHERE i = 2 AND c = 'foo') SELECT 1");
		CheckNoRow("IF NOT EXISTS(SELECT * FROM #test WHERE i = 6 AND c = 'foo') SELECT 1");
	}
}
Ejemplo n.º 26
0
int
main(int argc, char *argv[])
{
	SQLINTEGER len, out;
	int i;
	SQLHSTMT stmt1, stmt2;
	SQLHSTMT *pcur_stmt = NULL;

	odbc_use_version3 = 1;
	odbc_set_conn_attr = my_attrs;
	odbc_connect();

	stmt1 = odbc_stmt;

	out = 0;
	len = sizeof(out);
	CHKGetConnectAttr(1224, (SQLPOINTER) &out, sizeof(out), &len, "S");

	/* test we really support MARS on this connection */
	/* TODO should out be correct ?? */
	printf("Following row can contain an error due to MARS detection (is expected)\n");
	if (!out || odbc_command2("BEGIN TRANSACTION", "SNoE") != SQL_ERROR) {
		printf("MARS not supported for this connection\n");
		odbc_disconnect();
		odbc_test_skipped();
		return 0;
	}
	odbc_read_error();
	if (!strstr(odbc_err, "MARS")) {
		printf("Error message invalid \"%s\"\n", odbc_err);
		return 1;
	}

	/* create a test table with some data */
	odbc_command("create table #mars1 (n int, v varchar(100))");
	for (i = 0; i < 60; ++i) {
		char cmd[120], buf[80];
		memset(buf, 'a' + (i % 26), sizeof(buf));
		buf[i * 7 % 73] = 0;
		sprintf(cmd, "insert into #mars1 values(%d, '%s')", i, buf);
		odbc_command(cmd);
	}

	/* and another to avid locking problems */
	odbc_command("create table #mars2 (n int, v varchar(100))");

	AutoCommit(SQL_AUTOCOMMIT_OFF);

	/* try to do a select which return a lot of data (to test server didn't cache everything) */
	odbc_command("select a.n, b.n, a.v from #mars1 a, #mars1 b order by a.n, b.n");
	CHKFetch("S");

	/* try to do other commands */
	CHKAllocStmt(&stmt2, "S");
	SET_STMT(stmt2);
	odbc_command("insert into #mars2 values(1, 'foo')");
	SET_STMT(stmt1);

	CHKFetch("S");

	/* reset statements */
	odbc_reset_statement();
	SET_STMT(stmt2);
	odbc_reset_statement();

	/* now to 2 select with prepare/execute */
	CHKPrepare(T("select a.n, b.n, a.v from #mars1 a, #mars1 b order by a.n, b.n"), SQL_NTS, "S");
	SET_STMT(stmt1);
	CHKPrepare(T("select a.n, b.n, a.v from #mars1 a, #mars1 b order by a.n desc, b.n"), SQL_NTS, "S");
	SET_STMT(stmt2);
	CHKExecute("S");
	SET_STMT(stmt1);
	CHKExecute("S");
	SET_STMT(stmt2);
	CHKFetch("S");
	SET_STMT(stmt1);
	CHKFetch("S");
	SET_STMT(stmt2);
	CHKFetch("S");
	odbc_reset_statement();
	SET_STMT(stmt1);
	CHKFetch("S");
	odbc_reset_statement();

	EndTransaction(SQL_COMMIT);

	/* TODO test receiving large data should not take much memory */

	odbc_disconnect();
	return 0;
}
Ejemplo n.º 27
0
static int
TestOutput(const char *type, const char *value_to_convert, SQLSMALLINT out_c_type, SQLSMALLINT out_sql_type, const char *expected)
{
    char sbuf[1024];
    unsigned char out_buf[256];
    SQLLEN out_len = 0;
    const char *sep;

    odbc_reset_statement();

    /* build store procedure to test */
    odbc_command("IF OBJECT_ID('spTestProc') IS NOT NULL DROP PROC spTestProc");
    sep = "'";
    if (strncmp(value_to_convert, "0x", 2) == 0)
        sep = "";
    sprintf(sbuf, "CREATE PROC spTestProc @i %s OUTPUT AS SELECT @i = CONVERT(%s, %s%s%s)", type, type, sep, value_to_convert, sep);
    odbc_command(sbuf);
    memset(out_buf, 0, sizeof(out_buf));

    if (use_cursors) {
        odbc_reset_statement();
        CHKSetStmtAttr(SQL_ATTR_CURSOR_SCROLLABLE, (SQLPOINTER) SQL_SCROLLABLE, 0, "S");
        CHKSetStmtAttr(SQL_ATTR_CURSOR_TYPE, (SQLPOINTER) SQL_CURSOR_DYNAMIC, 0, "S");
    }

    /* bind parameter */
    if (exec_direct) {
        CHKBindParameter(1, SQL_PARAM_OUTPUT, out_c_type, out_sql_type, precision, 0, out_buf,
                         sizeof(out_buf), &out_len, "S");

        /* call store procedure */
        CHKExecDirect(T("{call spTestProc(?)}"), SQL_NTS, "S");
    } else {
        if (prepare_before)
            CHKPrepare(T("{call spTestProc(?)}"), SQL_NTS, "S");

        CHKBindParameter(1, SQL_PARAM_OUTPUT, out_c_type, out_sql_type, precision, 0, out_buf,
                         sizeof(out_buf), &out_len, "S");

        if (!prepare_before)
            CHKPrepare(T("{call spTestProc(?)}"), SQL_NTS, "S");

        CHKExecute("S");
    }

    /*
     * MS OBDC requires it cause first recordset is a recordset with a
     * warning caused by the way it execute RPC (via EXEC statement)
     */
    if (use_cursors && !odbc_driver_is_freetds())
        SQLMoreResults(odbc_stmt);

    /* test results */
    odbc_c2string(sbuf, out_c_type, out_buf, out_len);

    if (strcmp(sbuf, expected) != 0) {
        if (only_test) {
            odbc_command("drop proc spTestProc");
            ODBC_FREE();
            return 1;
        }
        fprintf(stderr, "Wrong result\n  Got: %s\n  Expected: %s\n", sbuf, expected);
        exit(1);
    }
    only_test = 0;
    odbc_command("drop proc spTestProc");
    ODBC_FREE();
    return 0;
}
Ejemplo n.º 28
0
static void
query_test(const char* expected, const char *expected_status)
{
#define ARRAY_SIZE 10

    ODBC_BUF *odbc_buf = NULL;
    SQLUINTEGER *ids;
    SQLCHAR *descs;
    SQLLEN *id_lens, *desc_lens;
    SQLULEN processed;
    SQLUSMALLINT i, statuses[ARRAY_SIZE];
    int desc_len = trunc ? 4 : 51;
    int rec_size = 0;
    Record *rec = NULL;
    char status[20];

    assert(odbc_stmt != SQL_NULL_HSTMT);
    odbc_reset_statement();

    SQLSetStmtAttr(odbc_stmt, SQL_ATTR_ROW_STATUS_PTR, statuses, 0);
    SQLSetStmtAttr(odbc_stmt, SQL_ATTR_ROW_ARRAY_SIZE, (void *) ARRAY_SIZE, 0);
    SQLSetStmtAttr(odbc_stmt, SQL_ATTR_ROWS_FETCHED_PTR, &processed, 0);
    SQLSetStmtAttr(odbc_stmt, SQL_ATTR_ROW_BIND_TYPE, SQL_BIND_BY_COLUMN, 0);

    if (!record_bind) {
        ids = (SQLUINTEGER *) ODBC_GET(sizeof(SQLUINTEGER) * ARRAY_SIZE);
        descs = ODBC_GET(sizeof(SQLCHAR) * ARRAY_SIZE * desc_len);
        desc_lens = (SQLLEN *) ODBC_GET(sizeof(SQLLEN) * ARRAY_SIZE);
        id_lens = (SQLLEN *) ODBC_GET(sizeof(SQLLEN) * ARRAY_SIZE);
        assert(descs && ids && desc_lens && id_lens);
    } else {
        rec_size = (sizeof(Record) + (sizeof(SQLCHAR) * desc_len + sizeof(SQLLEN) - 1)) & ~(sizeof(SQLLEN) - 1);
        SQLSetStmtAttr(odbc_stmt, SQL_ATTR_ROW_BIND_TYPE, int2ptr(rec_size), 0);
        rec = (Record *) ODBC_GET(rec_size * ARRAY_SIZE);
        ids = &rec->id;
        id_lens = &rec->id_len;
        desc_lens = &rec->desc_len;
        descs = (SQLCHAR *) (((char *) rec) + sizeof(Record));
    }
#define REC(f,n) (((char*)f)+rec_size*(n))
#define DESCS(n) (rec ? (SQLCHAR*)REC(descs,n): (descs+(n)*desc_len))
#define IDS(n) *(rec ? (SQLUINTEGER*)REC(ids,n) : &ids[n])
#define ID_LENS(n) *(rec ? (SQLLEN*)REC(id_lens,n) : &id_lens[n])
#define DESC_LENS(n) *(rec ? (SQLLEN*)REC(desc_lens,n) : &desc_lens[n])

    processed = ARRAY_SIZE + 1;
    for (i = 0; i < ARRAY_SIZE; i++) {
        statuses[i] = SQL_ROW_UPDATED;
        IDS(i) = i * 132;
        sprintf((char *) DESCS(i), "aaa");
        ID_LENS(i) = 0;
        DESC_LENS(i) = -i;
    }

    SQLBindCol(odbc_stmt, 1, SQL_C_ULONG, &IDS(0), 0, &ID_LENS(0));
    SQLBindCol(odbc_stmt, 2, SQL_C_CHAR, DESCS(0), desc_len, &DESC_LENS(0));

    CHKExecDirect(T(test_query), SQL_NTS, "S");

    CHKFetch(expected);

    assert(processed <= ARRAY_SIZE);

    for (i = 0; i < processed; ++i) {
        char buf[128];

        sprintf(buf, "%crow number %d", 'a' + i, i * 13);
        if (trunc)
            buf[3] = 0;
        if (IDS(i) != i + 1 || strcmp((char *) DESCS(i), buf) != 0) {
            fprintf(stderr, "Invalid result\n\tgot '%d|%s'\n\texpected '%d|%s'\n", (int) IDS(i), DESCS(i), i + 1, buf);
            exit(1);
        }

        switch (statuses[i]) {
        case SQL_ROW_SUCCESS:
            status[i] = 'V';
            break;

        case SQL_ROW_SUCCESS_WITH_INFO:
            status[i] = 'v';
            break;

        case SQL_ROW_ERROR:
            status[i] = '!';
            break;

        case SQL_ROW_NOROW:
            status[i] = ' ';
            break;

        default:
            fprintf(stderr, "Invalid status returned\n");
            exit(1);
        }
    }
    status[i] = 0;

    if (expected_status && strcmp(expected_status, status) != 0) {
        fprintf(stderr, "Invalid status\n\tgot '%s'\n\texpected '%s'\n", status, expected_status);
        exit(1);
    }

    ODBC_FREE();
}
Ejemplo n.º 29
0
static void
TestInput(SQLSMALLINT out_c_type, const char *type, SQLSMALLINT out_sql_type, const char *param_type, const char *value_to_convert)
{
    char sbuf[1024];
    unsigned char out_buf[256];
    SQLLEN out_len = 0;
    const char *expected = value_to_convert;
    size_t value_len = strlen(value_to_convert);
    const char *p;
    const char *sep = "'";

    odbc_reset_statement();

    /* execute a select to get data as wire */
    if ((p = strstr(value_to_convert, " -> ")) != NULL) {
        value_len = p - value_to_convert;
        expected = p + 4;
    }
    if (value_len >= 2 && strncmp(value_to_convert, "0x", 2) == 0)
        sep = "";
    sprintf(sbuf, "SELECT CONVERT(%s, %s%.*s%s)", type, sep, (int) value_len, value_to_convert, sep);
    odbc_command(sbuf);
    SQLBindCol(odbc_stmt, 1, out_c_type, out_buf, sizeof(out_buf), &out_len);
    CHKFetch("SI");
    CHKFetch("No");
    CHKMoreResults("No");
    if (use_nts) {
        out_len = SQL_NTS;
        use_nts = 0;
    }

    /* create a table with a column of that type */
    odbc_reset_statement();
    sprintf(sbuf, "CREATE TABLE #tmp_insert (col %s)", param_type);
    odbc_command(sbuf);

    if (use_cursors) {
        odbc_reset_statement();
        CHKSetStmtAttr(SQL_ATTR_CURSOR_SCROLLABLE, (SQLPOINTER) SQL_SCROLLABLE, 0, "S");
        CHKSetStmtAttr(SQL_ATTR_CURSOR_TYPE, (SQLPOINTER) SQL_CURSOR_DYNAMIC, 0, "S");
    }

    /* insert data using prepared statements */
    sprintf(sbuf, "INSERT INTO #tmp_insert VALUES(?)");
    if (exec_direct) {
        CHKBindParameter(1, SQL_PARAM_INPUT, out_c_type, out_sql_type, 20, 0, out_buf, sizeof(out_buf), &out_len, "S");

        if (check_truncation)
            CHKExecDirect(T(sbuf), SQL_NTS, "E");
        else
            CHKExecDirect(T(sbuf), SQL_NTS, "SNo");
    } else {
        if (prepare_before)
            CHKPrepare(T(sbuf), SQL_NTS, "S");

        CHKBindParameter(1, SQL_PARAM_INPUT, out_c_type, out_sql_type, 20, 0, out_buf, sizeof(out_buf), &out_len, "S");

        if (!prepare_before)
            CHKPrepare(T(sbuf), SQL_NTS, "S");

        if (check_truncation)
            CHKExecute("E");
        else
            CHKExecute("SNo");
    }

    /* check if row is present */
    if (!check_truncation) {
        odbc_reset_statement();
        sep = "'";
        if (strncmp(expected, "0x", 2) == 0)
            sep = "";
        if (strcmp(param_type, "TEXT") == 0)
            sprintf(sbuf, "SELECT * FROM #tmp_insert WHERE CONVERT(VARCHAR(255), col) = CONVERT(VARCHAR(255), %s%s%s)", sep, expected, sep);
        else if (strcmp(param_type, "NTEXT") == 0)
            sprintf(sbuf, "SELECT * FROM #tmp_insert WHERE CONVERT(NVARCHAR(2000), col) = CONVERT(NVARCHAR(2000), %s%s%s)", sep, expected, sep);
        else if (strcmp(param_type, "IMAGE") == 0)
            sprintf(sbuf, "SELECT * FROM #tmp_insert WHERE CONVERT(VARBINARY(255), col) = CONVERT(VARBINARY(255), %s%s%s)", sep, expected, sep);
        else
            sprintf(sbuf, "SELECT * FROM #tmp_insert WHERE col = CONVERT(%s, %s%s%s)", param_type, sep, expected, sep);
        odbc_command(sbuf);

        CHKFetch("S");
        CHKFetch("No");
        CHKMoreResults("No");
    }
    check_truncation = 0;
    odbc_command("DROP TABLE #tmp_insert");
    ODBC_FREE();
}
Ejemplo n.º 30
0
int
main(int argc, char *argv[])
{
#define TEST_FILE "attributes.in"
	const char *in_file = FREETDS_SRCDIR "/" TEST_FILE;
	FILE *f;
	char buf[256];
	SQLINTEGER i;
	SQLLEN len;
	get_attr_t get_attr_p = get_attr_stmt;

	odbc_connect();
	/* TODO find another way */
	odbc_check_cursor();
	odbc_command("SET TEXTSIZE 4096");

	SQLBindCol(odbc_stmt, 1, SQL_C_SLONG, &i, sizeof(i), &len);

	f = fopen(in_file, "r");
	if (!f)
		f = fopen(TEST_FILE, "r");
	if (!f) {
		fprintf(stderr, "error opening test file\n");
		exit(1);
	}

	line_num = 0;
	while (fgets(buf, sizeof(buf), f)) {
		char *p = buf, *cmd;

		++line_num;

		while (isspace((unsigned char) *p))
			++p;
		cmd = strtok(p, SEP);

		/* skip comments */
		if (!cmd || cmd[0] == '#' || cmd[0] == 0 || cmd[0] == '\n')
			continue;

		if (strcmp(cmd, "odbc") == 0) {
			int odbc3 = get_int(strtok(NULL, SEP)) == 3 ? 1 : 0;

			if (odbc_use_version3 != odbc3) {
				odbc_use_version3 = odbc3;
				odbc_disconnect();
				odbc_connect();
				odbc_command("SET TEXTSIZE 4096");
				SQLBindCol(odbc_stmt, 1, SQL_C_SLONG, &i, sizeof(i), &len);
			}
			continue;
		}

		/* set attribute */
		if (strcmp(cmd, "set") == 0) {
			const struct attribute *attr = lookup_attr(strtok(NULL, SEP));
			char *value = strtok(NULL, SEP);
			SQLRETURN ret;

			if (!value)
				fatal("Line %u: value not defined\n", line_num);

			ret = SQL_ERROR;
			switch (attr->type) {
			case type_UINTEGER:
			case type_INTEGER:
				ret = SQLSetStmtAttr(odbc_stmt, attr->value, int2ptr(lookup(value, attr->lookup)),
						      sizeof(SQLINTEGER));
				break;
			case type_SMALLINT:
				ret = SQLSetStmtAttr(odbc_stmt, attr->value, int2ptr(lookup(value, attr->lookup)),
						      sizeof(SQLSMALLINT));
				break;
			case type_LEN:
				ret = SQLSetStmtAttr(odbc_stmt, attr->value, int2ptr(lookup(value, attr->lookup)),
						      sizeof(SQLLEN));
				break;
			case type_CHARP:
				ret = SQLSetStmtAttr(odbc_stmt, attr->value, (SQLPOINTER) value, SQL_NTS);
				break;
			case type_VOIDP:
			case type_DESC:
				fatal("Line %u: not implemented\n");
			}
			if (!SQL_SUCCEEDED(ret))
				fatal("Line %u: failure not expected setting statement attribute\n", line_num);
			get_attr_p = get_attr_stmt;
			continue;
		}

		/* test attribute */
		if (strcmp(cmd, "attr") == 0) {
			const struct attribute *attr = lookup_attr(strtok(NULL, SEP));
			char *value = strtok(NULL, SEP);
			int i, expected = lookup(value, attr->lookup);

			if (!value)
				fatal("Line %u: value not defined\n", line_num);

			i = get_attr_p(attr, expected);
			if (i != expected) {
				g_result = 1;
				fprintf(stderr, "Line %u: invalid %s got %d(%s) expected %s\n", line_num, attr->name, i, unlookup(i, attr->lookup), value);
			}
			continue;
		}

		if (strcmp(cmd, "reset") == 0) {
			odbc_reset_statement();
			continue;
		}

		fatal("Line %u: command '%s' not handled\n", line_num, cmd);
	}

	fclose(f);
	odbc_disconnect();

	printf("Done.\n");
	return g_result;
}