messages in a file or a module.
We now support a new --enable-genmsgids configure option. When compiled with
this, superusers can run pg_msgmodule_set(moduleid, fileid, msgid, newlevel)
command to override the log level specified in the source code.
There are many TODOs and limitations of this approach. We could only, for
example, increase logging level of messages i.e. turn DEBUG2 to DEBUG1 or DEBUG
to LOG. But we can't change ERROR to PANIC or supress a log message. Also, we
are using a very sparse representation of the message log levels. This
increases memory requirements significantly, though should speed up lookups and
keep the code simple.
When configured with --enable-genmsgids, a file named MSGMODULES is created at
the top of the build tree and the module-ids are later picked from that file
while compiling individual files. We would also preprocess each file before
compilation and save all elog() calls, along with the file_name, line_number,
messgae, module_id, file_id, msg_id in MSGIDS file. This file can then be used
to lookup the messages so that correct information is passed. This clearly
needs a lot more polishing and work.
When configued without --enable-genmsgids, we don't expect this facility to add
overhead because all codes gets #ifdef-ed out
# Garbage from autoconf:
@rm -rf autom4te.cache/
rm -f config.cache config.log config.status GNUmakefile
+ rm -f MSGIDS MSGMODULES
check check-tests installcheck installcheck-parallel installcheck-tests:
$(MAKE) -C src/test/regress $@
--- /dev/null
+#/usr/bin/env sh
+
+#
+# Run this script when configuring with --enable-genmsgids
+#
+# Recurse through all subdiectories, collecting information about all subdirs
+# which has a Makefile/GNUMakefile with "subdir = <subdir_name>" entry and
+# assign a module_id for all such subdirs. The Makefile.global then looks up
+# this catalog and uses the module_id configured.
+#
+# The script assumes that every subdir's Makefile has a specific pattern of
+# "^subdir = .*", which is thankfully true for subdirs that we care for
+#
+# We could be a lot smarter than what we are doing, especially avoiding
+# module_id assignment for subdirs which do not directly compile any files with
+# elog() messages.
+#
+MSG_MODULE=0
+handle_dir()
+{
+ MSG_MODULE=`expr $2 + 1`
+ for subdir in `ls $1`; do
+ if [ -d $1/$subdir ]; then
+ makefile1=$1/$subdir/Makefile
+ makefile2=$1/$subdir/GNUMakefile
+ if [ -f $makefile1 ]; then
+ cat $makefile1 | grep -E "^subdir = " > /dev/null
+ if [ $? -ne 0 ]; then
+ if [ -f $makefile2 ]; then
+ cat $makefile2 | grep -E "^subdir = " > /dev/null
+ if [ $? -eq 0 ]; then
+ makefile=$makefile2
+ else
+ continue
+ fi
+ else
+ continue
+ fi
+ else
+ makefile=$makefile1
+ fi
+ else
+ continue
+ fi
+ cat $makefile | grep -E "^subdir = " > /dev/null
+ if [ $? -eq 0 ]; then
+ moduledir=`cat $makefile | grep -E '^subdir = '`
+ echo $moduledir:${MSG_MODULE}
+ fi
+ handle_dir "$1/$subdir" $MSG_MODULE
+ fi
+ done
+}
+
+handle_dir "." $MSG_MODULE
enable_thread_safety
INCLUDES
autodepend
+genmsgids
TAS
GCC
CPP
with_wal_segsize
with_CC
enable_depend
+enable_genmsgids
enable_cassert
enable_thread_safety
with_tcl
fi
+#
+# Automatic msgids generation
+#
+
+
+# Check whether --enable-genmsgids was given.
+if test "${enable_genmsgids+set}" = set; then :
+ enableval=$enable_genmsgids;
+ case $enableval in
+ yes)
+
+$as_echo "#define USE_MODULE_MSGIDS 1" >>confdefs.h
+
+ genmsgids=yes
+ $srcdir/config/create_msgids.sh > MSGMODULES 2>&1
+
+ ;;
+ no)
+ :
+ ;;
+ *)
+ as_fn_error $? "no argument expected for --enable-genmsgids option" "$LINENO" 5
+ ;;
+ esac
+
+else
+ enable_genmsgids=no
+
+fi
[autodepend=yes])
AC_SUBST(autodepend)
-
#
# Enable assert checks
#
[Define to 1 to build with assertion checks. (--enable-cassert)])])
+#
+# Enable module msgids
+#
+PGAC_ARG_BOOL(enable, genmsgids, no, [enable module msgids (for debugging)],
+ [AC_DEFINE([USE_MODULE_MSGIDS], 1,
+ [Define to 1 to build with module msgids. (--enable-genmsgids)])])
+AC_SUBST(genmsgids)
+
#
# Include directories
#
PGXS := $(shell $(PG_CONFIG) --pgxs)
include $(PGXS)
else
-subdir = contrib/pgxc_clean
+subdir = contrib/pgxc_ctl
top_builddir = ../..
include $(top_builddir)/src/Makefile.global
include $(top_srcdir)/contrib/contrib-global.mk
# $3: target to run in subdir (defaults to current element of $1)
recurse_always = $(foreach target,$(if $1,$1,$(standard_always_targets)),$(foreach subdir,$(if $2,$2,$(ALWAYS_SUBDIRS)),$(eval $(call _create_recursive_target,$(target),$(subdir),$(if $3,$3,$(target))))))
-
##########################################################################
#
# Automatic dependency generation
rm -f `find . -name '*.gcda' -print`
endif # enable_coverage
+
+genmsgids = @genmsgids@
+
+ifeq ($(genmsgids), yes)
+PREPROCESS.c = $(CC) $(CFLAGS) $(CPPFLAGS) -E
+
+PGXL_MSG_FILEID := 1
+PGXL_MSG_MODULE := $(shell cat $(top_builddir)/MSGMODULES | grep -E "^subdir = $(subdir):" | cut -d ':' -f 2)
+
+ifeq ($(autodepend), yes)
+ifeq ($(GCC), yes)
+
+# GCC allows us to create object and dependency file in one invocation.
+%.o : %.c
+ @if test ! -d $(DEPDIR); then mkdir -p $(DEPDIR); fi
+ $(PREPROCESS.c) -DPGXL_MSG_MODULE=$(PGXL_MSG_MODULE) -DPGXL_MSG_FILEID=$(PGXL_MSG_FILEID) -o
[email protected] $< -MMD -MP -MF $(DEPDIR)/$(*F).Po
+ -cat
[email protected] | grep -E "do \{ if \(errstart|do \{ if \(elog_start" >> $(top_srcdir)/MSGIDS
+ $(COMPILE.c) -DPGXL_MSG_MODULE=$(PGXL_MSG_MODULE) -DPGXL_MSG_FILEID=$(PGXL_MSG_FILEID) -o $@ $< -MMD -MP -MF $(DEPDIR)/$(*F).Po
+ $(eval PGXL_MSG_FILEID := $(shell echo $(PGXL_MSG_FILEID) + 1 | bc))
+endif # GCC
+else
+ifeq ($(GCC), yes)
+%.o : %.c
+ $(PREPROCESS.c) -DPGXL_MSG_MODULE=$(PGXL_MSG_MODULE) -DPGXL_MSG_FILEID=$(PGXL_MSG_FILEID) -o
[email protected] $<
+ -cat
[email protected] | grep -E "do \{ if \(errstart|do \{ if \(elog_start" >> $(top_srcdir)/MSGIDS
+ $(COMPILE.c) -DPGXL_MSG_MODULE=$(PGXL_MSG_MODULE) -DPGXL_MSG_FILEID=$(PGXL_MSG_FILEID) -o $@ $<
+ $(eval PGXL_MSG_FILEID := $(shell echo $(PGXL_MSG_FILEID) + 1 | bc))
+endif # GCC
+
+endif # autodepend
+
+endif # enable_genmsgids
size = add_size(size, ShmemBackendArraySize());
#endif
+#ifdef USE_MODULE_MSGIDS
+ size = add_size(size, MsgModuleShmemSize());
+#endif
+
/* freeze the addin request size and include it */
addin_request_allowed = false;
size = add_size(size, total_addin_request);
ShmemBackendArrayAllocation();
#endif
+#ifdef USE_MODULE_MSGIDS
+ MsgModuleShmemInit();
+#endif
+
/* Initialize dynamic shared memory facilities. */
if (!IsUnderPostmaster)
dsm_postmaster_startup(shim);
static const char *get_errno_symbol(int errnum);
static const char *error_severity(int elevel);
static void append_with_tabs(StringInfo buf, const char *str);
-static bool is_log_level_output(int elevel, int log_min_level);
+static bool is_log_level_output(int elevel,
+#ifdef USE_MODULE_MSGIDS
+ int moduleid,
+ int fileid,
+ int msgid,
+#endif
+ int log_min_level);
static void write_pipe_chunks(char *data, int len, int dest);
static void write_csvlog(ErrorData *edata);
static void setup_formatted_log_time(void);
static void setup_formatted_start_time(void);
+#ifdef USE_MODULE_MSGIDS
+char *MsgModuleCtl;
+#endif
/*
* in_error_recursion_trouble --- are we at risk of infinite error recursion?
*/
bool
errstart(int elevel, const char *filename, int lineno,
+#ifdef USE_MODULE_MSGIDS
+ int moduleid, int fileid, int msgid,
+#endif
const char *funcname, const char *domain)
{
ErrorData *edata;
*/
/* Determine whether message is enabled for server log output */
- output_to_server = is_log_level_output(elevel, log_min_messages);
+ output_to_server = is_log_level_output(elevel,
+#ifdef USE_MODULE_MSGIDS
+ moduleid,
+ fileid,
+ msgid,
+#endif
+ log_min_messages);
/* Determine whether message is enabled for client output */
if (whereToSendOutput == DestRemote && elevel != COMMERROR)
* evaluating the format arguments if we do that.)
*/
void
-elog_start(const char *filename, int lineno, const char *funcname)
+elog_start(const char *filename, int lineno,
+#ifdef USE_MODULE_MSGIDS
+ int moduleid, int fileid, int msgid,
+#endif
+ const char *funcname)
{
ErrorData *edata;
edata->filename = filename;
edata->lineno = lineno;
edata->funcname = funcname;
+#ifdef USE_MODULE_MSGIDS
+ edata->moduleid = moduleid;
+ edata->fileid = fileid;
+ edata->msgid = msgid;
+#endif
/* errno is saved now so that error parameter eval can't change it */
edata->saved_errno = errno;
*/
errordata_stack_depth--;
errno = edata->saved_errno;
- if (!errstart(elevel, edata->filename, edata->lineno, edata->funcname, NULL))
+ if (!errstart(elevel, edata->filename, edata->lineno,
+#ifdef USE_MODULE_MSGIDS
+ edata->moduleid,
+ edata->fileid, edata->msgid,
+#endif
+ edata->funcname, NULL))
return; /* nothing to do */
/*
MemoryContext oldcontext;
if (!errstart(edata->elevel, edata->filename, edata->lineno,
+#ifdef USE_MODULE_MSGIDS
+ edata->moduleid,
+ edata->fileid, edata->msgid,
+#endif
edata->funcname, NULL))
return;
*/
if (IsPostmasterEnvironment)
edata->output_to_server = is_log_level_output(FATAL,
- log_min_messages);
+#ifdef USE_MODULE_MSGIDS
+ 0,
+ 0,
+ 0,
+#endif
+ log_min_messages);
else
edata->output_to_server = (FATAL >= log_min_messages);
if (whereToSendOutput == DestRemote)
appendStringInfoChar(&buf, ',');
/* user query --- only reported if not disabled by the caller */
- if (is_log_level_output(edata->elevel, log_min_error_statement) &&
+ if (is_log_level_output(edata->elevel,
+#ifdef USE_MODULE_MSGIDS
+ edata->moduleid,
+ edata->fileid,
+ edata->msgid,
+#endif
+ log_min_error_statement) &&
debug_query_string != NULL &&
!edata->hide_stmt)
print_stmt = true;
/*
* If the user wants the query that generated this error logged, do it.
*/
- if (is_log_level_output(edata->elevel, log_min_error_statement) &&
+ if (is_log_level_output(edata->elevel,
+#ifdef USE_MODULE_MSGIDS
+ edata->moduleid,
+ edata->fileid,
+ edata->msgid,
+#endif
+ log_min_error_statement) &&
debug_query_string != NULL &&
!edata->hide_stmt)
{
va_end(ap);
}
+#ifdef USE_MODULE_MSGIDS
+static int
+get_overriden_log_level(int moduleid, int fileid, int msgid, int origlevel)
+{
+ uint32 position;
+
+ /*
+ * The shared memory may not set during init processing or in a stand alone
+ * backend.
+ */
+ if (!IsPostmasterEnvironment || IsInitProcessingMode())
+ return origlevel;
+
+ /*
+ * Reject invalid bounds
+ */
+ if ((moduleid <= 0 || moduleid >= PGXL_MSG_MAX_MODULES) ||
+ (fileid <= 0 || fileid >= PGXL_MSG_MAX_FILEIDS_PER_MODULE) ||
+ (msgid <= 0 || msgid >= PGXL_MSG_MAX_MSGIDS_PER_FILE))
+ return origlevel;
+
+ /*
+ * Get the overridden log level and return it back
+ */
+ position = (moduleid - 1) * PGXL_MSG_MAX_FILEIDS_PER_MODULE *
+ PGXL_MSG_MAX_MSGIDS_PER_FILE +
+ (fileid - 1) * PGXL_MSG_MAX_MSGIDS_PER_FILE +
+ (msgid - 1);
+ return MsgModuleCtl[position] ? MsgModuleCtl[position] : origlevel;
+}
+#endif
/*
* is_log_level_output -- is elevel logically >= log_min_level?
* test is correct for testing whether the message should go to the client.
*/
static bool
-is_log_level_output(int elevel, int log_min_level)
+is_log_level_output(int elevel,
+#ifdef USE_MODULE_MSGIDS
+ int moduleid,
+ int fileid,
+ int msgid,
+#endif
+ int log_min_level)
{
if (elevel == LOG || elevel == COMMERROR)
{
/* Neither is LOG */
else if (elevel >= log_min_level)
return true;
+#ifdef USE_MODULE_MSGIDS
+ /*
+ * Check if the message's compile time value has been changed during the
+ * run time.
+ *
+ * Currently, we only support increasing the log level of messages and that
+ * too only for deciding whether the message should go to the server log or
+ * not. A message which would otherwise not qualify to go to the server
+ * log, thus can be forced to be logged.
+ *
+ * In future, we may also want to go otherway round i.e. supressing a log
+ * message or also change severity of log messages. The latter may
+ * especially be useful to turn some specific ERROR messages into FATAL or
+ * PANIC to be able to get a core dump for analysis.
+ */
+ else
+ {
+ int newlevel = get_overriden_log_level(moduleid, fileid, msgid,
+ elevel);
+ if (newlevel == LOG)
+ {
+ if (log_min_level == LOG || log_min_level <= ERROR)
+ return true;
+ }
+ else if (newlevel >= log_min_level)
+ return true;
+ }
+#endif
return false;
}
return trace_level;
}
+
+#ifdef USE_MODULE_MSGIDS
+Size
+MsgModuleShmemSize(void)
+{
+ Size mm_size;
+
+ /*
+ * One byte per message to store overridden log level.
+ * !!TODO We don't really need a byte and a few bits would be enough. So
+ * look for improving this/
+ *
+ * What we have done is a very simplisitic representation of msg-ids. The
+ * overall memory requirement of this representation is too large as
+ * compared to the actual number of msgs. For example, both
+ * PGXL_MSG_MAX_MSGIDS_PER_FILE and PGXL_MSG_MAX_FILEIDS_PER_MODULE are set
+ * to the largest value that any one module uses, but the actual values are
+ * much smaller
+ *
+ * In theory, we could also have separate area for each backend so that
+ * logging can be controlled at a backend level. But the current
+ * representation is not at all efficient to do that.
+ */
+ mm_size = mul_size(PGXL_MSG_MAX_MODULES, PGXL_MSG_MAX_FILEIDS_PER_MODULE);
+ mm_size = mul_size(mm_size, PGXL_MSG_MAX_MSGIDS_PER_FILE);
+
+ return mm_size;
+}
+
+void
+MsgModuleShmemInit(void)
+{
+ bool found;
+
+ MsgModuleCtl = ShmemInitStruct("Message Module Struct",
+ (PGXL_MSG_MAX_MODULES *
+ PGXL_MSG_MAX_FILEIDS_PER_MODULE *
+ PGXL_MSG_MAX_MSGIDS_PER_FILE),
+ &found);
+}
+
+Datum
+pg_msgmodule_set(PG_FUNCTION_ARGS)
+{
+ int32 moduleid = PG_GETARG_INT32(0);
+ int32 fileid = PG_GETARG_INT32(1);
+ int32 msgid = PG_GETARG_INT32(2);
+ const char *levelstr = PG_GETARG_CSTRING(3);
+ int32 level;
+ uint32 start_position;
+ uint32 len;
+
+ if (!superuser())
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ (errmsg("must be superuser to change elog message level"))));
+
+ /*
+ * The only accepted values for the log levels are - LOG, DEBUG[1-5] and
+ * DEFAULT
+ */
+ if (strcasecmp(levelstr, "LOG") == 0)
+ level = LOG;
+ else if (strcasecmp(levelstr, "DEFAULT") == 0)
+ level = 0;
+ else if (strcasecmp(levelstr, "DEBUG1") == 0)
+ level = DEBUG1;
+ else if (strcasecmp(levelstr, "DEBUG2") == 0)
+ level = DEBUG2;
+ else if (strcasecmp(levelstr, "DEBUG3") == 0)
+ level = DEBUG3;
+ else if (strcasecmp(levelstr, "DEBUG4") == 0)
+ level = DEBUG4;
+ else if (strcasecmp(levelstr, "DEBUG5") == 0)
+ level = DEBUG5;
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_INTERNAL_ERROR),
+ (errmsg("Invalid value \"%s\" for log level", levelstr))));
+
+ if (moduleid <= 0 || moduleid >= PGXL_MSG_MAX_MODULES)
+ ereport(ERROR, (errmsg_internal("Invalid module id %d, allowed values 1-%d",
+ moduleid, PGXL_MSG_MAX_MODULES)));
+
+ if (fileid == -1)
+ {
+ /*
+ * All messages in the given module to be overridden with the given
+ * level
+ */
+ len = PGXL_MSG_MAX_FILEIDS_PER_MODULE * PGXL_MSG_MAX_MSGIDS_PER_FILE;
+ start_position = (moduleid - 1) * len;
+ memset(MsgModuleCtl + start_position, level, len);
+ PG_RETURN_BOOL(true);
+ }
+ else
+ {
+ if (fileid <= 0 || fileid >= PGXL_MSG_MAX_FILEIDS_PER_MODULE)
+ ereport(ERROR, (errmsg_internal("Invalid file id %d, allowed values 1-%d",
+ fileid, PGXL_MSG_MAX_FILEIDS_PER_MODULE)));
+
+ /*
+ * All messages in the given <module, file> to be overridden with the
+ * given level
+ */
+ if (msgid == -1)
+ {
+ len = PGXL_MSG_MAX_MSGIDS_PER_FILE;
+ start_position = ((moduleid - 1) * PGXL_MSG_MAX_FILEIDS_PER_MODULE * PGXL_MSG_MAX_MSGIDS_PER_FILE) +
+ (fileid - 1) * PGXL_MSG_MAX_MSGIDS_PER_FILE;
+ memset(MsgModuleCtl + start_position, level, len);
+ PG_RETURN_BOOL(true);
+ }
+
+ if (msgid <= 0 || msgid >= PGXL_MSG_MAX_MSGIDS_PER_FILE)
+ ereport(ERROR, (errmsg_internal("Invalid msg id %d, allowed values 1-%d",
+ fileid, PGXL_MSG_MAX_MSGIDS_PER_FILE)));
+
+ /*
+ * Deal with a specific <module, file, msg>
+ */
+ len = sizeof (char);
+ start_position = ((moduleid - 1) * PGXL_MSG_MAX_FILEIDS_PER_MODULE * PGXL_MSG_MAX_MSGIDS_PER_FILE) +
+ ((fileid - 1) * PGXL_MSG_MAX_MSGIDS_PER_FILE) +
+ (msgid - 1);
+ memset(MsgModuleCtl + start_position, level, len);
+ PG_RETURN_BOOL(true);
+ }
+ PG_RETURN_BOOL(true);
+}
+#else
+Datum
+pg_msgmodule_set(PG_FUNCTION_ARGS)
+{
+ ereport(ERROR, (errmsg_internal("Module msgid support not available. "
+ "Please recompile with --enable-genmsgids")));
+}
+#endif
#-----------------------------------------------------------------------------
top_builddir=../../..
include $(top_builddir)/src/Makefile.global
-subdir=src/bin/gtm_ctl
+subdir = src/bin/gtm_ctl
override CPPFLAGS := -I$(libpq_srcdir) $(CPPFLAGS)
# their *.o siblings as well, which do have proper dependencies. It's
# a hack that might fail someday if there is a *_srv.o without a
# corresponding *.o, but it works for now.
+ifeq ($(genmsgids), yes)
+PGXL_MSG_FILEID := 1
+%_srv.o: %.c %.o
+ $(CC) $(CFLAGS) -DPGXL_MSG_MODULE=$(PGXL_MSG_MODULE) -DPGXL_MSG_FILEID=$(PGXL_MSG_FILEID) $(subst -DFRONTEND,, $(CPPFLAGS)) -c $< -o $@
+ $(eval PGXL_MSG_FILEID := $(shell echo $(PGXL_MSG_FILEID) + 1 | bc))
+else
%_srv.o: %.c %.o
$(CC) $(CFLAGS) $(subst -DFRONTEND,, $(CPPFLAGS)) -c $< -o $@
+endif
$(OBJS_SRV): | submake-errcodes
DATA(insert OID = 6014 ( pg_show_replication_origin_status PGNSP PGUID 12 1 100 0 0 f f f f f t v 0 0 2249 "" "{26,25,3220,3220}" "{o,o,o,o}" "{local_id, external_id, remote_lsn, local_lsn}" _null_ _null_ pg_show_replication_origin_status _null_ _null_ _null_ ));
DESCR("get progress for all replication origins");
+#ifdef USE_MODULE_MSGIDS
+DATA(insert OID = 6015 ( pg_msgmodule_set PGNSP PGUID 12 1 1 0 0 f f f f t t i 4 0 16 "20 20 20 2275" _null_ _null_ _null_ _null_ _null_ pg_msgmodule_set _null_ _null_ _null_ ));
+DESCR("set debugging level for module/file/msg");
+#endif
+
/*
* Symbolic values for provolatile column: these indicate whether the result
* of a function is dependent *only* on the values of its explicit arguments,
/* Define to 1 to build with assertion checks. (--enable-cassert) */
#undef USE_ASSERT_CHECKING
+/* Define to 1 to build with module msgids. (--enable-genmsgids) */
+#undef USE_MODULE_MSGIDS
+
/* Define to 1 to build with Bonjour support. (--with-bonjour) */
#undef USE_BONJOUR
extern Datum pgxc_is_committed(PG_FUNCTION_ARGS);
extern Datum pgxc_is_inprogress(PG_FUNCTION_ARGS);
#endif
-
+#ifdef USE_MODULE_MSGIDS
+extern Datum pg_msgmodule_set(PG_FUNCTION_ARGS);
+#endif
#endif /* BUILTINS_H */
* prevents gcc from making the unreachability deduction at optlevel -O0.
*----------
*/
+#ifdef USE_MODULE_MSGIDS
+#ifdef HAVE__BUILTIN_CONSTANT_P
+#define ereport_domain(elevel, domain, rest) \
+ do { \
+ if (errstart(elevel, __FILE__, __LINE__, PGXL_MSG_MODULE, PGXL_MSG_FILEID, __COUNTER__, PG_FUNCNAME_MACRO, domain)) \
+ errfinish rest; \
+ if (__builtin_constant_p(elevel) && (elevel) >= ERROR) \
+ pg_unreachable(); \
+ } while(0)
+#else /* !HAVE__BUILTIN_CONSTANT_P */
+#define ereport_domain(elevel, domain, rest) \
+ do { \
+ const int elevel_ = (elevel); \
+ if (errstart(elevel, __FILE__, __LINE__, PGXL_MSG_MODULE, PGXL_MSG_FILEID, __COUNTER__, PG_FUNCNAME_MACRO, domain)) \
+ errfinish rest; \
+ if (elevel_ >= ERROR) \
+ pg_unreachable(); \
+ } while(0)
+#endif /* HAVE__BUILTIN_CONSTANT_P */
+#else
#ifdef HAVE__BUILTIN_CONSTANT_P
#define ereport_domain(elevel, domain, rest) \
do { \
#define ereport_domain(elevel, domain, rest) \
do { \
const int elevel_ = (elevel); \
- if (errstart(elevel_, __FILE__, __LINE__, PG_FUNCNAME_MACRO, domain)) \
+ if (errstart(elevel, __FILE__, __LINE__, PG_FUNCNAME_MACRO, domain)) \
errfinish rest; \
if (elevel_ >= ERROR) \
pg_unreachable(); \
} while(0)
#endif /* HAVE__BUILTIN_CONSTANT_P */
+#endif
#define ereport(elevel, rest) \
ereport_domain(elevel, TEXTDOMAIN, rest)
#define TEXTDOMAIN NULL
extern bool errstart(int elevel, const char *filename, int lineno,
- const char *funcname, const char *domain);
+#ifdef USE_MODULE_MSGIDS
+ int moduleid, int fileid, int msgid,
+#endif
+ const char *funcname, const char *domain
+ );
extern void errfinish(int dummy,...);
extern int errcode(int sqlerrcode);
* elog(ERROR, "portal \"%s\" not found", stmt->portalname);
*----------
*/
+#ifdef USE_MODULE_MSGIDS
#ifdef HAVE__VA_ARGS
/*
* If we have variadic macros, we can give the compiler a hint about the
* before evaluating "elevel", so we preserve that behavior here.
*/
#ifdef HAVE__BUILTIN_CONSTANT_P
+#define elog(elevel, ...) \
+ do { \
+ elog_start(__FILE__, __LINE__, PGXL_MSG_MODULE, PGXL_MSG_FILEID, __COUNTER__, PG_FUNCNAME_MACRO); \
+ elog_finish(elevel, __VA_ARGS__); \
+ if (__builtin_constant_p(elevel) && (elevel) >= ERROR) \
+ pg_unreachable(); \
+ } while(0)
+#else /* !HAVE__BUILTIN_CONSTANT_P */
+#define elog(elevel, ...) \
+ do { \
+ int elevel_; \
+ elog_start(__FILE__, __LINE__, PGXL_MSG_MODULE, PGXL_MSG_FILEID, __COUNTER__, PG_FUNCNAME_MACRO); \
+ elevel_ = (elevel); \
+ elog_finish(elevel_, __VA_ARGS__); \
+ if (elevel_ >= ERROR) \
+ pg_unreachable(); \
+ } while(0)
+#endif /* HAVE__BUILTIN_CONSTANT_P */
+#else /* !HAVE__VA_ARGS */
+#define elog \
+ elog_start(__FILE__, __LINE__, PGXL_MSG_MODULE, PGXL_MSG_FILEID, __COUNTER__, PG_FUNCNAME_MACRO); \
+ elog_finish
+#endif /* HAVE__VA_ARGS */
+#else
+#ifdef HAVE__VA_ARGS
+#ifdef HAVE__BUILTIN_CONSTANT_P
#define elog(elevel, ...) \
do { \
elog_start(__FILE__, __LINE__, PG_FUNCNAME_MACRO); \
#endif /* HAVE__BUILTIN_CONSTANT_P */
#else /* !HAVE__VA_ARGS */
#define elog \
- elog_start(__FILE__, __LINE__, PG_FUNCNAME_MACRO), \
+ elog_start(__FILE__, __LINE__, PG_FUNCNAME_MACRO); \
elog_finish
#endif /* HAVE__VA_ARGS */
+#endif
-extern void elog_start(const char *filename, int lineno, const char *funcname);
+extern void elog_start(const char *filename, int lineno,
+#ifdef USE_MODULE_MSGIDS
+ int moduleid, int flieid, int msgid,
+#endif
+ const char *funcname
+ );
extern void elog_finish(int elevel, const char *fmt,...) pg_attribute_printf(2, 3);
int internalpos; /* cursor index into internalquery */
char *internalquery; /* text of internally-generated query */
int saved_errno; /* errno at entry */
+#ifdef USE_MODULE_MSGIDS
+ int moduleid;
+ int fileid;
+ int msgid; /* msgid */
+#endif
/* context containing associated non-constant strings */
struct MemoryContextData *assoc_context;
} ErrorData;
+#ifdef USE_MODULE_MSGIDS
+#define PGXL_MSG_MAX_MODULES 256
+#define PGXL_MSG_MAX_FILEIDS_PER_MODULE 100
+#define PGXL_MSG_MAX_MSGIDS_PER_FILE 300
+
+extern char *MsgModuleCtl;
+extern Size MsgModuleShmemSize(void);
+extern void MsgModuleShmemInit(void);
+#endif
+
extern void EmitErrorReport(void);
extern ErrorData *CopyErrorData(void);
extern void FreeErrorData(ErrorData *edata);
# a hack that might fail someday if there is a *_srv.o without a
# corresponding *.o, but it works for now (and those would probably go
# into src/backend/port/ anyway).
+ifeq ($(genmsgids), yes)
+PGXL_MSG_FILEID := 1
+%_srv.o: %.c %.o
+ $(CC) $(CFLAGS) -DPGXL_MSG_MODULE=$(PGXL_MSG_MODULE) -DPGXL_MSG_FILEID=$(PGXL_MSG_FILEID) $(subst -DFRONTEND,, $(CPPFLAGS)) -c $< -o $@
+ $(eval PGXL_MSG_FILEID := $(shell echo $(PGXL_MSG_FILEID) + 1 | bc))
+else
%_srv.o: %.c %.o
$(CC) $(CFLAGS) $(subst -DFRONTEND,, $(CPPFLAGS)) -c $< -o $@
+endif
$(OBJS_SRV): | submake-errcodes