Re: [0.95rc2] Preliminary test results

Frediano Ziglio <[email protected]>
Newsgroups gmane.comp.db.tds.freetds
Message-ID <CAHt6W4ddoheQC_TRnOZE2sjF_kJjaL5fa12nFDd5-pG_C4749A@mail.gmail.com>
2015-05-11 23:45 GMT+01:00 Sergio NNX <[email protected]>:
>> Hi Sergio,
>>   can you try the new rc version? Should be much better.
>
> Compile-time settings (established with the "configure" script)
>                             Version: freetds v0.95rc2
>              freetds.conf directory: \freetds-0.95rc2\etc
>      MS db-lib source compatibility: no
>         Sybase binary compatibility: no
>                       Thread safety: yes
>                       iconv library: yes
>                         TDS version: 7.0
>                               iODBC: no
>                            unixodbc: yes
>               SSPI "trusted" logins: yes
>                            Kerberos: yes (Heimdal 1.6.99)
>                             OpenSSL: yes (OpenSSL 1.0.2a)
>                              GnuTLS: no
>
> Protocol Version = <whichever is set by 'make check' command>
>
> MS SQL Server version: 2008 (10.0.1600.22)
>
> ===================
> All 4 tests passed (replacements/unittests)
> ===================
>
> ===================
> All 20 tests passed (tds/unittests)
> ===================
>
> ===================
> All 29 tests passed (ctlib/unittests)
> ===================
>
> ====================
> 1 of 35 tests failed (dblib/unittests)
> ====================
>
> Failed tests: rpc
>
> [...]
> retrieving return status...
> 42
> retrieving output parameters...
> param name                  type length  data
> ----  -------------------   ----  ----- ------------------------------
> 1     @null_input             39      3  xml
> 2     @first_type             39      6  bigint
> 3     @nullout                56      0
> 4     @varchar_tds7_out       39   8000  ÷÷÷÷÷÷÷÷÷÷...
> 5     @nvarchar_tds7_out      39   4000  öööööööööö...
> 6     @nrows                  56      4  3
> Good: Got 6 output parameters and 1 return status of 42.
> Expected an empty resultset got 2.
> FAIL rpc.exe (exit status: 1)
>

I start to suspect this (and the other rpc test) could be due to some
changes in the protocol for mssql 2008 r2.
I'll need a dump to confirm it.

> ====================
> 3 of 72 tests failed (odbc/unittests)
> ====================
>
> Failed tests: genparams rpc freeclose
>
> genparams test output
>
> [...]
> DROP TABLE #tmp_insert
> SELECT GETDATE()
> SELECT CONVERT(DATETIME, '2003-07-22 13:02:03')
> CREATE TABLE #tmp_insert (col DATETIME)
> SELECT * FROM #tmp_insert WHERE col = CONVERT(DATETIME, '2015-05-12 13:02:03')
> genparams.c:191 rc=100 SQLFetch
> FAIL genparams.exe (exit status: 1)
>

Believe or not this test for me fails at a specific time near
midday... can you run again (just this test is enough).

> rpc test output
>
> [...]
> done.
> bound data for parameter 1 is 4 bytes: 42.
> bound data for parameter 2 is 3 bytes: 'xml'.
> bound data for parameter 3 is 6 bytes: 'bigint'.
> bound data for parameter 4 is 4 bytes: 6381921.
> bound data for parameter 5 is 4 bytes: 3.
> executing SQLFreeStmt
> 1 errors found in expected row count
> FAIL rpc.exe (exit status: 1)
>
> freeclose test output
>
> [...]
> Error finding last socket opened
> FAIL freeclose.exe (exit status: 1)
>

Can you try the attached version?

Frediano

_______________________________________________
FreeTDS mailing list
[email protected]
http://lists.ibiblio.org/mailman/listinfo/freetds
freeclose.c (text/x-csrc, 11.1 KB)
#include "common.h"

#if HAVE_UNISTD_H
#include <unistd.h>
#endif /* HAVE_UNISTD_H */

#include <freetds/time.h>

#if HAVE_ERRNO_H
#include <errno.h>
#endif /* HAVE_ERRNO_H */

#if HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif /* HAVE_SYS_SOCKET_H */

#if HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif /* HAVE_SYS_STAT_H */

#if HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif /* HAVE_SYS_IOCTL_H */

#if HAVE_SYS_WAIT_H
#include <sys/wait.h>
#endif /* HAVE_SYS_WAIT_H */

#if HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif /* HAVE_NETINET_IN_H */

#if (!defined(TDS_NO_THREADSAFE) && HAVE_ALARM && HAVE_FSTAT && defined(S_IFSOCK)) || defined(_WIN32)

#include <ctype.h>

#include <freetds/tds.h>
#include <freetds/thread.h>

/* this crazy test test that we do not send too much prepare ... */

static tds_mutex mtx;

#ifdef _WIN32
static TDS_SYS_SOCKET
odbc_find_last_socket(void)
{
	typedef struct {
		TDS_SYS_SOCKET sock;
		int local_port;
		int remote_port;
	} sock_info;
	sock_info found[8];
	unsigned num_found = 0, n;
	int i;

	for (i = 4; i <= (4096*4); i += 4) {
		struct sockaddr remote_addr, local_addr;
		struct sockaddr_in *in;
		socklen_t remote_addr_len, local_addr_len;
		sock_info *info;

		/* check if is a socket */
		remote_addr_len = sizeof(remote_addr);
		if (tds_getpeername((TDS_SYS_SOCKET) i, &remote_addr, &remote_addr_len))
			continue;
		local_addr_len = sizeof(local_addr);
		if (tds_getsockname((TDS_SYS_SOCKET) i, &local_addr, &local_addr_len))
			continue;

		/* save in the array */
		if (num_found >= 8) {
			memmove(found, found+1, sizeof(found) - sizeof(found[0]));
			num_found = 7;
		}
		info = &found[num_found++];
		info->sock = (TDS_SYS_SOCKET) i;
		info->local_port = -1;
		info->remote_port = -1;

		/* now check if is a socketpair */
		in = (struct sockaddr_in *) &remote_addr;
		if (in->sin_family != AF_INET)
			continue;
		if (in->sin_addr.s_addr != htonl(INADDR_LOOPBACK))
			continue;
		info->remote_port = ntohs(in->sin_port);
		in = (struct sockaddr_in *) &local_addr;
		if (in->sin_family != AF_INET)
			continue;
		if (in->sin_addr.s_addr != htonl(INADDR_LOOPBACK))
			continue;
		info->local_port = ntohs(in->sin_port);
		for (n = 0; n < num_found - 1; ++n) {
			if (found[n].remote_port != info->local_port
			    || found[n].local_port != info->remote_port)
				continue;
			--num_found;
			memmove(found+n, found+n+1, num_found-n-1);
			--num_found;
			break;
		}
	}

	/* return last */
	if (num_found == 0)
		return INVALID_SOCKET;
	return found[num_found-1].sock;
}
#endif

static struct sockaddr remote_addr;
static socklen_t remote_addr_len;

static TDS_SYS_SOCKET fake_sock;

static tds_thread fake_thread;
#ifdef _WIN32
#define alarm(n) do { ; } while(0)
#endif
static TDS_THREAD_PROC_DECLARE(fake_thread_proc, arg);

static int
init_fake_server(int ip_port)
{
	struct sockaddr_in sin;
	TDS_SYS_SOCKET s;

	memset(&sin, 0, sizeof(sin));
	sin.sin_addr.s_addr = INADDR_ANY;
	sin.sin_port = htons((short) ip_port);
	sin.sin_family = AF_INET;

	if (TDS_IS_SOCKET_INVALID(s = socket(AF_INET, SOCK_STREAM, 0))) {
		perror("socket");
		exit(1);
	}
	if (bind(s, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
		perror("bind");
		CLOSESOCKET(s);
		return 1;
	}
	listen(s, 5);
	if (tds_thread_create(&fake_thread, fake_thread_proc, int2ptr(s)) != 0) {
		perror("tds_thread_create");
		exit(1);
	}
	return 0;
}

static void
write_all(TDS_SYS_SOCKET s, const void *buf, size_t len)
{
	int res, l;
	fd_set fds_write;

	for (; len > 0;) {
		FD_ZERO(&fds_write);
		FD_SET(s, &fds_write);

		res = select(s + 1, NULL, &fds_write, NULL, NULL);
		if (res <= 0) {
			if (errno == EINTR)
				continue;
			perror("select");
			exit(1);
		}

		l = WRITESOCKET(s, buf, len);
		if (l <= 0) {
			perror("write socket");
			exit(1);
		}
		buf = ((const char *) buf) + l;
		len -= l;
	}
}

static unsigned int inserts = 0;
static char insert_buf[256] = "";

static void
count_insert(const char* buf, size_t len)
{
	static const char search[] = "insert into";
	static unsigned char prev = 'x';
	char *p;
	unsigned char c;
	size_t insert_len;

	/* add to buffer */
	for (p = strchr(insert_buf, 0); len > 0; --len, ++buf) {
		c = (unsigned char) buf[0];
		if (prev == 0 || c != 0)
			*p++ = (c >= ' ' && c < 128) ? tolower(c) : '_';
		prev = c;
	}
	*p = 0;

	/* check it */
	while ((p=strstr(insert_buf, search)) != NULL) {
		tds_mutex_lock(&mtx);
		++inserts;
		tds_mutex_unlock(&mtx);
		/* do not find again */
		p[0] = '_';
	}

	/* avoid buffer too long */
	insert_len = strlen(insert_buf);
	if (insert_len > sizeof(search)) {
		p = insert_buf + insert_len - sizeof(search);
		memmove(insert_buf, p, strlen(p) + 1);
	}
}

static unsigned int round_trips = 0;
static enum { sending, receiving } flow = sending;

static TDS_THREAD_PROC_DECLARE(fake_thread_proc, arg)
{
	TDS_SYS_SOCKET s = ptr2int(arg), server_sock;
	socklen_t sock_len;
	int len;
	char buf[128];
	struct sockaddr_in sin;
	fd_set fds_read, fds_write, fds_error;
	TDS_SYS_SOCKET max_fd = 0;

	memset(&sin, 0, sizeof(sin));
	sock_len = sizeof(sin);
	alarm(30);
	if ((fake_sock = tds_accept(s, (struct sockaddr *) &sin, &sock_len)) < 0) {
		perror("accept");
		exit(1);
	}
	CLOSESOCKET(s);

	if (TDS_IS_SOCKET_INVALID(server_sock = socket(AF_INET, SOCK_STREAM, 0))) {
		perror("socket");
		exit(1);
	}

	if (connect(server_sock, &remote_addr, remote_addr_len)) {
		perror("connect");
		exit(1);
	}
	alarm(0);

	if (fake_sock > max_fd) max_fd = fake_sock;
	if (server_sock > max_fd) max_fd = server_sock;

	for (;;) {
		int res;

		FD_ZERO(&fds_read);
		FD_SET(fake_sock, &fds_read);
		FD_SET(server_sock, &fds_read);

		FD_ZERO(&fds_write);

		FD_ZERO(&fds_error);
		FD_SET(fake_sock, &fds_error);
		FD_SET(server_sock, &fds_error);

		alarm(30);
		res = select(max_fd + 1, &fds_read, &fds_write, &fds_error, NULL);
		alarm(0);
		if (res < 0) {
			if (sock_errno == TDSSOCK_EINTR)
				continue;
			perror("select");
			exit(1);
		}

		if (FD_ISSET(fake_sock, &fds_error) || FD_ISSET(server_sock, &fds_error)) {
			fprintf(stderr, "error in select\n");
			exit(1);
		}

		/* just read and forward */
		if (FD_ISSET(fake_sock, &fds_read)) {
			if (flow != sending) {
				tds_mutex_lock(&mtx);
				++round_trips;
				tds_mutex_unlock(&mtx);
			}
			flow = sending;

			len = READSOCKET(fake_sock, buf, sizeof(buf));
			if (len == 0)
				break;
			if (len < 0 && sock_errno != TDSSOCK_EINPROGRESS)
				break;
			count_insert(buf, len);
			write_all(server_sock, buf, len);
		}

		if (FD_ISSET(server_sock, &fds_read)) {
			if (flow != receiving) {
				tds_mutex_lock(&mtx);
				++round_trips;
				tds_mutex_unlock(&mtx);
			}
			flow = receiving;

			len = READSOCKET(server_sock, buf, sizeof(buf));
			if (len == 0)
				break;
			if (len < 0 && sock_errno != TDSSOCK_EINPROGRESS)
				break;
			write_all(fake_sock, buf, len);
		}
	}
	CLOSESOCKET(fake_sock);
	CLOSESOCKET(server_sock);
	return NULL;
}

int
main(int argc, char **argv)
{
	SQLLEN sql_nts = SQL_NTS;
	const char *query;
	SQLINTEGER id = 0;
	char string[64];
	TDS_SYS_SOCKET last_socket;
	int port;
	const int num_inserts = 20;
	int is_freetds;

#ifdef _WIN32
	WSADATA wsaData;
	WSAStartup(MAKEWORD(1, 1), &wsaData);
#endif

	if (tds_mutex_init(&mtx))
		return 1;

	odbc_connect();

	/*
	 * this does not work if server is not connected with socket
	 * (ie ms driver connected locally)
	 */
	last_socket = odbc_find_last_socket();
	if (TDS_IS_SOCKET_INVALID(last_socket)) {
		fprintf(stderr, "Error finding last socket opened\n");
		return 1;
	}

	remote_addr_len = sizeof(remote_addr);
	if (tds_getpeername(last_socket, &remote_addr, &remote_addr_len)) {
		fprintf(stderr, "Unable to get remote address\n");
		return 1;
	}

	is_freetds = odbc_driver_is_freetds();
	odbc_disconnect();

	/* init fake server, behave like a proxy */
	for (port = 12340; port < 12350; ++port)
		if (!init_fake_server(port))
			break;
	if (port == 12350) {
		fprintf(stderr, "Cannot bind to a port\n");
		return 1;
	}
	printf("Fake server bound at port %d\n", port);

	/* override connections */
	if (is_freetds) {
		setenv("TDSHOST", "127.0.0.1", 1);
		sprintf(string, "%d", port);
		setenv("TDSPORT", string, 1);

		odbc_connect();
	} else {
		char tmp[2048];
		SQLSMALLINT len;

		CHKAllocEnv(&odbc_env, "S");
		CHKAllocConnect(&odbc_conn, "S");
		sprintf(tmp, "DRIVER={SQL Server};SERVER=127.0.0.1,%d;UID=%s;PWD=%s;DATABASE=%s;Network=DBMSSOCN;", port, odbc_user, odbc_password, odbc_database);
		printf("connection string: %s\n", tmp);
		CHKDriverConnect(NULL, T(tmp), SQL_NTS, (SQLTCHAR *) tmp, sizeof(tmp)/sizeof(SQLTCHAR), &len, SQL_DRIVER_NOPROMPT, "SI");
		CHKAllocStmt(&odbc_stmt, "S");
	}

	/* real test */
	odbc_command("CREATE TABLE #test(i int, c varchar(40))");

	odbc_reset_statement();

	/* do not take into account connection statistics */
	tds_mutex_lock(&mtx);
	round_trips = 0;
	inserts = 0;
	tds_mutex_unlock(&mtx);

	query = "insert into #test values (?, ?)";

	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(query), SQL_NTS, "SI");
	tds_mutex_lock(&mtx);
	printf("%u round trips %u inserts\n", round_trips, inserts);
	tds_mutex_unlock(&mtx);

	for (id = 0; id < num_inserts; id++) {
		sprintf(string, "This is a test (%d)", (int) id);
		CHKExecute("SI");
		CHKFreeStmt(SQL_CLOSE, "S");
	}

	tds_mutex_lock(&mtx);
	printf("%u round trips %u inserts\n", round_trips, inserts);
	tds_mutex_unlock(&mtx);
	odbc_reset_statement();

	tds_mutex_lock(&mtx);
	if (inserts > 1 || round_trips > (unsigned) (num_inserts * 2 + 6)) {
		fprintf(stderr, "Too much round trips (%u) or insert (%u) !!!\n", round_trips, inserts);
		tds_mutex_unlock(&mtx);
		return 1;
	}
	printf("%u round trips %u inserts\n", round_trips, inserts);
	tds_mutex_unlock(&mtx);

#ifdef ENABLE_DEVELOPING
	/* check for SQL_RESET_PARAMS */
	tds_mutex_lock(&mtx);
	round_trips = 0;
	inserts = 0;
	tds_mutex_unlock(&mtx);

	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((SQLCHAR *) query, SQL_NTS, "SI");
	tds_mutex_lock(&mtx);
	printf("%u round trips %u inserts\n", round_trips, inserts);
	tds_mutex_unlock(&mtx);

	for (id = 0; id < num_inserts; id++) {
		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");

		sprintf(string, "This is a test (%d)", (int) id);
		CHKExecute("SI");
		CHKFreeStmt(SQL_RESET_PARAMS, "S");
	}

	tds_mutex_lock(&mtx);
	printf("%u round trips %u inserts\n", round_trips, inserts);
	tds_mutex_unlock(&mtx);
	odbc_reset_statement();

	tds_mutex_lock(&mtx);
	if (inserts > 1 || round_trips > num_inserts * 2 + 6) {
		fprintf(stderr, "Too much round trips (%u) or insert (%u) !!!\n", round_trips, inserts);
		tds_mutex_unlock(&mtx);
		return 1;
	}
	printf("%u round trips %u inserts\n", round_trips, inserts);
	tds_mutex_unlock(&mtx);
#endif

	odbc_disconnect();

	alarm(10);
	tds_thread_join(fake_thread, NULL);

	return 0;
}

#else
int
main(void)
{
        printf("Not possible for this platform.\n");
        return 0;
}
#endif
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.