]> granicus.if.org Git - postgresql/commitdiff
TODO item:
authorTatsuo Ishii <ishii@postgresql.org>
Sun, 15 Jul 2001 11:07:37 +0000 (11:07 +0000)
committerTatsuo Ishii <ishii@postgresql.org>
Sun, 15 Jul 2001 11:07:37 +0000 (11:07 +0000)
* Make n of CHAR(n)/VARCHAR(n) the number of letters, not bytes

src/backend/utils/adt/varchar.c
src/backend/utils/mb/mbutils.c
src/include/mb/pg_wchar.h

index d70a256dfd1a42a3f3cbb19bdb668c919ca975bd..38b26173ad23d5230cfb8e081bc6ea764a0822e2 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/adt/varchar.c,v 1.80 2001/06/09 23:21:55 petere Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/utils/adt/varchar.c,v 1.81 2001/07/15 11:07:37 ishii Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -73,26 +73,48 @@ bpcharin(PG_FUNCTION_ARGS)
        char       *r;
        size_t          len, maxlen;
        int                     i;
+#ifdef MULTIBYTE
+       int     charlen;        /* number of charcters in the input string */
+#endif
 
        len = strlen(s);
+#ifdef MULTIBYTE
+       charlen = pg_mbstrlen(s);
+#endif
 
        /* If typmod is -1 (or invalid), use the actual string length */
        if (atttypmod < (int32) VARHDRSZ)
+#ifdef MULTIBYTE
+               maxlen = charlen;
+#else
                maxlen = len;
+#endif
        else
                maxlen = atttypmod - VARHDRSZ;
 
+#ifdef MULTIBYTE
+       if (charlen > maxlen)
+#else
        if (len > maxlen)
+#endif
        {
                /* Verify that extra characters are spaces, and clip them off */
 #ifdef MULTIBYTE
-               size_t mbmaxlen = pg_mbcliplen(s, len, maxlen);
-
+               size_t mbmaxlen = pg_mbcharcliplen(s, len, maxlen);
+               /*
+                * at this point, len is the actual BYTE length of the
+                * input string, maxlen is the max number of
+                * CHARACTERS allowed for this bpchar type. 
+                */
                if (strspn(s + mbmaxlen, " ") == len - mbmaxlen)
                        len = mbmaxlen;
                else
                        elog(ERROR, "value too long for type character(%d)", maxlen);
-               Assert(len <= maxlen);
+               /*
+                * XXX: at this point, maxlen is the necessary byte
+                * length, not the number of CHARACTERS!
+                */
+               maxlen = len;
 #else
                if (strspn(s + maxlen, " ") == len - maxlen)
                        len = maxlen;
@@ -100,6 +122,16 @@ bpcharin(PG_FUNCTION_ARGS)
                        elog(ERROR, "value too long for type character(%d)", maxlen);
 #endif
        }
+#ifdef MULTIBYTE
+       else
+       {
+               /*
+                * XXX: at this point, maxlen is the necessary byte
+                * length, not the number of CHARACTERS!
+                */
+               maxlen = len + (maxlen - charlen);
+       }
+#endif
 
        result = palloc(maxlen + VARHDRSZ);
        VARATT_SIZEP(result) = maxlen + VARHDRSZ;
@@ -158,19 +190,29 @@ bpchar(PG_FUNCTION_ARGS)
        char       *r;
        char       *s;
        int                     i;
+#ifdef MULTIBYTE
+       int     charlen;        /* number of charcters in the input string 
+                                + VARHDRSZ*/
+#endif
 
        len = VARSIZE(source);
+#ifdef MULTIBYTE
+       charlen = pg_mbstrlen_with_len(VARDATA(source), len - VARHDRSZ) + VARHDRSZ;
+#endif
        /* No work if typmod is invalid or supplied data matches it already */
        if (maxlen < (int32) VARHDRSZ || len == maxlen)
                PG_RETURN_BPCHAR_P(source);
-
+#ifdef MULTIBYTE
+       if (charlen > maxlen)
+#else
        if (len > maxlen)
+#endif
        {
                /* Verify that extra characters are spaces, and clip them off */
 #ifdef MULTIBYTE
                size_t          maxmblen;
 
-               maxmblen = pg_mbcliplen(VARDATA(source), len - VARHDRSZ,
+               maxmblen = pg_mbcharcliplen(VARDATA(source), len - VARHDRSZ,
                                                                maxlen - VARHDRSZ) + VARHDRSZ;
 
                for (i = maxmblen - VARHDRSZ; i < len - VARHDRSZ; i++)
@@ -179,7 +221,11 @@ bpchar(PG_FUNCTION_ARGS)
                                         maxlen - VARHDRSZ);
 
                len = maxmblen;
-               Assert(len <= maxlen);
+               /*
+                * XXX: at this point, maxlen is the necessary byte
+                * length+VARHDRSZ, not the number of CHARACTERS!
+                */
+               maxlen = len;
 #else
                for (i = maxlen - VARHDRSZ; i < len - VARHDRSZ; i++)
                        if (*(VARDATA(source) + i) != ' ')
@@ -189,6 +235,16 @@ bpchar(PG_FUNCTION_ARGS)
                len = maxlen;
 #endif
        }
+#ifdef MULTIBYTE
+       else
+       {
+               /*
+                * XXX: at this point, maxlen is the necessary byte
+                * length+VARHDRSZ, not the number of CHARACTERS!
+                */
+               maxlen = len + (maxlen - charlen);
+       }
+#endif
 
        s = VARDATA(source);
 
@@ -333,9 +389,12 @@ name_bpchar(PG_FUNCTION_ARGS)
  * Convert a C string to VARCHAR internal representation.  atttypmod
  * is the declared length of the type plus VARHDRSZ.
  *
- * If the C string is too long, raise an error, unless the extra
- * characters are spaces, in which case they're truncated.  (per SQL)
- */
+ * Note that if MULTIBYTE is enabled, atttypmod is regarded as the
+ * number of characters, rather than number of bytes.
+ *
+ * If the C string is too long,
+ * raise an error, unless the extra characters are spaces, in which
+ * case they're truncated.  (per SQL) */
 Datum
 varcharin(PG_FUNCTION_ARGS)
 {
@@ -354,7 +413,7 @@ varcharin(PG_FUNCTION_ARGS)
        {
                /* Verify that extra characters are spaces, and clip them off */
 #ifdef MULTIBYTE
-               size_t mbmaxlen = pg_mbcliplen(s, len, maxlen);
+               size_t mbmaxlen = pg_mbcharcliplen(s, len, maxlen);
 
                if (strspn(s + mbmaxlen, " ") == len - mbmaxlen)
                        len = mbmaxlen;
@@ -428,7 +487,7 @@ varchar(PG_FUNCTION_ARGS)
                size_t          maxmblen;
 
                /* truncate multi-byte string preserving multi-byte boundary */
-               maxmblen = pg_mbcliplen(VARDATA(source), len - VARHDRSZ,
+               maxmblen = pg_mbcharcliplen(VARDATA(source), len - VARHDRSZ,
                                                                maxlen - VARHDRSZ) + VARHDRSZ;
 
                for (i = maxmblen - VARHDRSZ; i < len - VARHDRSZ; i++)
@@ -515,22 +574,9 @@ bpcharlen(PG_FUNCTION_ARGS)
        BpChar     *arg = PG_GETARG_BPCHAR_P(0);
 
 #ifdef MULTIBYTE
-       unsigned char *s;
-       int                     len,
-                               l,
-                               wl;
-
-       l = VARSIZE(arg) - VARHDRSZ;
-       len = 0;
-       s = VARDATA(arg);
-       while (l > 0)
-       {
-               wl = pg_mblen(s);
-               l -= wl;
-               s += wl;
-               len++;
-       }
-       PG_RETURN_INT32(len);
+       PG_RETURN_INT32(
+               pg_mbstrlen_with_len(VARDATA(arg), VARSIZE(arg) - VARHDRSZ)
+           );
 #else
        PG_RETURN_INT32(VARSIZE(arg) - VARHDRSZ);
 #endif
@@ -736,22 +782,9 @@ varcharlen(PG_FUNCTION_ARGS)
        VarChar    *arg = PG_GETARG_VARCHAR_P(0);
 
 #ifdef MULTIBYTE
-       unsigned char *s;
-       int                     len,
-                               l,
-                               wl;
-
-       len = 0;
-       s = VARDATA(arg);
-       l = VARSIZE(arg) - VARHDRSZ;
-       while (l > 0)
-       {
-               wl = pg_mblen(s);
-               l -= wl;
-               s += wl;
-               len++;
-       }
-       PG_RETURN_INT32(len);
+       PG_RETURN_INT32(
+               pg_mbstrlen_with_len(VARDATA(arg), VARSIZE(arg) - VARHDRSZ)
+           );
 #else
        PG_RETURN_INT32(VARSIZE(arg) - VARHDRSZ);
 #endif
index c355bf1e41424d22e91064293355e920bc6d2f2b..7b5262da6c4eaf6c00866d69636520e919031005 100644 (file)
@@ -3,7 +3,7 @@
  * client encoding and server internal encoding.
  * (currently mule internal code (mic) is used)
  * Tatsuo Ishii
- * $Id: mbutils.c,v 1.17 2001/04/16 02:42:01 tgl Exp $
+ * $Id: mbutils.c,v 1.18 2001/07/15 11:07:36 ishii Exp $
  */
 #include "postgres.h"
 
@@ -241,9 +241,9 @@ pg_mbstrlen_with_len(const unsigned char *mbstr, int limit)
 }
 
 /*
- * returns the length of a multi-byte string
+ * returns the byte length of a multi-byte string
  * (not necessarily  NULL terminated)
- * that is not longer than limit.
+ * that is no longer than limit.
  * this function does not break multi-byte word boundary.
  */
 int
@@ -267,8 +267,30 @@ pg_mbcliplen(const unsigned char *mbstr, int len, int limit)
 }
 
 /*
- * functions for utils/init
- */
+ * Similar to pg_mbcliplen but the limit parameter specifies the
+ * character length, not the byte length.  */
+int
+pg_mbcharcliplen(const unsigned char *mbstr, int len, int limit)
+{
+       int                     clen = 0;
+       int                     nch = 0;
+       int                     l;
+
+       while (len > 0 && *mbstr)
+       {
+               l = pg_mblen(mbstr);
+               nch++;
+               if (nch > limit)
+                       break;
+               clen += l;
+               len -= l;
+               mbstr += l;
+       }
+       return (clen);
+}
+
+/*
+ * functions for utils/init */
 static int     DatabaseEncoding = MULTIBYTE;
 
 void
index a95203f108b873a26eb93c706bbbe2606990306c..a51aefa27d5870fe54ba903576a105cf307d5a2f 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: pg_wchar.h,v 1.26 2001/05/03 21:38:44 momjian Exp $ */
+/* $Id: pg_wchar.h,v 1.27 2001/07/15 11:07:37 ishii Exp $ */
 
 #ifndef PG_WCHAR_H
 #define PG_WCHAR_H
@@ -136,6 +136,7 @@ extern int  pg_mic_mblen(const unsigned char *);
 extern int     pg_mbstrlen(const unsigned char *);
 extern int     pg_mbstrlen_with_len(const unsigned char *, int);
 extern int     pg_mbcliplen(const unsigned char *, int, int);
+extern int     pg_mbcharcliplen(const unsigned char *, int, int);
 extern pg_encoding_conv_tbl *pg_get_encent_by_encoding(int);
 extern int     pg_set_client_encoding(int);
 extern int     pg_get_client_encoding(void);