Re: CTLib patch

Frediano Ziglio <[email protected]>
Newsgroups gmane.comp.db.tds.freetds
Message-ID <[email protected]>
2009/6/17 Andrew Victor <[email protected]>
>
> hi Frediano,
>
> > ... it seems that client datatype does not support
> > wide characters, isn't it? So you are correctly trying to bind client
> > utf-8 (multi-byte) to server wide characters (nvarchar in mssql),
> > isn't it?
>
> There must be some data-type mapping to NVARCHAR?  I assumed it was
> CS_UNICHAR_TYPE.
>
>
> > Do you have an example so I can write a small unittests??
>
> I have extended the FreeTDS ctlib unit-test "rpc_ct_param.c", which is attached.
> Just ensure you have "client charset = UTF-8" in you freetds.conf
>
> Without the patch the unit-test gives:
>
> Open Client Message:
> Message number: LAYER = (0) ORIGIN = (0) SEVERITY = (9) NUMBER = (98)
> Message String: Error converting characters into server's character
> set. Some character(s) could not be converted
>
> Server message:
> Message number: 8016, Severity 16, State 26, Line 1
> Server 'xxxx'
> Message String: The incoming tabular data stream (TDS) remote
> procedure call (RPC) protocol stream is incorrect. Parameter 2
> ("@nvparam"): Data type 0xA7 has an invalid data length or metadata
> length.

Attached my patch which merge your test (currently not working)

freddy77

_______________________________________________
FreeTDS mailing list
[email protected]
http://lists.ibiblio.org/mailman/listinfo/freetds
ctlib_unichar.diff (application/octet-stream, 5.6 KB)
Index: freetds83/include/cstypes.h
===================================================================
--- freetds83.orig/include/cstypes.h
+++ freetds83/include/cstypes.h
@@ -54,6 +54,8 @@ typedef long 				CS_LONG;
 typedef unsigned char 			CS_BINARY;
 typedef unsigned tds_sysdep_int16_type 	CS_USHORT;
 typedef unsigned char 			CS_BIT;
+typedef unsigned tds_sysdep_int16_type	CS_UNICHAR;
+typedef unsigned tds_sysdep_int16_type	CS_UNITEXT;
 
 typedef CS_INT CS_RETCODE;
 
Index: freetds83/src/ctlib/unittests/common.c
===================================================================
--- freetds83.orig/src/ctlib/unittests/common.c
+++ freetds83/src/ctlib/unittests/common.c
@@ -338,12 +338,11 @@ CS_INT result_type;
 	while ((results_ret = ct_results(cmd, &result_type)) == CS_SUCCEED) {
 		switch ((int) result_type) {
 		case CS_CMD_SUCCEED:
-			break;
 		case CS_CMD_DONE:
 			break;
 		case CS_CMD_FAIL:
 			fprintf(stderr, "ct_results() result_type CS_CMD_FAIL.\n");
-			/* return CS_FAIL; */
+			return CS_FAIL;
 			break;
 		default:
 			fprintf(stderr, "ct_results() unexpected result_type.\n");
Index: freetds83/src/ctlib/unittests/rpc_ct_param.c
===================================================================
--- freetds83.orig/src/ctlib/unittests/rpc_ct_param.c
+++ freetds83/src/ctlib/unittests/rpc_ct_param.c
@@ -34,6 +34,23 @@ typedef struct _ex_column_data
 }
 EX_COLUMN_DATA;
 
+static void reset_cmd(CS_CONNECTION *conn, CS_COMMAND **cmd)
+{
+	CS_RETCODE ret;
+
+	if (!conn || !cmd || !*cmd) {
+		fprintf(stderr, "Invalid reset_cmd call\n");
+		exit(1);
+	}
+	ct_cancel(conn, NULL, CS_CANCEL_ALL);
+	ct_cmd_drop(*cmd);
+	ret = ct_cmd_alloc(conn, cmd);
+        if (ret != CS_SUCCEED) {
+		fprintf(stderr, "Command Alloc failed!\n");
+		exit(1);
+        }
+}
+
 /* Testing: array binding of result set */
 int
 main(int argc, char *argv[])
@@ -68,8 +85,16 @@ main(int argc, char *argv[])
 	EX_COLUMN_DATA *coldata;
 	CS_DATAFMT *outdatafmt;
 	CS_SMALLINT msg_id;
+	const char *uni_type = NULL;
 
-
+	/* "аовлыфаво авыоладжовы авыолдавжыа ецкуеку авыфа вы" coded in CS_UNICHAR */
+	static const CS_UNICHAR uni_data[] = {
+		0x0430, 0x043e, 0x0432, 0x043b, 0x044b, 0x0444, 0x0430, 0x0432, 0x043e, ' ',
+		0x0430, 0x0432, 0x044b, 0x043e, 0x043b, 0x0430, 0x0434, 0x0436, 0x043e, 0x0432, 0x044b, ' ',
+		0x0430, 0x0432, 0x044b, 0x043e, 0x043b, 0x0434, 0x0430, 0x0432, 0x0436, 0x044b, 0x0430, ' ',
+		0x0435, 0x0446, 0x043a, 0x0443, 0x0435, 0x043a, 0x0443, ' ',
+		0x0430, 0x0432, 0x044b, 0x0444, 0x0430, ' ', 0x0432, 0x044b, 0
+	};
 
 	fprintf(stdout, "%s: submit a stored procedure using ct_param \n", __FILE__);
 	if (verbose) {
@@ -86,16 +111,24 @@ main(int argc, char *argv[])
 	ct_callback(ctx, NULL, CS_SET, CS_SERVERMSG_CB, (CS_VOID *) ex_servermsg_cb);
 
 	/* do not test error */
-	ret = run_command(cmd, "IF EXISTS(SELECT * FROM SYSOBJECTS WHERE name = 'sample_rpc' AND type = 'P') DROP PROCEDURE sample_rpc");
+	ret = run_command(cmd, "IF OBJECT_ID('sample_rpc') IS NOT NULL DROP PROCEDURE sample_rpc");
 
-	strcpy(cmdbuf, "create proc sample_rpc (@intparam int, \
+	if (run_command(cmd, "IF NOT EXISTS(SELECT CAST('a' AS UNICHAR(50))) DROP TABLE mao") == CS_SUCCEED)
+		uni_type = "unichar(50)";
+	reset_cmd(conn, &cmd);
+
+	if (!uni_type && run_command(cmd, "IF NOT EXISTS(SELECT CAST('a' AS NVARCHAR(50))) DROP TABLE mao") == CS_SUCCEED)
+		uni_type = "nvarchar(50)";
+	reset_cmd(conn, &cmd);
+
+	sprintf(cmdbuf, "create proc sample_rpc (@intparam int%s%s, \
         @sintparam smallint output, @floatparam float output, \
         @moneyparam money output,  \
         @dateparam datetime output, @charparam char(20) output, \
         @binaryparam    binary(20) output) \
-        as ");
+        as ", uni_type ? ", @uniparam " : "", uni_type ? uni_type : "");
 
-	strcat(cmdbuf, "select @intparam, @sintparam, @floatparam, @moneyparam, \
+	sprintf(cmdbuf+strlen(cmdbuf), "select @intparam%s, @sintparam, @floatparam, @moneyparam, \
         @dateparam, @charparam, @binaryparam \
         select @sintparam = @sintparam + @intparam \
         select @floatparam = @floatparam + @intparam \
@@ -103,7 +136,8 @@ main(int argc, char *argv[])
         select @dateparam = getdate() \
         select @charparam = \'The char parameters\' \
         select @binaryparam = @binaryparam \
-        print \'This is the message printed out by sample_rpc.\'");
+        print \'This is the message printed out by sample_rpc.\'",
+		uni_type ? ", @uniparam" : "");
 
 	ret = run_command(cmd, cmdbuf);
 
@@ -185,6 +219,21 @@ main(int argc, char *argv[])
 		return 1;
 	}
 
+	if (uni_type) {
+		memset(&datafmt, 0, sizeof(datafmt));
+		strcpy(datafmt.name, "@uniparam");
+		datafmt.namelen = CS_NULLTERM;
+		datafmt.datatype = CS_UNICHAR_TYPE;
+		datafmt.maxlength = sizeof(uni_data)-2;
+		datafmt.status = CS_INPUTVALUE;
+		datafmt.locale = NULL;
+
+		if ((ret = ct_param(cmd, &datafmt, (CS_VOID *) uni_data, sizeof(uni_data)-2, 0)) != CS_SUCCEED) {
+			fprintf(stderr, "ct_param(int) failed");
+			return 1;
+		}
+	}
+
 	strcpy(datafmt.name, "@sintparam");
 	datafmt.namelen = CS_NULLTERM;
 	datafmt.datatype = CS_SMALLINT_TYPE;
Index: freetds83/src/ctlib/unittests/t0008.c
===================================================================
--- freetds83.orig/src/ctlib/unittests/t0008.c
+++ freetds83/src/ctlib/unittests/t0008.c
@@ -109,8 +109,8 @@ main(int argc, char **argv)
 	}
 	clientmsg_cb_invoked = 0;
 	ret = run_command(cmd, ".");
-	if (ret != CS_SUCCEED) {
-		fprintf(stderr, "run_command() failed\n");
+	if (ret != CS_FAIL) {
+		fprintf(stderr, "run_command() suceeded\n");
 		return 1;
 	}
 	if (clientmsg_cb_invoked) {
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.