Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 17 additions & 5 deletions src/backend/tcop/backend_startup.c
Original file line number Diff line number Diff line change
Expand Up @@ -778,12 +778,24 @@ ProcessStartupPacket(Port *port, bool ssl_done, bool gss_done)
else if (strncmp(nameptr, "_pq_.", 5) == 0)
{
/*
* Any option beginning with _pq_. is reserved for use as a
* protocol-level option, but at present no such options are
* defined.
* Options beginning with _pq_. are protocol-level options.
* Recognized options are mapped to their corresponding GUCs.
*/
unrecognized_protocol_options =
lappend(unrecognized_protocol_options, pstrdup(nameptr));
if (strcmp(nameptr, "_pq_.command_tag_format") == 0)
{
/*
* Protocol-level option: store for deferred application
* in process_startup_options() after GUC init. This
* is NOT added to guc_options so that old-style
* options=-c cannot set it (GUC is PGC_INTERNAL).
*/
port->pq_command_tag_format = pstrdup(valptr);
}
else
{
unrecognized_protocol_options =
lappend(unrecognized_protocol_options, pstrdup(nameptr));
}
}
else
{
Expand Down
35 changes: 33 additions & 2 deletions src/backend/tcop/cmdtag.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "postgres.h"

#include "tcop/cmdtag.h"
#include "utils/guc.h"
#include "utils/builtins.h"


Expand All @@ -36,11 +37,16 @@ static const CommandTagBehavior tag_behavior[] = {

#undef PG_CMDTAG

/* GUC variable: command tag format style */
int command_tag_format = COMMAND_TAG_FORMAT_LEGACY;

void
InitializeQueryCompletion(QueryCompletion *qc)
{
qc->commandTag = CMDTAG_UNKNOWN;
qc->nprocessed = 0;
qc->relname = NULL;
qc->nspname = NULL;
}

const char *
Expand Down Expand Up @@ -147,8 +153,33 @@ BuildQueryCompletionString(char *buff, const QueryCompletion *qc,
{
if (tag == CMDTAG_INSERT)
{
*bufp++ = ' ';
*bufp++ = '0';
if (command_tag_format == COMMAND_TAG_FORMAT_LEGACY)
{
/* Legacy: INSERT 0 N */
*bufp++ = ' ';
*bufp++ = '0';
}
else if ((command_tag_format == COMMAND_TAG_FORMAT_VERBOSE ||
command_tag_format == COMMAND_TAG_FORMAT_FQN) &&
qc->relname != NULL)
{
/* Verbose/FQN: INSERT [schema.]table N */
*bufp++ = ' ';
if (command_tag_format == COMMAND_TAG_FORMAT_FQN &&
qc->nspname != NULL)
{
Size nsplen = strlen(qc->nspname);
memcpy(bufp, qc->nspname, nsplen);
bufp += nsplen;
*bufp++ = '.';
}
{
Size rellen = strlen(qc->relname);
memcpy(bufp, qc->relname, rellen);
bufp += rellen;
}
}
/* Modern: INSERT N (nothing extra before count) */
}
*bufp++ = ' ';
bufp += pg_ulltoa_n(qc->nprocessed, bufp);
Expand Down
24 changes: 24 additions & 0 deletions src/backend/tcop/pquery.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@
#include "tcop/pquery.h"
#include "tcop/utility.h"
#include "utils/memutils.h"
#include "catalog/namespace.h"
#include "utils/rel.h"
#include "utils/lsyscache.h"
#include "utils/snapmgr.h"


Expand Down Expand Up @@ -181,6 +184,27 @@ ProcessQuery(PlannedStmt *plan,
tag = CMDTAG_UNKNOWN;

SetQueryCompletion(qc, tag, queryDesc->estate->es_processed);

/* For verbose/FQN command tags, attach relation info for DML */
if (command_tag_format >= COMMAND_TAG_FORMAT_VERBOSE &&
(tag == CMDTAG_INSERT || tag == CMDTAG_UPDATE ||
tag == CMDTAG_DELETE || tag == CMDTAG_MERGE) &&
queryDesc->plannedstmt != NULL &&
queryDesc->plannedstmt->resultRelations != NIL &&
queryDesc->estate->es_result_relations != NULL)
{
int ri_index = linitial_int(queryDesc->plannedstmt->resultRelations) - 1;
if (ri_index >= 0 &&
ri_index < (int) queryDesc->estate->es_range_table_size &&
queryDesc->estate->es_result_relations[ri_index] != NULL &&
queryDesc->estate->es_result_relations[ri_index]->ri_RelationDesc != NULL)
{
ResultRelInfo *rri = queryDesc->estate->es_result_relations[ri_index];
qc->relname = RelationGetRelationName(rri->ri_RelationDesc);
qc->nspname = get_namespace_name(
RelationGetNamespace(rri->ri_RelationDesc));
}
}
}

/*
Expand Down
11 changes: 11 additions & 0 deletions src/backend/utils/init/postinit.c
Original file line number Diff line number Diff line change
Expand Up @@ -1309,6 +1309,17 @@ process_startup_options(Port *port, bool am_superuser)

SetConfigOption(name, value, gucctx, PGC_S_CLIENT);
}

/*
* Apply protocol-negotiated options. These use PGC_INTERNAL context
* with PGC_S_OVERRIDE source, so they bypass the normal GUC access
* controls. This ensures only the _pq_ protocol path can set them;
* SET and options=-c are blocked by PGC_INTERNAL.
*/
if (port->pq_command_tag_format != NULL)
SetConfigOption("command_tag_format",
port->pq_command_tag_format,
PGC_INTERNAL, PGC_S_OVERRIDE);
}

/*
Expand Down
10 changes: 10 additions & 0 deletions src/backend/utils/misc/guc_parameters.dat
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,16 @@
check_hook => 'check_cluster_name',
},


{ name => 'command_tag_format', type => 'enum', context => 'PGC_INTERNAL', group => 'CLIENT_CONN_STATEMENT',
short_desc => 'Controls the format of INSERT command completion tags.',
long_desc => 'legacy: INSERT 0 N (default, backward compatible). verbose: INSERT tablename N. fqn: INSERT schema.tablename N. Can be set via _pq_.command_tag_format startup parameter for protocol-level negotiation.',
flags => 'GUC_REPORT',
variable => 'command_tag_format',
boot_val => 'COMMAND_TAG_FORMAT_LEGACY',
options => 'command_tag_format_options',
includes => 'tcop/cmdtag.h',
},
# we have no microseconds designation, so can't supply units here
{ name => 'commit_delay', type => 'int', context => 'PGC_SUSET', group => 'WAL_SETTINGS',
short_desc => 'Sets the delay in microseconds between transaction commit and flushing WAL to disk.',
Expand Down
8 changes: 8 additions & 0 deletions src/backend/utils/misc/guc_tables.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
*--------------------------------------------------------------------
*/
#include "postgres.h"
#include "tcop/cmdtag.h"

#ifdef HAVE_COPYFILE_H
#include <copyfile.h>
Expand Down Expand Up @@ -148,6 +149,13 @@ static const struct config_enum_entry client_message_level_options[] = {
{NULL, 0, false}
};

static const struct config_enum_entry command_tag_format_options[] = {
{"legacy", 0, false},
{"verbose", 1, false},
{"fqn", 2, false},
{NULL, 0, false}
};

const struct config_enum_entry server_message_level_options[] = {
{"debug5", DEBUG5, false},
{"debug4", DEBUG4, false},
Expand Down
3 changes: 3 additions & 0 deletions src/include/libpq/libpq-be.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,9 @@ typedef struct Port
char *cmdline_options;
List *guc_options;

/* Protocol-negotiated command tag format (from _pq_.command_tag_format) */
char *pq_command_tag_format;

/*
* The startup packet application name, only used here for the "connection
* authorized" log message. We shouldn't use this post-startup, instead
Expand Down
9 changes: 9 additions & 0 deletions src/include/tcop/cmdtag.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ typedef struct QueryCompletion
{
CommandTag commandTag;
uint64 nprocessed;
const char *relname; /* relation name for verbose command tags */
const char *nspname; /* schema name for FQN command tags */
} QueryCompletion;


Expand All @@ -56,6 +58,13 @@ extern bool command_tag_display_rowcount(CommandTag commandTag);
extern bool command_tag_event_trigger_ok(CommandTag commandTag);
extern bool command_tag_table_rewrite_ok(CommandTag commandTag);
extern CommandTag GetCommandTagEnum(const char *commandname);

/* GUC: command tag format style */
#define COMMAND_TAG_FORMAT_LEGACY 0 /* INSERT 0 N (default, backward compat) */
#define COMMAND_TAG_FORMAT_VERBOSE 1 /* INSERT tablename N */
#define COMMAND_TAG_FORMAT_FQN 2 /* INSERT schema.tablename N */

extern int command_tag_format;
extern Size BuildQueryCompletionString(char *buff, const QueryCompletion *qc,
bool nameonly);

Expand Down