summaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2009-06-04 18:33:08 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2009-06-04 18:33:08 +0000
commit76d4abf2d974ffa578ddc7ff40984cc05c1d48b1 (patch)
treec3f8bab555f06d141026d34df4c7402f279f8ab8 /src/backend
parentfd416db406f9efdbbdbd7b63ea4f9ccf47eec8b3 (diff)
downloadpostgresql-76d4abf2d974ffa578ddc7ff40984cc05c1d48b1.tar.gz
Improve the recently-added support for properly pluralized error messages
by extending the ereport() API to cater for pluralization directly. This is better than the original method of calling ngettext outside the elog.c code because (1) it avoids double translation, which wastes cycles and in the worst case could give a wrong result; and (2) it avoids having to use a different coding method in PL code than in the core backend. The client-side uses of ngettext are not touched since neither of these concerns is very pressing in the client environment. Per my proposal of yesterday.
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/catalog/dependency.c10
-rw-r--r--src/backend/catalog/pg_proc.c10
-rw-r--r--src/backend/catalog/pg_shdepend.c7
-rw-r--r--src/backend/executor/execQual.c27
-rw-r--r--src/backend/nls.mk4
-rw-r--r--src/backend/parser/parse_func.c42
-rw-r--r--src/backend/postmaster/bgwriter.c10
-rw-r--r--src/backend/utils/error/elog.c89
8 files changed, 145 insertions, 54 deletions
diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c
index 957cac49f3..377ae8b712 100644
--- a/src/backend/catalog/dependency.c
+++ b/src/backend/catalog/dependency.c
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/catalog/dependency.c,v 1.87 2009/03/26 22:26:06 petere Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/dependency.c,v 1.88 2009/06/04 18:33:06 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -914,10 +914,10 @@ reportDependentObjects(const ObjectAddresses *targetObjects,
{
ereport(msglevel,
/* translator: %d always has a value larger than 1 */
- (errmsg(ngettext("drop cascades to %d other object",
- "drop cascades to %d other objects",
- numReportedClient + numNotReportedClient),
- numReportedClient + numNotReportedClient),
+ (errmsg_plural("drop cascades to %d other object",
+ "drop cascades to %d other objects",
+ numReportedClient + numNotReportedClient,
+ numReportedClient + numNotReportedClient),
errdetail("%s", clientdetail.data),
errdetail_log("%s", logdetail.data)));
}
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index ad9539234f..ce42910e78 100644
--- a/src/backend/catalog/pg_proc.c
+++ b/src/backend/catalog/pg_proc.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/catalog/pg_proc.c,v 1.162 2009/03/26 22:26:06 petere Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/pg_proc.c,v 1.163 2009/06/04 18:33:06 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -112,10 +112,10 @@ ProcedureCreate(const char *procedureName,
if (parameterCount < 0 || parameterCount > FUNC_MAX_ARGS)
ereport(ERROR,
(errcode(ERRCODE_TOO_MANY_ARGUMENTS),
- errmsg(ngettext("functions cannot have more than %d argument",
- "functions cannot have more than %d arguments",
- FUNC_MAX_ARGS),
- FUNC_MAX_ARGS)));
+ errmsg_plural("functions cannot have more than %d argument",
+ "functions cannot have more than %d arguments",
+ FUNC_MAX_ARGS,
+ FUNC_MAX_ARGS)));
/* note: the above is correct, we do NOT count output arguments */
if (allParameterTypes != PointerGetDatum(NULL))
diff --git a/src/backend/catalog/pg_shdepend.c b/src/backend/catalog/pg_shdepend.c
index a4de276b8d..19cfe08f4f 100644
--- a/src/backend/catalog/pg_shdepend.c
+++ b/src/backend/catalog/pg_shdepend.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/catalog/pg_shdepend.c,v 1.32 2009/03/26 22:26:06 petere Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/pg_shdepend.c,v 1.33 2009/06/04 18:33:06 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1049,7 +1049,10 @@ storeObjectDescription(StringInfo descs, objectType type,
case REMOTE_OBJECT:
/* translator: %s will always be "database %s" */
- appendStringInfo(descs, ngettext("%d object in %s", "%d objects in %s", count), count, objdesc);
+ appendStringInfo(descs, ngettext("%d object in %s",
+ "%d objects in %s",
+ count),
+ count, objdesc);
break;
default:
diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c
index d9cbb1d763..c7bfe7c76c 100644
--- a/src/backend/executor/execQual.c
+++ b/src/backend/executor/execQual.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.246 2009/04/08 21:51:38 petere Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.247 2009/06/04 18:33:07 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -616,10 +616,11 @@ ExecEvalVar(ExprState *exprstate, ExprContext *econtext,
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("table row type and query-specified row type do not match"),
- errdetail(ngettext("Table row contains %d attribute, but query expects %d.",
- "Table row contains %d attributes, but query expects %d.",
- slot_tupdesc->natts),
- slot_tupdesc->natts, var_tupdesc->natts)));
+ errdetail_plural("Table row contains %d attribute, but query expects %d.",
+ "Table row contains %d attributes, but query expects %d.",
+ slot_tupdesc->natts,
+ slot_tupdesc->natts,
+ var_tupdesc->natts)));
else if (var_tupdesc->natts < slot_tupdesc->natts)
needslow = true;
@@ -1043,10 +1044,10 @@ init_fcache(Oid foid, FuncExprState *fcache,
if (list_length(fcache->args) > FUNC_MAX_ARGS)
ereport(ERROR,
(errcode(ERRCODE_TOO_MANY_ARGUMENTS),
- errmsg(ngettext("cannot pass more than %d argument to a function",
- "cannot pass more than %d arguments to a function",
- FUNC_MAX_ARGS),
- FUNC_MAX_ARGS)));
+ errmsg_plural("cannot pass more than %d argument to a function",
+ "cannot pass more than %d arguments to a function",
+ FUNC_MAX_ARGS,
+ FUNC_MAX_ARGS)));
/* Set up the primary fmgr lookup information */
fmgr_info_cxt(foid, &(fcache->func), fcacheCxt);
@@ -1314,10 +1315,10 @@ tupledesc_match(TupleDesc dst_tupdesc, TupleDesc src_tupdesc)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("function return row and query-specified return row do not match"),
- errdetail(ngettext("Returned row contains %d attribute, but query expects %d.",
- "Returned row contains %d attributes, but query expects %d.",
- src_tupdesc->natts),
- src_tupdesc->natts, dst_tupdesc->natts)));
+ errdetail_plural("Returned row contains %d attribute, but query expects %d.",
+ "Returned row contains %d attributes, but query expects %d.",
+ src_tupdesc->natts,
+ src_tupdesc->natts, dst_tupdesc->natts)));
for (i = 0; i < dst_tupdesc->natts; i++)
{
diff --git a/src/backend/nls.mk b/src/backend/nls.mk
index 8e66d2d199..3a79ca5048 100644
--- a/src/backend/nls.mk
+++ b/src/backend/nls.mk
@@ -1,8 +1,8 @@
-# $PostgreSQL: pgsql/src/backend/nls.mk,v 1.25 2009/05/14 21:41:50 alvherre Exp $
+# $PostgreSQL: pgsql/src/backend/nls.mk,v 1.26 2009/06/04 18:33:07 tgl Exp $
CATALOG_NAME := postgres
AVAIL_LANGUAGES := af cs de es fr hr hu it ja ko nb nl pt_BR ro ru sk sl sv tr zh_CN zh_TW pl
GETTEXT_FILES := + gettext-files
-GETTEXT_TRIGGERS:= _ errmsg errdetail errdetail_log errhint errcontext write_stderr yyerror
+GETTEXT_TRIGGERS:= _ errmsg errmsg_plural:1,2 errdetail errdetail_log errdetail_plural:1,2 errhint errcontext write_stderr yyerror
gettext-files: distprep
find $(srcdir)/ $(srcdir)/../port/ -name '*.c' -print >$@
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index 38008b9cea..260f74d595 100644
--- a/src/backend/parser/parse_func.c
+++ b/src/backend/parser/parse_func.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.214 2009/05/12 00:56:05 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.215 2009/06/04 18:33:07 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -85,10 +85,10 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
if (list_length(fargs) > FUNC_MAX_ARGS)
ereport(ERROR,
(errcode(ERRCODE_TOO_MANY_ARGUMENTS),
- errmsg(ngettext("cannot pass more than %d argument to a function",
- "cannot pass more than %d arguments to a function",
- FUNC_MAX_ARGS),
- FUNC_MAX_ARGS),
+ errmsg_plural("cannot pass more than %d argument to a function",
+ "cannot pass more than %d arguments to a function",
+ FUNC_MAX_ARGS,
+ FUNC_MAX_ARGS),
parser_errposition(pstate, location)));
/*
@@ -257,10 +257,10 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
if (nargsplusdefs >= FUNC_MAX_ARGS)
ereport(ERROR,
(errcode(ERRCODE_TOO_MANY_ARGUMENTS),
- errmsg(ngettext("cannot pass more than %d argument to a function",
- "cannot pass more than %d arguments to a function",
- FUNC_MAX_ARGS),
- FUNC_MAX_ARGS),
+ errmsg_plural("cannot pass more than %d argument to a function",
+ "cannot pass more than %d arguments to a function",
+ FUNC_MAX_ARGS,
+ FUNC_MAX_ARGS),
parser_errposition(pstate, location)));
actual_arg_types[nargsplusdefs++] = exprType(expr);
@@ -538,10 +538,10 @@ func_select_candidate(int nargs,
if (nargs > FUNC_MAX_ARGS)
ereport(ERROR,
(errcode(ERRCODE_TOO_MANY_ARGUMENTS),
- errmsg(ngettext("cannot pass more than %d argument to a function",
- "cannot pass more than %d arguments to a function",
- FUNC_MAX_ARGS),
- FUNC_MAX_ARGS)));
+ errmsg_plural("cannot pass more than %d argument to a function",
+ "cannot pass more than %d arguments to a function",
+ FUNC_MAX_ARGS,
+ FUNC_MAX_ARGS)));
/*
* If any input types are domains, reduce them to their base types. This
@@ -1332,10 +1332,10 @@ LookupFuncNameTypeNames(List *funcname, List *argtypes, bool noError)
if (argcount > FUNC_MAX_ARGS)
ereport(ERROR,
(errcode(ERRCODE_TOO_MANY_ARGUMENTS),
- errmsg(ngettext("functions cannot have more than %d argument",
- "functions cannot have more than %d arguments",
- FUNC_MAX_ARGS),
- FUNC_MAX_ARGS)));
+ errmsg_plural("functions cannot have more than %d argument",
+ "functions cannot have more than %d arguments",
+ FUNC_MAX_ARGS,
+ FUNC_MAX_ARGS)));
args_item = list_head(argtypes);
for (i = 0; i < argcount; i++)
@@ -1372,10 +1372,10 @@ LookupAggNameTypeNames(List *aggname, List *argtypes, bool noError)
if (argcount > FUNC_MAX_ARGS)
ereport(ERROR,
(errcode(ERRCODE_TOO_MANY_ARGUMENTS),
- errmsg(ngettext("functions cannot have more than %d argument",
- "functions cannot have more than %d arguments",
- FUNC_MAX_ARGS),
- FUNC_MAX_ARGS)));
+ errmsg_plural("functions cannot have more than %d argument",
+ "functions cannot have more than %d arguments",
+ FUNC_MAX_ARGS,
+ FUNC_MAX_ARGS)));
i = 0;
foreach(lc, argtypes)
diff --git a/src/backend/postmaster/bgwriter.c b/src/backend/postmaster/bgwriter.c
index 7a23c0130d..b2a90528b6 100644
--- a/src/backend/postmaster/bgwriter.c
+++ b/src/backend/postmaster/bgwriter.c
@@ -37,7 +37,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/postmaster/bgwriter.c,v 1.58 2009/05/15 15:56:39 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/postmaster/bgwriter.c,v 1.59 2009/06/04 18:33:07 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -459,10 +459,10 @@ BackgroundWriterMain(void)
(flags & CHECKPOINT_CAUSE_XLOG) &&
elapsed_secs < CheckPointWarning)
ereport(LOG,
- (errmsg(ngettext("checkpoints are occurring too frequently (%d second apart)",
- "checkpoints are occurring too frequently (%d seconds apart)",
- elapsed_secs),
- elapsed_secs),
+ (errmsg_plural("checkpoints are occurring too frequently (%d second apart)",
+ "checkpoints are occurring too frequently (%d seconds apart)",
+ elapsed_secs,
+ elapsed_secs),
errhint("Consider increasing the configuration parameter \"checkpoint_segments\".")));
/*
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index 0439c4c1d1..d93aaeb54d 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -42,7 +42,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/error/elog.c,v 1.213 2009/03/02 21:18:43 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/error/elog.c,v 1.214 2009/06/04 18:33:07 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -681,6 +681,47 @@ errcode_for_socket_access(void)
pfree(buf.data); \
}
+/*
+ * Same as above, except for pluralized error messages. The calling routine
+ * must be declared like "const char *fmt_singular, const char *fmt_plural,
+ * unsigned long n, ...". Translation is assumed always wanted.
+ */
+#define EVALUATE_MESSAGE_PLURAL(targetfield, appendval) \
+ { \
+ const char *fmt; \
+ char *fmtbuf; \
+ StringInfoData buf; \
+ /* Internationalize the error format string */ \
+ if (!in_error_recursion_trouble()) \
+ fmt = dngettext(edata->domain, fmt_singular, fmt_plural, n); \
+ else \
+ fmt = (n == 1 ? fmt_singular : fmt_plural); \
+ /* Expand %m in format string */ \
+ fmtbuf = expand_fmt_string(fmt, edata); \
+ initStringInfo(&buf); \
+ if ((appendval) && edata->targetfield) \
+ appendStringInfo(&buf, "%s\n", edata->targetfield); \
+ /* Generate actual output --- have to use appendStringInfoVA */ \
+ for (;;) \
+ { \
+ va_list args; \
+ bool success; \
+ va_start(args, n); \
+ success = appendStringInfoVA(&buf, fmtbuf, args); \
+ va_end(args); \
+ if (success) \
+ break; \
+ enlargeStringInfo(&buf, buf.maxlen); \
+ } \
+ /* Done with expanded fmt */ \
+ pfree(fmtbuf); \
+ /* Save the completed message into the stack item */ \
+ if (edata->targetfield) \
+ pfree(edata->targetfield); \
+ edata->targetfield = pstrdup(buf.data); \
+ pfree(buf.data); \
+ }
+
/*
* errmsg --- add a primary error message text to the current error
@@ -739,6 +780,29 @@ errmsg_internal(const char *fmt,...)
/*
+ * errmsg_plural --- add a primary error message text to the current error,
+ * with support for pluralization of the message text
+ */
+int
+errmsg_plural(const char *fmt_singular, const char *fmt_plural,
+ unsigned long n, ...)
+{
+ ErrorData *edata = &errordata[errordata_stack_depth];
+ MemoryContext oldcontext;
+
+ recursion_depth++;
+ CHECK_STACK_DEPTH();
+ oldcontext = MemoryContextSwitchTo(ErrorContext);
+
+ EVALUATE_MESSAGE_PLURAL(message, false);
+
+ MemoryContextSwitchTo(oldcontext);
+ recursion_depth--;
+ return 0; /* return value does not matter */
+}
+
+
+/*
* errdetail --- add a detail error message text to the current error
*/
int
@@ -781,6 +845,29 @@ errdetail_log(const char *fmt,...)
/*
+ * errdetail_plural --- add a detail error message text to the current error,
+ * with support for pluralization of the message text
+ */
+int
+errdetail_plural(const char *fmt_singular, const char *fmt_plural,
+ unsigned long n, ...)
+{
+ ErrorData *edata = &errordata[errordata_stack_depth];
+ MemoryContext oldcontext;
+
+ recursion_depth++;
+ CHECK_STACK_DEPTH();
+ oldcontext = MemoryContextSwitchTo(ErrorContext);
+
+ EVALUATE_MESSAGE_PLURAL(detail, false);
+
+ MemoryContextSwitchTo(oldcontext);
+ recursion_depth--;
+ return 0; /* return value does not matter */
+}
+
+
+/*
* errhint --- add a hint error message text to the current error
*/
int