I wrote:
> This is still not very nice because what the user would get is
> a complaint about ERRORDATA_STACK_SIZE exceeded with no hint that
> he's got an encoding problem.  It'd be better if we could get the
> disable-gettext-and-FATAL-out behavior to apply to the "character
> has no equivalent" error message, but I'm not sure how we do that
> without bollixing up less-critical occurrences of that message.

After poking around a bit I decided that this could be done in a not
horrendously ugly way if we are willing to make a couple more places
know about escaping from error recursion situations.  Attached is a
proposed patch that prevents the crash shown previously.  BTW, a better
stress test for this is to set LANG = tr_TR.utf8, client_encoding =
latin1, and then try "select E'\305\237';".  That's because the
"character has no equivalent" message isn't itself translated in the
present ko translation, but it is in the tr translation.  My first-cut
patch worked for the ko case and not the tr case :-(

One thing that is still a bit ugly about this patch is the hack in
wchar.c to ensure that the "character has no equivalent" message
doesn't get translated:

     * ...  Note that we have to
     * spell the message slightly differently, which we do by sticking a
     * space on the end --- using errmsg_internal() doesn't actually keep
     * elog.c from calling gettext, it only prevents the string from being
     * entered into the translation lists.

It might be better to modify elog.c so that errmsg_internal really
doesn't call gettext.  This would require kluging up EVALUATE_MESSAGE()
a bit, so I'm not quite sure which is cleaner.  Thoughts?

                        regards, tom lane

Index: src/backend/utils/error/elog.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/utils/error/elog.c,v
retrieving revision 1.208
diff -c -r1.208 elog.c
*** src/backend/utils/error/elog.c      17 Oct 2008 22:56:16 -0000      1.208
--- src/backend/utils/error/elog.c      27 Oct 2008 16:16:28 -0000
***************
*** 149,154 ****
--- 149,169 ----
  static void setup_formatted_log_time(void);
  static void setup_formatted_start_time(void);
  
+ 
+ /*
+  * in_error_recursion_trouble --- are we at risk of infinite error recursion?
+  *
+  * This function exists to provide common control of various fallback steps
+  * that we take if we think we are facing infinite error recursion.  See the
+  * callers for details.
+  */
+ bool
+ in_error_recursion_trouble(void)
+ {
+       /* Pull the plug if recurse more than once */
+       return (recursion_depth > 2);
+ }
+ 
  /*
   * errstart --- begin an error-reporting cycle
   *
***************
*** 261,272 ****
                MemoryContextReset(ErrorContext);
  
                /*
!                * If we recurse more than once, the problem might be something 
broken
                 * in a context traceback routine.      Abandon them too.  We 
also abandon
                 * attempting to print the error statement (which, if long, 
could
                 * itself be the source of the recursive failure).
                 */
!               if (recursion_depth > 2)
                {
                        error_context_stack = NULL;
                        debug_query_string = NULL;
--- 276,287 ----
                MemoryContextReset(ErrorContext);
  
                /*
!                * Infinite error recursion might be due to something broken
                 * in a context traceback routine.      Abandon them too.  We 
also abandon
                 * attempting to print the error statement (which, if long, 
could
                 * itself be the source of the recursive failure).
                 */
!               if (in_error_recursion_trouble())
                {
                        error_context_stack = NULL;
                        debug_query_string = NULL;
***************
*** 2408,2413 ****
--- 2423,2432 ----
  
  /*
   * error_severity --- get localized string representing elevel
+  *
+  * Note: in an error recursion situation, we stop localizing the tags
+  * for ERROR and above.  This is necessary because the problem might be
+  * failure to convert one of these strings to the client encoding.
   */
  static const char *
  error_severity(int elevel)
***************
*** 2437,2449 ****
                        prefix = _("WARNING");
                        break;
                case ERROR:
!                       prefix = _("ERROR");
                        break;
                case FATAL:
!                       prefix = _("FATAL");
                        break;
                case PANIC:
!                       prefix = _("PANIC");
                        break;
                default:
                        prefix = "???";
--- 2456,2477 ----
                        prefix = _("WARNING");
                        break;
                case ERROR:
!                       if (in_error_recursion_trouble())
!                               prefix = "ERROR";
!                       else
!                               prefix = _("ERROR");
                        break;
                case FATAL:
!                       if (in_error_recursion_trouble())
!                               prefix = "FATAL";
!                       else
!                               prefix = _("FATAL");
                        break;
                case PANIC:
!                       if (in_error_recursion_trouble())
!                               prefix = "PANIC";
!                       else
!                               prefix = _("PANIC");
                        break;
                default:
                        prefix = "???";
Index: src/backend/utils/mb/wchar.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/utils/mb/wchar.c,v
retrieving revision 1.66
diff -c -r1.66 wchar.c
*** src/backend/utils/mb/wchar.c        15 Nov 2007 21:14:40 -0000      1.66
--- src/backend/utils/mb/wchar.c        27 Oct 2008 16:16:28 -0000
***************
*** 1567,1578 ****
        for (j = 0; j < jlimit; j++)
                p += sprintf(p, "%02x", (unsigned char) mbstr[j]);
  
!       ereport(ERROR,
!                       (errcode(ERRCODE_UNTRANSLATABLE_CHARACTER),
!         errmsg("character 0x%s of encoding \"%s\" has no equivalent in 
\"%s\"",
!                        buf,
!                        pg_enc2name_tbl[src_encoding].name,
!                        pg_enc2name_tbl[dest_encoding].name)));
  }
  
  #endif
--- 1567,1595 ----
        for (j = 0; j < jlimit; j++)
                p += sprintf(p, "%02x", (unsigned char) mbstr[j]);
  
!       /*
!        * In an error recursion situation, don't try to translate the message.
!        * This gets us out of trouble if the problem is failure to convert
!        * the translated message to the client encoding.  Note that we have to
!        * spell the message slightly differently, which we do by sticking a
!        * space on the end --- using errmsg_internal() doesn't actually keep
!        * elog.c from calling gettext, it only prevents the string from being
!        * entered into the translation lists.
!        */
!       if (in_error_recursion_trouble())
!               ereport(ERROR,
!                               (errcode(ERRCODE_UNTRANSLATABLE_CHARACTER),
!                                errmsg_internal("character 0x%s of encoding 
\"%s\" has no equivalent in \"%s\" ",
!                                                                buf,
!                                                                
pg_enc2name_tbl[src_encoding].name,
!                                                                
pg_enc2name_tbl[dest_encoding].name)));
!       else
!               ereport(ERROR,
!                               (errcode(ERRCODE_UNTRANSLATABLE_CHARACTER),
!                                errmsg("character 0x%s of encoding \"%s\" has 
no equivalent in \"%s\"",
!                                               buf,
!                                               
pg_enc2name_tbl[src_encoding].name,
!                                               
pg_enc2name_tbl[dest_encoding].name)));
  }
  
  #endif
Index: src/include/utils/elog.h
===================================================================
RCS file: /cvsroot/pgsql/src/include/utils/elog.h,v
retrieving revision 1.96
diff -c -r1.96 elog.h
*** src/include/utils/elog.h    9 Oct 2008 22:22:31 -0000       1.96
--- src/include/utils/elog.h    27 Oct 2008 16:16:28 -0000
***************
*** 324,329 ****
--- 324,330 ----
  /* Other exported functions */
  extern void DebugFileOpen(void);
  extern char *unpack_sql_state(int sql_state);
+ extern bool in_error_recursion_trouble(void);
  
  #ifdef HAVE_SYSLOG
  extern void set_syslog_parameters(const char *ident, int facility);
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to