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[] = { 34 : #include "tcop/cmdtaglist.h" 35 : }; 36 : 37 : #undef PG_CMDTAG 38 : 39 : void 40 737458 : InitializeQueryCompletion(QueryCompletion *qc) 41 : { 42 737458 : qc->commandTag = CMDTAG_UNKNOWN; 43 737458 : qc->nprocessed = 0; 44 737458 : } 45 : 46 : const char * 47 17276 : GetCommandTagName(CommandTag commandTag) 48 : { 49 17276 : return tag_behavior[commandTag].name; 50 : } 51 : 52 : const char * 53 1222076 : GetCommandTagNameAndLen(CommandTag commandTag, Size *len) 54 : { 55 1222076 : *len = (Size) tag_behavior[commandTag].namelen; 56 1222076 : return tag_behavior[commandTag].name; 57 : } 58 : 59 : bool 60 557072 : command_tag_display_rowcount(CommandTag commandTag) 61 : { 62 557072 : return tag_behavior[commandTag].display_rowcount; 63 : } 64 : 65 : bool 66 140 : command_tag_event_trigger_ok(CommandTag commandTag) 67 : { 68 140 : return tag_behavior[commandTag].event_trigger_ok; 69 : } 70 : 71 : bool 72 0 : command_tag_table_rewrite_ok(CommandTag commandTag) 73 : { 74 0 : 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 434 : GetCommandTagEnum(const char *commandname) 84 : { 85 : const CommandTagBehavior *base, 86 : *last, 87 : *position; 88 : int result; 89 : 90 434 : if (commandname == NULL || *commandname == '\0') 91 0 : return CMDTAG_UNKNOWN; 92 : 93 434 : base = tag_behavior; 94 434 : last = tag_behavior + lengthof(tag_behavior) - 1; 95 3176 : while (last >= base) 96 : { 97 3164 : position = base + ((last - base) >> 1); 98 3164 : result = pg_strcasecmp(commandname, position->name); 99 3164 : if (result == 0) 100 422 : return (CommandTag) (position - tag_behavior); 101 2742 : else if (result < 0) 102 1000 : last = position - 1; 103 : else 104 1742 : base = position + 1; 105 : } 106 12 : 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 121 557072 : BuildQueryCompletionString(char *buff, const QueryCompletion *qc, 122 : bool nameonly) 123 : { 124 557072 : CommandTag tag = qc->commandTag; 125 : Size taglen; 126 557072 : 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 557072 : memcpy(buff, tagname, taglen); 134 557072 : bufp = buff + taglen; 135 : 136 : /* ensure that the tagname isn't long enough to overrun the buffer */ 137 : 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 557072 : if (command_tag_display_rowcount(tag) && !nameonly) 147 : { 148 343068 : if (tag == CMDTAG_INSERT) 149 : { 150 64084 : *bufp++ = ' '; 151 64084 : *bufp++ = '0'; 152 : } 153 343068 : *bufp++ = ' '; 154 343068 : bufp += pg_ulltoa_n(qc->nprocessed, bufp); 155 : } 156 : 157 : /* and finally, NUL terminate the string */ 158 557072 : *bufp = '\0'; 159 : 160 : Assert((bufp - buff) == strlen(buff)); 161 : 162 557072 : return bufp - buff; 163 : }