From e67de85c0b9c5253799d3ea205ad7defa69640b7 Mon Sep 17 00:00:00 2001 From: Dave Cramer Date: Thu, 11 Jul 2019 08:20:14 -0400 Subject: [PATCH] Add a STARTUP packet option to set GUC_REPORT on GUC's that currently do not have that option set. There is a facility to add protocol options using _pq_. The new option name is report and takes a comma delmited string of GUC names which will have GUC_REPORT set. Add functionality into libpq to accept this new option key Use SplitGUCList instead of strtok --- src/backend/postmaster/postmaster.c | 34 +++++++++++++++++++++++++---- src/backend/utils/init/postinit.c | 13 +++++++++++ src/backend/utils/misc/guc.c | 22 +++++++++++++++++++ src/include/libpq/libpq-be.h | 1 + src/include/utils/guc.h | 1 + src/interfaces/libpq/fe-connect.c | 5 ++++- src/interfaces/libpq/fe-protocol3.c | 3 +++ src/interfaces/libpq/libpq-int.h | 2 ++ 8 files changed, 76 insertions(+), 5 deletions(-) diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index eb9e0221f8..b2491da42b 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -2094,6 +2094,7 @@ retry1: * zeroing extra byte above. */ port->guc_options = NIL; + port->guc_report = NIL; while (offset < len) { @@ -2140,11 +2141,36 @@ retry1: { /* * Any option beginning with _pq_. is reserved for use as a - * protocol-level option, but at present no such options are - * defined. + * protocol-level option. */ - unrecognized_protocol_options = - lappend(unrecognized_protocol_options, pstrdup(nameptr)); + + if (strncasecmp(nameptr + 5, "report", 6) == 0) + { + List *reportlist; + ListCell *lc; + + /* avoid scribbling on valptr */ + char *tempval = pstrdup(valptr); + + /* Parse string into list of identifiers */ + if (!SplitGUCList(tempval, ',', &reportlist)) + { + /* this shouldn't fail really */ + elog(ERROR, "invalid list syntax in guc_report list"); + } + foreach(lc, reportlist) + { + char *guc = (char *) lfirst(lc); + port->guc_report = lappend(port->guc_report, + pstrdup(guc)); + } + pfree(tempval); + } + else + { + unrecognized_protocol_options = + lappend(unrecognized_protocol_options, pstrdup(nameptr)); + } } else { diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c index 29c5ec7b58..98b9517143 100644 --- a/src/backend/utils/init/postinit.c +++ b/src/backend/utils/init/postinit.c @@ -1090,6 +1090,9 @@ process_startup_options(Port *port, bool am_superuser) { GucContext gucctx; ListCell *gucopts; + ListCell *gucreport; + List *gucReports; + gucctx = am_superuser ? PGC_SU_BACKEND : PGC_BACKEND; @@ -1124,6 +1127,16 @@ process_startup_options(Port *port, bool am_superuser) (void) process_postgres_switches(ac, av, gucctx, NULL); } + /* Loop through the user requested GUC_REPORT and set them */ + gucReports = port->guc_report; + foreach(gucreport,gucReports) + { + char *name; + + name = lfirst(gucreport); + SetConfigReport(name, true); + } + /* * Process any additional GUC variable settings passed in startup packet. * These are handled exactly like command-line variables. diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 2178e1cf5e..25cf17f2a8 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -7630,7 +7630,29 @@ GetConfigOptionFlags(const char *name, bool missing_ok) return record->flags; } +/* + * Set the option to be GUC_REPORT + */ + +bool +SetConfigReport(const char *name, bool missing_ok) +{ + struct config_generic *record; + record = find_option(name, false, WARNING); + if (record == NULL) + { + if (missing_ok) + return 0; + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("unrecognized configuration parameter \"%s\"", + name))); + } + record->flags |= GUC_REPORT; + + return 0; +} /* * flatten_set_variable_args * Given a parsenode List as emitted by the grammar for SET, diff --git a/src/include/libpq/libpq-be.h b/src/include/libpq/libpq-be.h index 541f970f99..0350b70f02 100644 --- a/src/include/libpq/libpq-be.h +++ b/src/include/libpq/libpq-be.h @@ -141,6 +141,7 @@ typedef struct Port char *user_name; char *cmdline_options; List *guc_options; + List *guc_report; /* * The startup packet application name, only used here for the "connection diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 6791e0cbc2..8c4fc5ed62 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -348,6 +348,7 @@ extern const char *GetConfigOption(const char *name, bool missing_ok, bool restrict_privileged); extern const char *GetConfigOptionResetString(const char *name); extern int GetConfigOptionFlags(const char *name, bool missing_ok); +extern bool SetConfigReport(const char *name, bool missing_ok); extern void ProcessConfigFile(GucContext context); extern void InitializeGUCOptions(void); extern bool SelectConfigFiles(const char *userDoption, const char *progname); diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index f91f0f2efe..c0f59f37f8 100644 --- a/src/interfaces/libpq/fe-connect.c +++ b/src/interfaces/libpq/fe-connect.c @@ -353,6 +353,10 @@ static const internalPQconninfoOption PQconninfoOptions[] = { "Target-Session-Attrs", "", 11, /* sizeof("read-write") = 11 */ offsetof(struct pg_conn, target_session_attrs)}, + {"_pq_.report",NULL, NULL, NULL, + "Report", "D", 5, + offsetof(struct pg_conn, guc_report)}, + /* Terminating entry --- MUST BE LAST */ {NULL, NULL, NULL, NULL, NULL, NULL, 0} @@ -5560,7 +5564,6 @@ conninfo_array_parse(const char *const *keywords, const char *const *values, PQconninfoFree(dbname_options); return NULL; } - /* * If we are on the first dbname parameter, and we have a parsed * connection string, copy those parameters across, overriding any diff --git a/src/interfaces/libpq/fe-protocol3.c b/src/interfaces/libpq/fe-protocol3.c index b04f7ec123..f48200b972 100644 --- a/src/interfaces/libpq/fe-protocol3.c +++ b/src/interfaces/libpq/fe-protocol3.c @@ -2184,6 +2184,9 @@ build_startup_packet(const PGconn *conn, char *packet, ADD_STARTUP_OPTION("replication", conn->replication); if (conn->pgoptions && conn->pgoptions[0]) ADD_STARTUP_OPTION("options", conn->pgoptions); + if (conn->guc_report && conn->guc_report[0]) + ADD_STARTUP_OPTION("_pq_.report", conn->guc_report); + if (conn->send_appname) { /* Use appname if present, otherwise use fallback */ diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h index 64468ab4da..9ec8e8609b 100644 --- a/src/interfaces/libpq/libpq-int.h +++ b/src/interfaces/libpq/libpq-int.h @@ -370,6 +370,8 @@ struct pg_conn /* Type of connection to make. Possible values: any, read-write. */ char *target_session_attrs; + char *guc_report; + /* Optional file to write trace info to */ FILE *Pfdebug; -- 2.20.1 (Apple Git-117)