Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Don't downcase non-ascii identifier chars in multi-byte encodings.
authorAndrew Dunstan <andrew@dunslane.net>
Sat, 8 Jun 2013 14:20:54 +0000 (10:20 -0400)
committerAndrew Dunstan <andrew@dunslane.net>
Sat, 8 Jun 2013 14:20:54 +0000 (10:20 -0400)
Long-standing code has called tolower() on identifier character bytes
with the high bit set. This is clearly an error and produces junk output
when the encoding is multi-byte. This patch therefore restricts this
activity to cases where there is a character with the high bit set AND
the encoding is single-byte.

There have been numerous gripes about this, most recently from Martin
Schäfer.

Backpatch to all live releases.

src/backend/parser/scansup.c

index c6ac203f86c18d1f3e132de0e9b121bdc1bc949e..1586da6d94b66125f697f90803ed7663e0ea9fcf 100644 (file)
@@ -130,8 +130,10 @@ downcase_truncate_identifier(const char *ident, int len, bool warn)
 {
    char       *result;
    int         i;
+   bool        enc_is_single_byte;
 
    result = palloc(len + 1);
+   enc_is_single_byte = pg_database_encoding_max_length() == 1;
 
    /*
     * SQL99 specifies Unicode-aware case normalization, which we don't yet
@@ -139,8 +141,8 @@ downcase_truncate_identifier(const char *ident, int len, bool warn)
     * locale-aware translation.  However, there are some locales where this
     * is not right either (eg, Turkish may do strange things with 'i' and
     * 'I').  Our current compromise is to use tolower() for characters with
-    * the high bit set, and use an ASCII-only downcasing for 7-bit
-    * characters.
+    * the high bit set, as long as they aren't part of a multi-byte character,
+    * and use an ASCII-only downcasing for 7-bit characters.
     */
    for (i = 0; i < len; i++)
    {
@@ -148,7 +150,7 @@ downcase_truncate_identifier(const char *ident, int len, bool warn)
 
        if (ch >= 'A' && ch <= 'Z')
            ch += 'a' - 'A';
-       else if (IS_HIGHBIT_SET(ch) && isupper(ch))
+       else if (enc_is_single_byte && IS_HIGHBIT_SET(ch) && isupper(ch))
            ch = tolower(ch);
        result[i] = (char) ch;
    }