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