The documentation for the functions in the fields of pg_wchar_tbl was
spread out all over the place and was missing a lot of detail. I propose the attached patch that moves the important material into the definition of the struct and also expands the details a bit, so that all the important info is in one easy to find place. Some of those details I gathered and inferred from various places, and some of those used to be more like "it works this way" where I'm now somewhat elevating it to "it is supposed to work this way", so maybe that's worth double-checking.

I'm also removing some unnecessary typedefs for those functions, except where they were used elsewhere to hold local variables. This indirection made the code documentation harder to follow. And some of those typedefs had nonsensical names, like *_converter for functions that didn't do any converting.

(I was looking for example at struct TableAmRoutine in access/tableam.h for inspiration for a well-commented callback table definition.)
From 3ebaaada53f1a04dc7e807b31ba54f420c967b42 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <[email protected]>
Date: Tue, 27 Oct 2026 14:12:49 +0100
Subject: [PATCH] Clean up code comments for pg_wchar_tbl

The documentation for the functions in the fields of pg_wchar_tbl was
spread out all over the place and was missing a lot of detail.  Move
and expand this at the definition of the struct.  (See also struct
TableAmRoutine in access/tableam.h for inspiration.)

Also remove unnecessary typedefs, except where they were used
elsewhere as well.  This indirection makes the code documentation
harder to follow.  And some of those typedefs had nonsensical names,
like *_converter for functions that didn't do any converting.
---
 src/backend/utils/mb/mbutils.c   |  10 +--
 src/common/wchar.c               |  60 +--------------
 src/include/mb/pg_wchar.h        | 125 +++++++++++++++++++++++++------
 src/tools/pgindent/typedefs.list |   8 +-
 4 files changed, 113 insertions(+), 90 deletions(-)

diff --git a/src/backend/utils/mb/mbutils.c b/src/backend/utils/mb/mbutils.c
index b57dba4ead1..bdfdd9eeace 100644
--- a/src/backend/utils/mb/mbutils.c
+++ b/src/backend/utils/mb/mbutils.c
@@ -1222,7 +1222,7 @@ int
 pg_encoding_mbcliplen(int encoding, const char *mbstr,
                                          int len, int limit)
 {
-       mblen_converter mblen_fn;
+       mblen_function mblen_fn;
        int                     clen = 0;
        int                     l;
 
@@ -1452,15 +1452,15 @@ static bool
 pg_generic_charinc(unsigned char *charptr, int len)
 {
        unsigned char *lastbyte = charptr + len - 1;
-       mbchar_verifier mbverify;
+       mbverifychar_function mbverifychar;
 
        /* We can just invoke the character verifier directly. */
-       mbverify = pg_wchar_table[GetDatabaseEncoding()].mbverifychar;
+       mbverifychar = pg_wchar_table[GetDatabaseEncoding()].mbverifychar;
 
        while (*lastbyte < (unsigned char) 255)
        {
                (*lastbyte)++;
-               if ((*mbverify) (charptr, len) == len)
+               if ((*mbverifychar) (charptr, len) == len)
                        return true;
        }
 
@@ -1723,7 +1723,7 @@ pg_verify_mbstr(int encoding, const char *mbstr, int len, 
bool noError)
 int
 pg_verify_mbstr_len(int encoding, const char *mbstr, int len, bool noError)
 {
-       mbchar_verifier mbverifychar;
+       mbverifychar_function mbverifychar;
        int                     mb_len;
 
        Assert(PG_VALID_ENCODING(encoding));
diff --git a/src/common/wchar.c b/src/common/wchar.c
index 926823cabec..23bbdbd2ae5 100644
--- a/src/common/wchar.c
+++ b/src/common/wchar.c
@@ -37,32 +37,6 @@
 #define NONUTF8_INVALID_BYTE1 (' ')
 
 
-/*
- * Operations on multi-byte encodings are driven by a table of helper
- * functions.
- *
- * To add an encoding support, define mblen(), dsplen(), verifychar() and
- * verifystr() for the encoding.  For server-encodings, also define mb2wchar()
- * and wchar2mb() conversion functions.
- *
- * These functions generally assume that their input is validly formed.
- * The "verifier" functions, further down in the file, have to be more
- * paranoid.
- *
- * We expect that mblen() does not need to examine more than the first byte
- * of the character to discover the correct length.  GB18030 is an exception
- * to that rule, though, as it also looks at second byte.  But even that
- * behaves in a predictable way, if you only pass the first byte: it will
- * treat 4-byte encoded characters as two 2-byte encoded characters, which is
- * good enough for all current uses.
- *
- * Note: for the display output of psql to work properly, the return values
- * of the dsplen functions must conform to the Unicode standard. In particular
- * the NUL character is zero width and control characters are generally
- * width -1. It is recommended that non-ASCII encodings refer their ASCII
- * subset to the ASCII routines to ensure consistency.
- */
-
 /* No error-reporting facility.  Ignore incomplete trailing byte sequence. */
 #define MB2CHAR_NEED_AT_LEAST(len, need) if ((len) < (need)) break
 
@@ -390,9 +364,6 @@ pg_euctw_dsplen(const unsigned char *s)
 
 /*
  * Convert pg_wchar to EUC_* encoding.
- * caller must allocate enough space for "to", including a trailing zero!
- * len: length of from.
- * "from" not necessarily null terminated.
  */
 static int
 pg_wchar2euc_with_len(const pg_wchar *from, unsigned char *to, int len)
@@ -454,9 +425,6 @@ pg_johab_dsplen(const unsigned char *s)
 
 /*
  * convert UTF8 string to pg_wchar (UCS-4)
- * caller must allocate enough space for "to", including a trailing zero!
- * len: length of from.
- * "from" not necessarily null terminated.
  */
 static int
 pg_utf2wchar_with_len(const unsigned char *from, pg_wchar *to, int len)
@@ -517,9 +485,6 @@ pg_utf2wchar_with_len(const unsigned char *from, pg_wchar 
*to, int len)
 
 /*
  * Trivial conversion from pg_wchar to UTF-8.
- * caller should allocate enough space for "to"
- * len: length of from.
- * "from" not necessarily null terminated.
  */
 static int
 pg_wchar2utf_with_len(const pg_wchar *from, unsigned char *to, int len)
@@ -704,9 +669,6 @@ pg_latin12wchar_with_len(const unsigned char *from, 
pg_wchar *to, int len)
 /*
  * Trivial conversion from pg_wchar to single byte encoding. Just ignores
  * high bits.
- * caller should allocate enough space for "to"
- * len: length of from.
- * "from" not necessarily null terminated.
  */
 static int
 pg_wchar2single_with_len(const pg_wchar *from, unsigned char *to, int len)
@@ -891,25 +853,9 @@ pg_gb18030_dsplen(const unsigned char *s)
 /*
  *-------------------------------------------------------------------
  * multibyte sequence validators
- *
- * The verifychar functions accept "s", a pointer to the first byte of a
- * string, and "len", the remaining length of the string.  If there is a
- * validly encoded character beginning at *s, return its length in bytes;
- * else return -1.
- *
- * The verifystr functions also accept "s", a pointer to a string and "len",
- * the length of the string.  They verify the whole string, and return the
- * number of input bytes (<= len) that are valid.  In other words, if the
- * whole string is valid, verifystr returns "len", otherwise it returns the
- * byte offset of the first invalid character.  The verifystr functions must
- * test for and reject zeroes in the input.
- *
- * The verifychar functions can assume that len > 0 and that *s != '\0', but
- * they must test for and reject zeroes in any additional bytes of a
- * multibyte character.  Note that this definition allows the function for a
- * single-byte encoding to be just "return 1".
  *-------------------------------------------------------------------
  */
+
 static int
 pg_ascii_verifychar(const unsigned char *s, int len)
 {
@@ -1982,7 +1928,7 @@ pg_encoding_dsplen(int encoding, const char *mbstr)
 
 /*
  * Verify the first multibyte character of the given string.
- * Return its byte length if good, -1 if bad.  (See comments above for
+ * Return its byte length if good, -1 if bad.  (See comments at pg_wchar_tbl 
for
  * full details of the mbverifychar API.)
  */
 int
@@ -1996,7 +1942,7 @@ pg_encoding_verifymbchar(int encoding, const char *mbstr, 
int len)
 /*
  * Verify that a string is valid for the given encoding.
  * Returns the number of input bytes (<= len) that form a valid string.
- * (See comments above for full details of the mbverifystr API.)
+ * (See comments at pg_wchar_tbl for full details of the mbverifystr API.)
  */
 int
 pg_encoding_verifymbstr(int encoding, const char *mbstr, int len)
diff --git a/src/include/mb/pg_wchar.h b/src/include/mb/pg_wchar.h
index 9f0e4223748..72d960bde6d 100644
--- a/src/include/mb/pg_wchar.h
+++ b/src/include/mb/pg_wchar.h
@@ -208,35 +208,115 @@ extern PGDLLIMPORT const char *pg_enc2gettext_tbl[];
 /*
  * pg_wchar stuff
  */
-typedef int (*mb2wchar_with_len_converter) (const unsigned char *from,
-                                                                               
        pg_wchar *to,
-                                                                               
        int len);
 
-typedef int (*wchar2mb_with_len_converter) (const pg_wchar *from,
-                                                                               
        unsigned char *to,
-                                                                               
        int len);
+typedef int (*mblen_function) (const unsigned char *mbstr);
+typedef int (*mbverifychar_function) (const unsigned char *mbstr, int len);
 
-typedef int (*mblen_converter) (const unsigned char *mbstr);
+/*
+ * Operations on multi-byte encodings are driven by a table of helper
+ * functions.
+ *
+ * All functions are required, except the conversion functions
+ * .mb2wchar_with_len and .wchar2mb_with_len, which are only required for
+ * server encodings.
+ *
+ * These functions generally assume that their input is validly formed, and
+ * unless specified otherwise have no special return value for errors.  The
+ * exceptions are the two "verify" functions, which must check their input and
+ * signal invalid input through their return value.  None of these functions
+ * report errors via ereport().
+ */
+typedef struct
+{
+       /*
+        * Convert a multibyte string to a pg_wchar string.
+        *
+        * "len" is the length of "from" in bytes (not characters).  The input
+        * string need not be zero-terminated, but conversion will stop early 
on a
+        * zero byte.  The output is written to "to".  "to" must be allocated to
+        * accommodate at least len + 1 pg_wchar's.  A terminating 0 is always
+        * written.  The return value is the number of pg_wchar's written, 
without
+        * the terminator.
+        *
+        * If a multibyte sequence at the end is cut off by len, it is silently
+        * dropped.
+        */
+       int                     (*mb2wchar_with_len) (const unsigned char 
*from, pg_wchar *to, int len);
 
-typedef int (*mbdisplaylen_converter) (const unsigned char *mbstr);
+       /*
+        * Convert a pg_wchar string to a multibyte string.
+        *
+        * "len" is the length of "from" in pg_wchar characters (not bytes).  
The
+        * input need not be terminated by a 0 pg_wchar, but conversion will 
stop
+        * early on a 0 pg_wchar.  The output is written to "to".  "to" must be
+        * allocated as len * maxmblen + 1 bytes.  A terminating 0 byte is 
always
+        * written.  The return value is the number of bytes written, without 
the
+        * terminator.
+        */
+       int                     (*wchar2mb_with_len) (const pg_wchar *from, 
unsigned char *to, int len);
 
-typedef bool (*mbcharacter_incrementer) (unsigned char *mbstr, int len);
+       /*
+        * Get byte length of the first character of the input string.
+        *
+        * If the input string has length zero, then 1 is returned.  The return
+        * value is always between 1 and maxmblen inclusive.
+        *
+        * We expect that mblen does not need to examine more than the first 
byte
+        * of the character to discover the correct length.  GB18030 is an
+        * exception; see pg_gb18030_mblen().
+        */
+       mblen_function mblen;
 
-typedef int (*mbchar_verifier) (const unsigned char *mbstr, int len);
+       /*
+        * Get the display width of the first character of the input string.
+        *
+        * The possible results are -1, 0, 1 and 2.  Control characters return 
-1;
+        * callers can handle that specially.  Unlike mblen, an empty string
+        * returns 0.  (But the converse is not true: Zero-width characters also
+        * return 0.)
+        *
+        * Note: for the display output of psql to work properly, the return
+        * values of the dsplen functions must conform to the Unicode standard. 
In
+        * particular the NUL character is zero width and control characters are
+        * generally width -1. It is recommended that non-ASCII encodings refer
+        * their ASCII subset to the ASCII routines to ensure consistency.
+        */
+       int                     (*dsplen) (const unsigned char *mbstr);
 
-typedef int (*mbstr_verifier) (const unsigned char *mbstr, int len);
+       /*
+        * Verify multibyte character.
+        *
+        * The verifychar functions accept "mbstr", a pointer to the first byte 
of
+        * a string, and "len", the remaining length of the string.  If there 
is a
+        * validly encoded character beginning at *mbstr, return its length in
+        * bytes; else return -1.
+        *
+        * The verifychar functions can assume that len > 0 and that *mbstr !=
+        * '\0', but they must test for and reject zeroes in any additional 
bytes
+        * of a multibyte character.  Note that this definition allows the
+        * function for a single-byte encoding to be just "return 1".
+        */
+       mbverifychar_function mbverifychar;
 
-typedef struct
-{
-       mb2wchar_with_len_converter mb2wchar_with_len;  /* convert a multibyte
-                                                                               
                         * string to a wchar */
-       wchar2mb_with_len_converter wchar2mb_with_len;  /* convert a wchar 
string
-                                                                               
                         * to a multibyte */
-       mblen_converter mblen;          /* get byte length of a char */
-       mbdisplaylen_converter dsplen;  /* get display width of a char */
-       mbchar_verifier mbverifychar;   /* verify multibyte character */
-       mbstr_verifier mbverifystr; /* verify multibyte string */
-       int                     maxmblen;               /* max bytes for a char 
in this encoding */
+       /*
+        * Verify multibyte string.
+        *
+        * The verifystr functions accept "mbstr", a pointer to a string and
+        * "len", the length of the string.  They verify the whole string, and
+        * return the number of input bytes (<= len) that are valid.  In other
+        * words, if the whole string is valid, verifystr returns "len", 
otherwise
+        * it returns the byte offset of the first invalid character.  The
+        * verifystr functions must test for and reject zeroes in the input.
+        */
+       int                     (*mbverifystr) (const unsigned char *mbstr, int 
len);
+
+       /*
+        * The maximum number of bytes a character in this encoding could 
occupy.
+        *
+        * This is used to size output buffers of conversion routines, so it 
must
+        * not be too small.
+        */
+       int                     maxmblen;
 } pg_wchar_tbl;
 
 extern PGDLLIMPORT const pg_wchar_tbl pg_wchar_table[];
@@ -547,6 +627,7 @@ extern int  pg_encoding_mbcliplen(int encoding, const char 
*mbstr,
                                                                  int len, int 
limit);
 extern int     pg_mbcharcliplen(const char *mbstr, int len, int limit);
 extern int     pg_database_encoding_max_length(void);
+typedef bool (*mbcharacter_incrementer) (unsigned char *mbstr, int len);
 extern mbcharacter_incrementer 
pg_database_encoding_character_incrementer(void);
 
 extern int     PrepareClientEncoding(int encoding);
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index cfef572df80..7393e27a534 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -3952,12 +3952,9 @@ manifest_wal_range
 manifest_writer
 map_variable_attnos_context
 max_parallel_hazard_context
-mb2wchar_with_len_converter
-mbchar_verifier
 mbcharacter_incrementer
-mbdisplaylen_converter
-mblen_converter
-mbstr_verifier
+mblen_function
+mbverifychar_function
 memoize_hash
 memoize_iterator
 metastring
@@ -4440,7 +4437,6 @@ walrcv_receive_fn
 walrcv_send_fn
 walrcv_server_version_fn
 walrcv_startstreaming_fn
-wchar2mb_with_len_converter
 wchar_t
 win32_deadchild_waitinfo
 wint_t
-- 
2.56.0

Reply via email to