if (newval[0] != '\0' &&
!OidIsValid(get_tablespace_oid(newval)))
{
- if (source >= PGC_S_INTERACTIVE)
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("tablespace \"%s\" does not exist",
- newval)));
+ ereport(GUC_complaint_elevel(source),
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("tablespace \"%s\" does not exist",
+ newval)));
return NULL;
}
}
/* syntax error in list */
pfree(rawstring);
list_free(elemlist);
- if (source >= PGC_S_INTERACTIVE)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ ereport(GUC_complaint_elevel(source),
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("invalid list syntax for parameter \"datestyle\"")));
return NULL;
}
}
else
{
- if (source >= PGC_S_INTERACTIVE)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("unrecognized \"datestyle\" key word: \"%s\"",
- tok)));
+ ereport(GUC_complaint_elevel(source),
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("unrecognized \"datestyle\" key word: \"%s\"",
+ tok)));
ok = false;
break;
}
if (!ok)
{
- if (source >= PGC_S_INTERACTIVE)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("conflicting \"datestyle\" specifications")));
+ ereport(GUC_complaint_elevel(source),
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("conflicting \"datestyle\" specifications")));
return NULL;
}
/*
* Try to parse it. XXX an invalid interval format will result in
- * ereport, which is not desirable for GUC. We did what we could to
- * guard against this in flatten_set_variable_args, but a string
- * coming in from postgresql.conf might contain anything.
+ * ereport(ERROR), which is not desirable for GUC. We did what we
+ * could to guard against this in flatten_set_variable_args, but a
+ * string coming in from postgresql.conf might contain anything.
*/
interval = DatumGetIntervalP(DirectFunctionCall3(interval_in,
CStringGetDatum(val),
pfree(val);
if (interval->month != 0)
{
- if (source >= PGC_S_INTERACTIVE)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("invalid interval value for time zone: month not allowed")));
+ ereport(GUC_complaint_elevel(source),
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("invalid interval value for time zone: month not allowed")));
pfree(interval);
return NULL;
}
if (interval->day != 0)
{
- if (source >= PGC_S_INTERACTIVE)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("invalid interval value for time zone: day not allowed")));
+ ereport(GUC_complaint_elevel(source),
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("invalid interval value for time zone: day not allowed")));
pfree(interval);
return NULL;
}
if (!new_tz)
{
- ereport((source >= PGC_S_INTERACTIVE) ? ERROR : LOG,
+ ereport(GUC_complaint_elevel(source),
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("unrecognized time zone name: \"%s\"",
value)));
if (!tz_acceptable(new_tz))
{
- ereport((source >= PGC_S_INTERACTIVE) ? ERROR : LOG,
+ ereport(GUC_complaint_elevel(source),
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("time zone \"%s\" appears to use leap seconds",
value),
if (!new_tz)
{
- ereport((source >= PGC_S_INTERACTIVE) ? ERROR : LOG,
+ ereport(GUC_complaint_elevel(source),
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("unrecognized time zone name: \"%s\"",
value)));
if (!tz_acceptable(new_tz))
{
- ereport((source >= PGC_S_INTERACTIVE) ? ERROR : LOG,
+ ereport(GUC_complaint_elevel(source),
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("time zone \"%s\" appears to use leap seconds",
value),
{
if (SerializableSnapshot != NULL)
{
- if (source >= PGC_S_INTERACTIVE)
- ereport(ERROR,
- (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
- errmsg("SET TRANSACTION ISOLATION LEVEL must be called before any query")));
+ ereport(GUC_complaint_elevel(source),
+ (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
+ errmsg("SET TRANSACTION ISOLATION LEVEL must be called before any query")));
/* source == PGC_S_OVERRIDE means do it anyway, eg at xact abort */
- else if (source != PGC_S_OVERRIDE)
+ if (source != PGC_S_OVERRIDE)
return NULL;
}
- if (IsSubTransaction())
+ else if (IsSubTransaction())
{
- if (source >= PGC_S_INTERACTIVE)
- ereport(ERROR,
- (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
- errmsg("SET TRANSACTION ISOLATION LEVEL must not be called in a subtransaction")));
+ ereport(GUC_complaint_elevel(source),
+ (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
+ errmsg("SET TRANSACTION ISOLATION LEVEL must not be called in a subtransaction")));
/* source == PGC_S_OVERRIDE means do it anyway, eg at xact abort */
- else if (source != PGC_S_OVERRIDE)
+ if (source != PGC_S_OVERRIDE)
return NULL;
}
*/
if (SetClientEncoding(encoding, doit) < 0)
{
- if (source >= PGC_S_INTERACTIVE)
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("conversion between %s and %s is not supported",
- value, GetDatabaseEncodingName())));
+ ereport(GUC_complaint_elevel(source),
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("conversion between %s and %s is not supported",
+ value, GetDatabaseEncodingName())));
return NULL;
}
return value;
0, 0, 0);
if (!HeapTupleIsValid(roleTup))
{
- if (source >= PGC_S_INTERACTIVE)
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("role \"%s\" does not exist", value)));
+ ereport(GUC_complaint_elevel(source),
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("role \"%s\" does not exist", value)));
return NULL;
}
0, 0, 0);
if (!HeapTupleIsValid(roleTup))
{
- if (source >= PGC_S_INTERACTIVE)
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("role \"%s\" does not exist", value)));
+ ereport(GUC_complaint_elevel(source),
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("role \"%s\" does not exist", value)));
return NULL;
}
*/
if (!is_member_of_role(GetSessionUserId(), roleid))
{
- if (source >= PGC_S_INTERACTIVE)
- ereport(ERROR,
- (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("permission denied to set role \"%s\"",
- value)));
+ ereport(GUC_complaint_elevel(source),
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("permission denied to set role \"%s\"",
+ value)));
return NULL;
}
}
if (stack_rlimit > 0 && newval_bytes > stack_rlimit - STACK_DEPTH_SLOP)
{
- ereport((source >= PGC_S_INTERACTIVE) ? ERROR : LOG,
+ ereport(GUC_complaint_elevel(source),
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("\"max_stack_depth\" must not exceed %ldkB",
(stack_rlimit - STACK_DEPTH_SLOP) / 1024L),
performed. If "doit" is false then the function should simply check
validity of newvalue and not change any derived state. The "source" parameter
indicates where the new value came from. If it is >= PGC_S_INTERACTIVE,
-then we are performing an interactive assignment (e.g., a SET command).
-In such cases it is okay for the assign_hook to raise an error via ereport().
-If the function returns false for an interactive assignment then guc.c will
-report a generic "invalid value" error message. (An internal ereport() in
-an assign_hook is only needed if you want to generate a specialized error
-message.) But when source < PGC_S_INTERACTIVE, we are reading a
-non-interactive option source, such as postgresql.conf. In this case the
-assign_hook should *not* ereport but should just return false if it doesn't
-like the newvalue. (An ereport(LOG) call would be acceptable if you feel a
-need for a custom complaint in this situation.)
+then we are performing an interactive assignment (e.g., a SET command), and
+ereport(ERROR) is safe to do. But when source < PGC_S_INTERACTIVE, we are
+reading a non-interactive option source, such as postgresql.conf. In this
+case the assign_hook should *not* ereport but should just return false if it
+doesn't like the newvalue.
+
+If an assign_hook returns false then guc.c will report a generic "invalid
+value for option FOO" error message. If you feel the need to provide a more
+specific error message, ereport() it using "GUC_complaint_elevel(source)"
+as the error level. Note that this might return either ERROR or a lower level
+such as LOG, so the ereport call might or might not return. If it does
+return, return false out of the assign_hook.
For string variables, the signature for assign hooks is a bit different:
const char *assign_hook(const char *newvalue,
* If there is an error (non-existing option, invalid value) then an
* ereport(ERROR) is thrown *unless* this is called in a context where we
* don't want to ereport (currently, startup or SIGHUP config file reread).
- * In that case we write a suitable error message via ereport(DEBUG) and
+ * In that case we write a suitable error message via ereport(LOG) and
* return false. This is working around the deficiencies in the ereport
* mechanism, so don't blame me. In all other cases, the function
* returns true, including cases where the input is valid but we chose
* To avoid cluttering the log, only the postmaster bleats loudly
* about problems with the config file.
*/
- elevel = IsUnderPostmaster ? DEBUG2 : LOG;
+ elevel = IsUnderPostmaster ? DEBUG3 : LOG;
}
else if (source == PGC_S_DATABASE || source == PGC_S_USER)
elevel = INFO;
}
+/*
+ * GUC_complaint_elevel
+ * Get the ereport error level to use in an assign_hook's error report.
+ *
+ * This should be used by assign hooks that want to emit a custom error
+ * report (in addition to the generic "invalid value for option FOO" that
+ * guc.c will provide). Note that the result might be ERROR or a lower
+ * level, so the caller must be prepared for control to return from ereport,
+ * or not. If control does return, return false/NULL from the hook function.
+ *
+ * At some point it'd be nice to replace this with a mechanism that allows
+ * the custom message to become the DETAIL line of guc.c's generic message.
+ */
+int
+GUC_complaint_elevel(GucSource source)
+{
+ int elevel;
+
+ if (source == PGC_S_FILE)
+ {
+ /*
+ * To avoid cluttering the log, only the postmaster bleats loudly
+ * about problems with the config file.
+ */
+ elevel = IsUnderPostmaster ? DEBUG3 : LOG;
+ }
+ else if (source < PGC_S_INTERACTIVE)
+ elevel = LOG;
+ else
+ elevel = ERROR;
+
+ return elevel;
+}
+
+
/*
* flatten_set_variable_args
* Given a parsenode List as emitted by the grammar for SET,
/* syntax error in list */
pfree(rawstring);
list_free(elemlist);
- if (source >= PGC_S_INTERACTIVE)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ ereport(GUC_complaint_elevel(source),
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("invalid list syntax for parameter \"log_destination\"")));
return NULL;
}
#endif
else
{
- if (source >= PGC_S_INTERACTIVE)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ ereport(GUC_complaint_elevel(source),
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("unrecognized \"log_destination\" key word: \"%s\"",
tok)));
pfree(rawstring);
{
if (!newval)
{
- if (doit && source >= PGC_S_INTERACTIVE)
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("SET AUTOCOMMIT TO OFF is no longer supported")));
+ ereport(GUC_complaint_elevel(source),
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("SET AUTOCOMMIT TO OFF is no longer supported")));
return false;
}
return true;
{
#ifndef USE_ASSERT_CHECKING
if (newval)
- ereport(ERROR,
+ {
+ ereport(GUC_complaint_elevel(source),
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("assertion checking is not supported by this build")));
+ return false;
+ }
#endif
return true;
}
{
#ifndef USE_SSL
if (newval)
- ereport(ERROR,
+ {
+ ereport(GUC_complaint_elevel(source),
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("SSL is not supported by this build")));
+ return false;
+ }
#endif
return true;
}
{
if (newval && log_statement_stats)
{
- if (source >= PGC_S_INTERACTIVE)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("cannot enable parameter when \"log_statement_stats\" is true")));
+ ereport(GUC_complaint_elevel(source),
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("cannot enable parameter when \"log_statement_stats\" is true")));
/* source == PGC_S_OVERRIDE means do it anyway, eg at xact abort */
- else if (source != PGC_S_OVERRIDE)
+ if (source != PGC_S_OVERRIDE)
return false;
}
return true;
if (newval &&
(log_parser_stats || log_planner_stats || log_executor_stats))
{
- if (source >= PGC_S_INTERACTIVE)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("cannot enable \"log_statement_stats\" when "
- "\"log_parser_stats\", \"log_planner_stats\", "
- "or \"log_executor_stats\" is true")));
+ ereport(GUC_complaint_elevel(source),
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("cannot enable \"log_statement_stats\" when "
+ "\"log_parser_stats\", \"log_planner_stats\", "
+ "or \"log_executor_stats\" is true")));
/* source == PGC_S_OVERRIDE means do it anyway, eg at xact abort */
- else if (source != PGC_S_OVERRIDE)
+ if (source != PGC_S_OVERRIDE)
return false;
}
return true;
/* Can't go to r/w mode inside a r/o transaction */
if (newval == false && XactReadOnly && IsSubTransaction())
{
- if (source >= PGC_S_INTERACTIVE)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("cannot set transaction read-write mode inside a read-only transaction")));
+ ereport(GUC_complaint_elevel(source),
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("cannot set transaction read-write mode inside a read-only transaction")));
/* source == PGC_S_OVERRIDE means do it anyway, eg at xact abort */
- else if (source != PGC_S_OVERRIDE)
+ if (source != PGC_S_OVERRIDE)
return false;
}
return true;
* and we use WARNING message level.
*/
if (source == PGC_S_FILE)
- elevel = IsUnderPostmaster ? DEBUG2 : LOG;
+ elevel = IsUnderPostmaster ? DEBUG3 : LOG;
else
elevel = WARNING;
if (!load_tzoffsets(newval, doit, elevel))
extern ArrayType *GUCArrayAdd(ArrayType *array, const char *name, const char *value);
extern ArrayType *GUCArrayDelete(ArrayType *array, const char *name);
+extern int GUC_complaint_elevel(GucSource source);
+
extern void pg_timezone_abbrev_initialize(void);
#ifdef EXEC_BACKEND