[freetds] Internationalization of FreeTDS

Hi-Ho jbaba at amy.hi-ho.ne.jp
Tue Jul 1 14:09:43 EDT 2003


I'm new here, so please excuse me if I'm missing something.

I am Japanese.
I think, the functions of ICONV of FreeTDS is wonderful!
But, there are several problems, to treat Japanese by using FreeTDS.

There are 2 facts.

(1) "server charset" is not necessarily "singlebyte".
(2) "server charset" and "client charset" are not necessarily same.

e.g.
   Client charset = EUC-JP
   Server charset = CP932
   Of course, UCS2 is used with TDS7.0/8.0.

I present some patches.(base of freetds-0.62.dev.20030630)
I tested it by using MS SQLServer2000 by TDS4.2 and TDS7.0.

Please reflect it, if you are thought as usefulness.

Jiro Baba

diff -u -r freetds-0.62.dev.20030630/include/tds.h
freetds-0.62.dev.patch/include/tds.h
--- freetds-0.62.dev.20030630/include/tds.h 2003-06-25 06:07:14.000000000
+0900
+++ freetds-0.62.dev.patch/include/tds.h 2003-07-01 10:15:39.000000000 +0900
@@ -997,6 +997,8 @@
 void tds_iconv_open(TDSSOCKET *tds, char *charset);
 void tds_iconv_close(TDSSOCKET *tds);
 void tds7_srv_charset_changed(TDSSOCKET * tds, int lcid);
+int tds_iconv_info_init(TDSICONVINFO * iconv_info, const char *client_name,
const char *server_name);
+int tds_charset_name_compare(const char *name1, const char *name2);

 /* threadsafe.c */
 char *tds_timestamp_str(char *str, int maxlen);
@@ -1151,6 +1153,8 @@
 /** Calc a version number for Sybase. */
 #define TDS_SYB_VER(maj,min,x) (((maj)<<24)|((min)<<16)|(x)<<8)

+#define IS_TDSENVCHARSET(x)
((x)->iconv_info[client2server_singlebyte].to_wire!=(iconv_t)-1)
+
 #ifdef __cplusplus
 }
 #endif
diff -u -r freetds-0.62.dev.20030630/src/tds/iconv.c
freetds-0.62.dev.patch/src/tds/iconv.c
--- freetds-0.62.dev.20030630/src/tds/iconv.c 2003-06-10 16:22:24.000000000
+0900
+++ freetds-0.62.dev.patch/src/tds/iconv.c 2003-07-01 10:23:14.000000000
+0900
@@ -56,8 +56,6 @@
 static int bytes_per_char(TDS_ENCODING * charset);
 static const char *lcid2charset(int lcid);
 static int skip_one_input_sequence(iconv_t cd, const TDS_ENCODING *
charset, ICONV_CONST char **input, size_t * input_size);
-static int tds_charset_name_compare(const char *name1, const char *name2);
-static int tds_iconv_info_init(TDSICONVINFO * iconv_info, const char
*client_name, const char *server_name);
 static int tds_iconv_init(void);
 static int tds_canonical_charset(const char *charset_name);

@@ -334,7 +332,7 @@
  * \remarks The charset names written to \a iconv_info will be the
canonical names,
  *          not necessarily the names passed in.
  */
-static int
+int
 tds_iconv_info_init(TDSICONVINFO * iconv_info, const char *client_name,
const char *server_name)
 {
  TDS_ENCODING *client = &iconv_info->client_charset;
@@ -815,7 +813,7 @@
  * \returns strcmp(3) of the canonical names.
  * \remarks If either name cannot be looked up, there is no way to return
an error.
  */
-static int
+int
 tds_charset_name_compare(const char *name1, const char *name2)
 {
  const char *s1, *s2;
diff -u -r freetds-0.62.dev.20030630/src/tds/read.c
freetds-0.62.dev.patch/src/tds/read.c
--- freetds-0.62.dev.20030630/src/tds/read.c 2003-06-04 00:35:05.000000000
+0900
+++ freetds-0.62.dev.patch/src/tds/read.c 2003-07-01 10:28:55.000000000
+0900
@@ -263,7 +263,7 @@

  tdsdump_log(TDS_DBG_NETWORK, "tds_get_string: need %d on wire for %d to
client?\n", dest_size, string_len);

- if (IS_TDS7_PLUS(tds)) {
+ if (IS_TDS7_PLUS(tds) || IS_TDSENVCHARSET(tds)) {
   if (dest == NULL) {
    tds_get_n(tds, NULL, wire_bytes);
    TEMP_FREE;
@@ -283,8 +283,11 @@

    /* convert chunk */
    in_left = in_size;
+   if (IS_TDS7_PLUS(tds)) {
    p += tds_iconv(to_client, tds->iconv_info, temp, &in_left, p, pend - p);
-
+   } else {
+   p += tds_iconv(to_client, &tds->iconv_info[client2server_singlebyte],
temp, &in_left, p, pend - p);
+   }
    /* update for next chunk */
    wire_bytes -= in_size - in_left;
    if (in_left) {
@@ -364,7 +367,7 @@
   * conversion descriptor.  Then, with the metadata pre-established, we
just pass everything to
   * tds_iconv and let it do the Right Thing.
   */
- if (curcol->column_size != curcol->on_server.column_size) { /* TODO:
remove this test */
+ if (curcol->column_size != curcol->on_server.column_size ||
IS_TDSENVCHARSET(tds)) { /* TODO: remove this test */
   in_left = 0;
   while (wire_size > 0) {
    int in_size;
@@ -384,7 +387,11 @@
     * TDS5/UTF-8 -> use server
     * TDS5/UTF-16 -> use UTF-16
     */
+   if( IS_TDSENVCHARSET(tds) &&
is_ascii_type(curcol->on_server.column_type) ) {
+   p += tds_iconv(to_client, &tds->iconv_info[client2server_singlebyte],
temp, &in_left, p, pend - p);
+   } else {
    p += tds_iconv(to_client, tds->iconv_info, temp, &in_left, p, pend - p);
+   }
    wire_size -= in_size - in_left;

    if (in_left) {
diff -u -r freetds-0.62.dev.20030630/src/tds/token.c
freetds-0.62.dev.patch/src/tds/token.c
--- freetds-0.62.dev.20030630/src/tds/token.c 2003-06-12 05:10:58.000000000
+0900
+++ freetds-0.62.dev.patch/src/tds/token.c 2003-07-01 10:21:43.000000000
+0900
@@ -2032,6 +2032,16 @@
    free(newval);
  }

+ switch (type) {
+ case TDS_ENV_CHARSET:
+     {
+  TDSICONVINFO *iconv_info = &tds->iconv_info[client2server_singlebyte];
+  if( tds_charset_name_compare(tds->iconv_info->client_charset.name,
tds->env->charset) != 0 ) {
+   tds_iconv_info_init(iconv_info, tds->iconv_info->client_charset.name,
tds->env->charset);
+  }
+     }
+     break;
+ }
  return TDS_SUCCEED;
 }

diff -u -r freetds-0.62.dev.20030630/src/tds/write.c
freetds-0.62.dev.patch/src/tds/write.c
--- freetds-0.62.dev.20030630/src/tds/write.c 2003-06-04 00:35:06.000000000
+0900
+++ freetds-0.62.dev.patch/src/tds/write.c 2003-07-01 10:31:23.000000000
+0900
@@ -141,12 +141,16 @@

  assert(len >= 0);

- if (IS_TDS7_PLUS(tds)) {
+ if (IS_TDS7_PLUS(tds) || IS_TDSENVCHARSET(tds)) {
   eob = s + len; /* 1 past the end of the input buffer */
   while (len > 0) {
    tdsdump_log(TDS_DBG_NETWORK, "%L tds_put_string converting %d bytes of
\"%s\"\n", len, s);
    output_size = sizeof(buffer);
+   if(IS_TDS7_PLUS(tds)) {
    bytes_out = tds_iconv(to_server, tds->iconv_info, s, &len, buffer,
output_size);
+   } else {
+   bytes_out = tds_iconv(to_server,
&tds->iconv_info[client2server_singlebyte], s, &len, buffer, output_size);
+   }
    s = eob - len; /* len was reduced by number of bytes processed by
tds_iconv() */
    tds_put_n(tds, buffer, bytes_out);
   }




More information about the FreeTDS mailing list