PostgreSQL Source Code  git master
cmdtag.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * cmdtag.c
4  * Data and routines for commandtag names and enumeration.
5  *
6  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  * IDENTIFICATION
10  * src/backend/tcop/cmdtag.c
11  *
12  *-------------------------------------------------------------------------
13  */
14 #include "postgres.h"
15 
16 #include "miscadmin.h"
17 #include "tcop/cmdtag.h"
18 #include "utils/builtins.h"
19 
20 
21 typedef struct CommandTagBehavior
22 {
23  const char *name; /* tag name, e.g. "SELECT" */
24  const uint8 namelen; /* set to strlen(name) */
25  const bool event_trigger_ok;
26  const bool table_rewrite_ok;
27  const bool display_rowcount; /* should the number of rows affected be
28  * shown in the command completion string */
30 
31 #define PG_CMDTAG(tag, name, evtrgok, rwrok, rowcnt) \
32  { name, (uint8) (sizeof(name) - 1), evtrgok, rwrok, rowcnt },
33 
35 #include "tcop/cmdtaglist.h"
36 };
37 
38 #undef PG_CMDTAG
39 
40 void
42 {
43  qc->commandTag = CMDTAG_UNKNOWN;
44  qc->nprocessed = 0;
45 }
46 
47 const char *
49 {
50  return tag_behavior[commandTag].name;
51 }
52 
53 const char *
55 {
56  *len = (Size) tag_behavior[commandTag].namelen;
57  return tag_behavior[commandTag].name;
58 }
59 
60 bool
62 {
63  return tag_behavior[commandTag].display_rowcount;
64 }
65 
66 bool
68 {
69  return tag_behavior[commandTag].event_trigger_ok;
70 }
71 
72 bool
74 {
75  return tag_behavior[commandTag].table_rewrite_ok;
76 }
77 
78 /*
79  * Search CommandTag by name
80  *
81  * Returns CommandTag, or CMDTAG_UNKNOWN if not recognized
82  */
84 GetCommandTagEnum(const char *commandname)
85 {
86  const CommandTagBehavior *base,
87  *last,
88  *position;
89  int result;
90 
91  if (commandname == NULL || *commandname == '\0')
92  return CMDTAG_UNKNOWN;
93 
94  base = tag_behavior;
95  last = tag_behavior + lengthof(tag_behavior) - 1;
96  while (last >= base)
97  {
98  position = base + ((last - base) >> 1);
99  result = pg_strcasecmp(commandname, position->name);
100  if (result == 0)
101  return (CommandTag) (position - tag_behavior);
102  else if (result < 0)
103  last = position - 1;
104  else
105  base = position + 1;
106  }
107  return CMDTAG_UNKNOWN;
108 }
109 
110 /*
111  * BuildQueryCompletionString
112  * Build a string containing the command tag name with the
113  * QueryCompletion's nprocessed for command tags with display_rowcount
114  * set. Returns the strlen of the constructed string.
115  *
116  * The caller must ensure that buff is at least COMPLETION_TAG_BUFSIZE bytes.
117  *
118  * If nameonly is true, then the constructed string will contain only the tag
119  * name.
120  */
121 Size
123  bool nameonly)
124 {
125  CommandTag tag = qc->commandTag;
126  Size taglen;
127  const char *tagname = GetCommandTagNameAndLen(tag, &taglen);
128  char *bufp;
129 
130  /*
131  * We assume the tagname is plain ASCII and therefore requires no encoding
132  * conversion.
133  */
134  memcpy(buff, tagname, taglen);
135  bufp = buff + taglen;
136 
137  /* ensure that the tagname isn't long enough to overrun the buffer */
138  Assert(taglen <= COMPLETION_TAG_BUFSIZE - MAXINT8LEN - 4);
139 
140  /*
141  * In PostgreSQL versions 11 and earlier, it was possible to create a
142  * table WITH OIDS. When inserting into such a table, INSERT used to
143  * include the Oid of the inserted record in the completion tag. To
144  * maintain compatibility in the wire protocol, we now write a "0" (for
145  * InvalidOid) in the location where we once wrote the new record's Oid.
146  */
147  if (command_tag_display_rowcount(tag) && !nameonly)
148  {
149  if (tag == CMDTAG_INSERT)
150  {
151  *bufp++ = ' ';
152  *bufp++ = '0';
153  }
154  *bufp++ = ' ';
155  bufp += pg_ulltoa_n(qc->nprocessed, bufp);
156  }
157 
158  /* and finally, NUL terminate the string */
159  *bufp = '\0';
160 
161  Assert((bufp - buff) == strlen(buff));
162 
163  return bufp - buff;
164 }
#define MAXINT8LEN
Definition: builtins.h:22
#define lengthof(array)
Definition: c.h:772
unsigned char uint8
Definition: c.h:488
size_t Size
Definition: c.h:589
void InitializeQueryCompletion(QueryCompletion *qc)
Definition: cmdtag.c:41
struct CommandTagBehavior CommandTagBehavior
const char * GetCommandTagNameAndLen(CommandTag commandTag, Size *len)
Definition: cmdtag.c:54
CommandTag GetCommandTagEnum(const char *commandname)
Definition: cmdtag.c:84
bool command_tag_event_trigger_ok(CommandTag commandTag)
Definition: cmdtag.c:67
static const CommandTagBehavior tag_behavior[COMMAND_TAG_NEXTTAG]
Definition: cmdtag.c:34
bool command_tag_table_rewrite_ok(CommandTag commandTag)
Definition: cmdtag.c:73
bool command_tag_display_rowcount(CommandTag commandTag)
Definition: cmdtag.c:61
Size BuildQueryCompletionString(char *buff, const QueryCompletion *qc, bool nameonly)
Definition: cmdtag.c:122
const char * GetCommandTagName(CommandTag commandTag)
Definition: cmdtag.c:48
#define COMPLETION_TAG_BUFSIZE
Definition: cmdtag.h:17
CommandTag
Definition: cmdtag.h:23
@ COMMAND_TAG_NEXTTAG
Definition: cmdtag.h:25
Assert(fmt[strlen(fmt) - 1] !='\n')
int pg_ulltoa_n(uint64 value, char *a)
Definition: numutils.c:738
const void size_t len
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36
const bool table_rewrite_ok
Definition: cmdtag.c:26
const uint8 namelen
Definition: cmdtag.c:24
const bool event_trigger_ok
Definition: cmdtag.c:25
const bool display_rowcount
Definition: cmdtag.c:27
const char * name
Definition: cmdtag.c:23
uint64 nprocessed
Definition: cmdtag.h:33
CommandTag commandTag
Definition: cmdtag.h:32