From f6e97451d8b2b7fe38f4e71ae4d14b46d6a3acf4 Mon Sep 17 00:00:00 2001 From: "okbob@github.com" Date: Mon, 24 Jul 2023 20:13:17 +0200 Subject: [PATCH 1/4] Protocol ReportGUC message This patch implements dynamic reporting changes of GUC to client side. The flags per GUC can be changed by functions SetGUCOptionFlag and UsetGUCOptionFlag. --- doc/src/sgml/protocol.sgml | 37 +++++++++++++++++++++++++++++ src/backend/tcop/postgres.c | 37 +++++++++++++++++++++++++++++ src/backend/utils/misc/guc.c | 31 ++++++++++++++++++++++++ src/include/libpq/protocol.h | 1 + src/include/utils/guc.h | 2 ++ src/interfaces/libpq/exports.txt | 2 ++ src/interfaces/libpq/fe-exec.c | 36 +++++++++++++++++++++++++++- src/interfaces/libpq/fe-protocol3.c | 1 - src/interfaces/libpq/fe-trace.c | 12 ++++++++++ src/interfaces/libpq/libpq-fe.h | 3 +++ src/interfaces/libpq/libpq-int.h | 4 +++- 11 files changed, 163 insertions(+), 3 deletions(-) diff --git a/doc/src/sgml/protocol.sgml b/doc/src/sgml/protocol.sgml index b11d9a6ba3..fe6c4042fd 100644 --- a/doc/src/sgml/protocol.sgml +++ b/doc/src/sgml/protocol.sgml @@ -5401,6 +5401,43 @@ psql "dbname=postgres replication=database" -c "IDENTIFY_SYSTEM;" + + ReportGUC (F) + + + + Byte1('r') + + + Identifies the message type. ReportGUC is sent by + frontend when the changes of specified GUC option + should be (or should not be) reported to state parameter. + + + + + + Byte1 + + + 't' when reporting should be enables, 'f' if reporting should be + disabled. + + + + + + String + + + The name of GUC option. + + + + + + + RowDescription (B) diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 21b9763183..817c7c7fa1 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -449,6 +449,11 @@ SocketBackend(StringInfo inBuf) doing_extended_query_message = false; break; + case PqMsg_ReportGUC: + maxmsglen = PQ_SMALL_MESSAGE_LIMIT; + doing_extended_query_message = false; + break; + default: /* @@ -4850,6 +4855,38 @@ PostgresMain(const char *dbname, const char *username) send_ready_for_query = true; break; + case PqMsg_ReportGUC: + { + const char *name; + const char *status; + int is_set; + + is_set = pq_getmsgbyte(&input_message); + name = pq_getmsgstring(&input_message); + pq_getmsgend(&input_message); + + if (is_set == 't') + { + SetGUCOptionFlag(name, GUC_REPORT); + status = "SET"; + } + else if (is_set == 'f') + { + UnsetGUCOptionFlag(name, GUC_REPORT); + status = "UNSET"; + } + else + ereport(ERROR, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("invalid argument of REPORTGUC message %c", + is_set))); + + pq_puttextmessage(PqMsg_CommandComplete, status); + + valgrind_report_error_query("ReportGUC message"); + } + break; + /* * 'X' means that the frontend is closing down the socket. EOF * means unexpected loss of frontend connection. Either way, diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 84e7ad4d90..df22496131 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -2532,6 +2532,37 @@ BeginReportingGUCOptions(void) } } +/* + * Allow to set / unset dynamicaly flags to GUC variables + */ +void +SetGUCOptionFlag(const char *name, int flag) +{ + struct config_generic *conf; + + /* only GUC_REPORT flag is supported now */ + Assert(flag == GUC_REPORT); + + conf = find_option(name, false, false, ERROR); + conf->flags |= flag; + + if (flag == GUC_REPORT) + /* force transmit value of related option to client Parameter Status */ + ReportGUCOption(conf); +} + +void +UnsetGUCOptionFlag(const char *name, int flag) +{ + struct config_generic *conf; + + /* only GUC_REPORT flag is supported now */ + Assert(flag == GUC_REPORT); + + conf = find_option(name, false, false, ERROR); + conf->flags &= ~flag; +} + /* * ReportChangedGUCOptions: report recently-changed GUC_REPORT variables * diff --git a/src/include/libpq/protocol.h b/src/include/libpq/protocol.h index cc46f4b586..bd2c368b54 100644 --- a/src/include/libpq/protocol.h +++ b/src/include/libpq/protocol.h @@ -27,6 +27,7 @@ #define PqMsg_Sync 'S' #define PqMsg_Terminate 'X' #define PqMsg_CopyFail 'f' +#define PqMsg_ReportGUC 'r' #define PqMsg_GSSResponse 'p' #define PqMsg_PasswordMessage 'p' #define PqMsg_SASLInitialResponse 'p' diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index e89083ee0e..c200ca9b34 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -370,6 +370,8 @@ extern void ResetAllOptions(void); extern void AtStart_GUC(void); extern int NewGUCNestLevel(void); extern void AtEOXact_GUC(bool isCommit, int nestLevel); +extern void SetGUCOptionFlag(const char *name, int flag); +extern void UnsetGUCOptionFlag(const char *name, int flag); extern void BeginReportingGUCOptions(void); extern void ReportChangedGUCOptions(void); extern void ParseLongOption(const char *string, char **name, char **value); diff --git a/src/interfaces/libpq/exports.txt b/src/interfaces/libpq/exports.txt index 850734ac96..7e101368d5 100644 --- a/src/interfaces/libpq/exports.txt +++ b/src/interfaces/libpq/exports.txt @@ -191,3 +191,5 @@ PQclosePrepared 188 PQclosePortal 189 PQsendClosePrepared 190 PQsendClosePortal 191 +PQlinkParameterStatus 192 +PQunlinkParameterStatus 193 diff --git a/src/interfaces/libpq/fe-exec.c b/src/interfaces/libpq/fe-exec.c index c6d80ec396..1971b63102 100644 --- a/src/interfaces/libpq/fe-exec.c +++ b/src/interfaces/libpq/fe-exec.c @@ -1069,6 +1069,33 @@ pqSaveMessageField(PGresult *res, char code, const char *value) res->errFields = pfield; } +/* + * Add GUC_REPORT flag to specified setting and wait for synchronization + * with state parameters. + */ +PGresult * +PQlinkParameterStatus(PGconn *conn, const char *paramName) +{ + if (!PQexecStart(conn)) + return NULL; + if (!PQsendTypedCommand(conn, PqMsg_ReportGUC, 't', paramName)) + return NULL; + return PQexecFinish(conn); +} + +/* + * Remove GUC_REPORT flag from specified setting. + */ +PGresult * +PQunlinkParameterStatus(PGconn *conn, const char *paramName) +{ + if (!PQexecStart(conn)) + return NULL; + if (!PQsendTypedCommand(conn, PqMsg_ReportGUC, 'f', paramName)) + return NULL; + return PQexecFinish(conn); +} + /* * pqSaveParameterStatus - remember parameter status sent by backend */ @@ -2543,11 +2570,14 @@ PQsendClosePortal(PGconn *conn, const char *portal) * * Available options for "command" are * PqMsg_Close for Close; or - * PqMsg_Describe for Describe. + * PqMsg_Describe for Describe; or + * PqMsg_ReportGUC for (un)set GUC_REPORT flag. * * Available options for "type" are * 'S' to run a command on a prepared statement; or * 'P' to run a command on a portal. + * 't' to set GUC_REPORT flag + * 'f' to unset GUC_REPORT flag * * Returns 1 on success and 0 on failure. */ @@ -2591,6 +2621,10 @@ PQsendTypedCommand(PGconn *conn, char command, char type, const char *target) { entry->queryclass = PGQUERY_DESCRIBE; } + else if (command == PqMsg_ReportGUC) + { + entry->queryclass = PGQUERY_SETTING; + } else { libpq_append_conn_error(conn, "unknown command type provided"); diff --git a/src/interfaces/libpq/fe-protocol3.c b/src/interfaces/libpq/fe-protocol3.c index 5613c56b14..90d4e17e6f 100644 --- a/src/interfaces/libpq/fe-protocol3.c +++ b/src/interfaces/libpq/fe-protocol3.c @@ -2003,7 +2003,6 @@ pqEndcopy3(PGconn *conn) return 1; } - /* * PQfn - Send a function call to the POSTGRES backend. * diff --git a/src/interfaces/libpq/fe-trace.c b/src/interfaces/libpq/fe-trace.c index b18e3deab6..2a439080e1 100644 --- a/src/interfaces/libpq/fe-trace.c +++ b/src/interfaces/libpq/fe-trace.c @@ -522,6 +522,15 @@ pqTraceOutputZ(FILE *f, const char *message, int *cursor) pqTraceOutputByte1(f, message, cursor); } +/* ReportGUC */ +static void +pqTraceOutputr(FILE *f, const char *message, int *cursor) +{ + fprintf(f, "ReportGUC\t"); + pqTraceOutputByte1(f, message, cursor); + pqTraceOutputString(f, message, cursor, false); +} + /* * Print the given message to the trace output stream. */ @@ -644,6 +653,9 @@ pqTraceOutputMessage(PGconn *conn, const char *message, bool toServer) case PqMsg_AuthenticationRequest: pqTraceOutputR(conn->Pfdebug, message, &logCursor); break; + case PqMsg_ReportGUC: + pqTraceOutputr(conn->Pfdebug, message, &logCursor); + break; case PqMsg_PortalSuspended: fprintf(conn->Pfdebug, "PortalSuspended"); /* No message content */ diff --git a/src/interfaces/libpq/libpq-fe.h b/src/interfaces/libpq/libpq-fe.h index 97762d56f5..ba3ad7e0aa 100644 --- a/src/interfaces/libpq/libpq-fe.h +++ b/src/interfaces/libpq/libpq-fe.h @@ -593,6 +593,9 @@ extern unsigned char *PQescapeBytea(const unsigned char *from, size_t from_lengt size_t *to_length); +/* Control of dynamic propagation settings to state parameters */ +extern PGresult *PQlinkParameterStatus(PGconn *conn, const char *paramName); +extern PGresult *PQunlinkParameterStatus(PGconn *conn, const char *paramName); /* === in fe-print.c === */ diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h index c745facfec..081e228f2b 100644 --- a/src/interfaces/libpq/libpq-int.h +++ b/src/interfaces/libpq/libpq-int.h @@ -322,7 +322,8 @@ typedef enum PGQUERY_PREPARE, /* Parse only (PQprepare) */ PGQUERY_DESCRIBE, /* Describe Statement or Portal */ PGQUERY_SYNC, /* Sync (at end of a pipeline) */ - PGQUERY_CLOSE /* Close Statement or Portal */ + PGQUERY_CLOSE, /* Close Statement or Portal */ + PGQUERY_SETTING /* setting GUC_REPORT flag */ } PGQueryClass; /* @@ -718,6 +719,7 @@ extern PGresult *pqFunctionCall3(PGconn *conn, Oid fnid, int *result_buf, int *actual_result_len, int result_is_int, const PQArgBlock *args, int nargs); +extern int pqSendReportGUCMessage(PGconn *conn, const char *paramName, bool create_flag); /* === in fe-misc.c === */ -- 2.41.0