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) {