Skip to content

Commit 0e8ea91

Browse files
committed
feat: command_tag_format GUC with legacy/modern/verbose/fqn modes
Adds a new enum GUC command_tag_format (PGC_USERSET) with four modes: - legacy: INSERT 0 N (default, backward compatible) - modern: INSERT N (drops legacy OID field) - verbose: INSERT tablename N (shows relation name) - fqn: INSERT schema.tablename N (fully qualified) Tested output: legacy: INSERT 0 1 modern: INSERT 1 verbose: INSERT users 1 fqn: INSERT myschema.users 1 Supports SET LOCAL for per-transaction control. libpq PQcmdTuples() handles all formats gracefully. Note: verbose/fqn currently only populated for INSERT (UPDATE/DELETE show count only — relname propagation for those pending).
1 parent b6eb8dd commit 0e8ea91

6 files changed

Lines changed: 98 additions & 8 deletions

File tree

src/backend/tcop/cmdtag.c

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "postgres.h"
1515

1616
#include "tcop/cmdtag.h"
17+
#include "utils/guc.h"
1718
#include "utils/builtins.h"
1819

1920

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

3738
#undef PG_CMDTAG
3839

40+
/* GUC variable: command tag format style */
41+
int command_tag_format = COMMAND_TAG_FORMAT_LEGACY;
42+
3943
void
4044
InitializeQueryCompletion(QueryCompletion *qc)
4145
{
4246
qc->commandTag = CMDTAG_UNKNOWN;
4347
qc->nprocessed = 0;
48+
qc->relname = NULL;
49+
qc->nspname = NULL;
4450
}
4551

4652
const char *
@@ -147,8 +153,33 @@ BuildQueryCompletionString(char *buff, const QueryCompletion *qc,
147153
{
148154
if (tag == CMDTAG_INSERT)
149155
{
150-
*bufp++ = ' ';
151-
*bufp++ = '0';
156+
if (command_tag_format == COMMAND_TAG_FORMAT_LEGACY)
157+
{
158+
/* Legacy: INSERT 0 N */
159+
*bufp++ = ' ';
160+
*bufp++ = '0';
161+
}
162+
else if ((command_tag_format == COMMAND_TAG_FORMAT_VERBOSE ||
163+
command_tag_format == COMMAND_TAG_FORMAT_FQN) &&
164+
qc->relname != NULL)
165+
{
166+
/* Verbose/FQN: INSERT [schema.]table N */
167+
*bufp++ = ' ';
168+
if (command_tag_format == COMMAND_TAG_FORMAT_FQN &&
169+
qc->nspname != NULL)
170+
{
171+
Size nsplen = strlen(qc->nspname);
172+
memcpy(bufp, qc->nspname, nsplen);
173+
bufp += nsplen;
174+
*bufp++ = '.';
175+
}
176+
{
177+
Size rellen = strlen(qc->relname);
178+
memcpy(bufp, qc->relname, rellen);
179+
bufp += rellen;
180+
}
181+
}
182+
/* Modern: INSERT N (nothing extra before count) */
152183
}
153184
*bufp++ = ' ';
154185
bufp += pg_ulltoa_n(qc->nprocessed, bufp);

src/backend/tcop/pquery.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@
2626
#include "tcop/pquery.h"
2727
#include "tcop/utility.h"
2828
#include "utils/memutils.h"
29+
#include "catalog/namespace.h"
30+
#include "utils/rel.h"
31+
#include "utils/lsyscache.h"
2932
#include "utils/snapmgr.h"
3033

3134

@@ -181,6 +184,27 @@ ProcessQuery(PlannedStmt *plan,
181184
tag = CMDTAG_UNKNOWN;
182185

183186
SetQueryCompletion(qc, tag, queryDesc->estate->es_processed);
187+
188+
/* For verbose/FQN command tags, attach relation info for DML */
189+
if (command_tag_format >= COMMAND_TAG_FORMAT_VERBOSE &&
190+
(tag == CMDTAG_INSERT || tag == CMDTAG_UPDATE ||
191+
tag == CMDTAG_DELETE || tag == CMDTAG_MERGE) &&
192+
queryDesc->plannedstmt != NULL &&
193+
queryDesc->plannedstmt->resultRelations != NIL &&
194+
queryDesc->estate->es_result_relations != NULL)
195+
{
196+
int ri_index = linitial_int(queryDesc->plannedstmt->resultRelations) - 1;
197+
if (ri_index >= 0 &&
198+
ri_index < (int) queryDesc->estate->es_range_table_size &&
199+
queryDesc->estate->es_result_relations[ri_index] != NULL &&
200+
queryDesc->estate->es_result_relations[ri_index]->ri_RelationDesc != NULL)
201+
{
202+
ResultRelInfo *rri = queryDesc->estate->es_result_relations[ri_index];
203+
qc->relname = RelationGetRelationName(rri->ri_RelationDesc);
204+
qc->nspname = get_namespace_name(
205+
RelationGetNamespace(rri->ri_RelationDesc));
206+
}
207+
}
184208
}
185209

186210
/*

src/backend/utils/misc/guc_parameters.dat

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,7 @@
426426
options => 'client_message_level_options',
427427
},
428428

429+
429430
{ name => 'cluster_name', type => 'string', context => 'PGC_POSTMASTER', group => 'PROCESS_TITLE',
430431
short_desc => 'Sets the name of the cluster, which is included in the process title.',
431432
flags => 'GUC_IS_NAME',
@@ -435,6 +436,15 @@
435436
},
436437

437438
# we have no microseconds designation, so can't supply units here
439+
440+
{ name => 'command_tag_format', type => 'enum', context => 'PGC_USERSET', group => 'CLIENT_CONN_STATEMENT',
441+
short_desc => 'Controls the format of INSERT command completion tags.',
442+
long_desc => 'legacy: INSERT 0 N (default, backward compatible). modern: INSERT N (no OID). verbose: INSERT tablename N. fqn: INSERT schema.tablename N.',
443+
variable => 'command_tag_format',
444+
boot_val => 'COMMAND_TAG_FORMAT_LEGACY',
445+
options => 'command_tag_format_options',
446+
includes => 'tcop/cmdtag.h',
447+
},
438448
{ name => 'commit_delay', type => 'int', context => 'PGC_SUSET', group => 'WAL_SETTINGS',
439449
short_desc => 'Sets the delay in microseconds between transaction commit and flushing WAL to disk.',
440450
variable => 'CommitDelay',

src/backend/utils/misc/guc_tables.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
*--------------------------------------------------------------------
2020
*/
2121
#include "postgres.h"
22+
#include "tcop/cmdtag.h"
2223

2324
#ifdef HAVE_COPYFILE_H
2425
#include <copyfile.h>
@@ -148,6 +149,14 @@ static const struct config_enum_entry client_message_level_options[] = {
148149
{NULL, 0, false}
149150
};
150151

152+
static const struct config_enum_entry command_tag_format_options[] = {
153+
{"legacy", 0, false},
154+
{"modern", 1, false},
155+
{"verbose", 2, false},
156+
{"fqn", 3, false},
157+
{NULL, 0, false}
158+
};
159+
151160
const struct config_enum_entry server_message_level_options[] = {
152161
{"debug5", DEBUG5, false},
153162
{"debug4", DEBUG4, false},

src/include/tcop/cmdtag.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ typedef struct QueryCompletion
3030
{
3131
CommandTag commandTag;
3232
uint64 nprocessed;
33+
const char *relname; /* relation name for verbose command tags */
34+
const char *nspname; /* schema name for FQN command tags */
3335
} QueryCompletion;
3436

3537

@@ -56,6 +58,14 @@ extern bool command_tag_display_rowcount(CommandTag commandTag);
5658
extern bool command_tag_event_trigger_ok(CommandTag commandTag);
5759
extern bool command_tag_table_rewrite_ok(CommandTag commandTag);
5860
extern CommandTag GetCommandTagEnum(const char *commandname);
61+
62+
/* GUC: command tag format style */
63+
#define COMMAND_TAG_FORMAT_LEGACY 0 /* INSERT 0 N (default, backward compat) */
64+
#define COMMAND_TAG_FORMAT_MODERN 1 /* INSERT N (no OID) */
65+
#define COMMAND_TAG_FORMAT_VERBOSE 2 /* INSERT tablename N */
66+
#define COMMAND_TAG_FORMAT_FQN 3 /* INSERT schema.tablename N */
67+
68+
extern int command_tag_format;
5969
extern Size BuildQueryCompletionString(char *buff, const QueryCompletion *qc,
6070
bool nameonly);
6171

src/interfaces/libpq/fe-exec.c

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3847,12 +3847,18 @@ PQcmdTuples(PGresult *res)
38473847
if (strncmp(res->cmdStatus, "INSERT ", 7) == 0)
38483848
{
38493849
p = res->cmdStatus + 7;
3850-
/* INSERT: skip oid and space */
3851-
while (*p && *p != ' ')
3852-
p++;
3853-
if (*p == 0)
3854-
goto interpret_error; /* no space? */
3855-
p++;
3850+
/* INSERT: handle both "INSERT oid count" and "INSERT count" */
3851+
{
3852+
char *q = p;
3853+
while (*q && *q != ' ')
3854+
q++;
3855+
if (*q == ' ')
3856+
{
3857+
/* Old format: "INSERT oid count" - skip oid and space */
3858+
p = q + 1;
3859+
}
3860+
/* else: new format "INSERT count" - p already points to count */
3861+
}
38563862
}
38573863
else if (strncmp(res->cmdStatus, "SELECT ", 7) == 0 ||
38583864
strncmp(res->cmdStatus, "DELETE ", 7) == 0 ||

0 commit comments

Comments
 (0)