From 2f9661311b83dc481fc19f6e3bda015392010a40 Mon Sep 17 00:00:00 2001 From: Alvaro Herrera Date: Mon, 2 Mar 2020 18:19:51 -0300 Subject: Represent command completion tags as structs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The backend was using strings to represent command tags and doing string comparisons in multiple places, but that's slow and unhelpful. Create a new command list with a supporting structure to use instead; this is stored in a tag-list-file that can be tailored to specific purposes with a caller-definable C macro, similar to what we do for WAL resource managers. The first first such uses are a new CommandTag enum and a CommandTagBehavior struct. Replace numerous occurrences of char *completionTag with a QueryCompletion struct so that the code no longer stores information about completed queries in a cstring. Only at the last moment, in EndCommand(), does this get converted to a string. EventTriggerCacheItem no longer holds an array of palloc’d tag strings in sorted order, but rather just a Bitmapset over the CommandTags. Author: Mark Dilger, with unsolicited help from Álvaro Herrera Reviewed-by: John Naylor, Tom Lane Discussion: https://postgr.es/m/981A9DB4-3F0C-4DA5-88AD-CB9CFF4D6CAD@enterprisedb.com --- src/backend/tcop/postgres.c | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) (limited to 'src/backend/tcop/postgres.c') diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 23661ae15f5..9dba3b0566a 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -1064,8 +1064,8 @@ exec_simple_query(const char *query_string) { RawStmt *parsetree = lfirst_node(RawStmt, parsetree_item); bool snapshot_set = false; - const char *commandTag; - char completionTag[COMPLETION_TAG_BUFSIZE]; + CommandTag commandTag; + QueryCompletion qc; MemoryContext per_parsetree_context = NULL; List *querytree_list, *plantree_list; @@ -1081,7 +1081,7 @@ exec_simple_query(const char *query_string) */ commandTag = CreateCommandTag(parsetree->stmt); - set_ps_display(commandTag, false); + set_ps_display(GetCommandTagName(commandTag), false); BeginCommand(commandTag, dest); @@ -1239,7 +1239,7 @@ exec_simple_query(const char *query_string) true, receiver, receiver, - completionTag); + &qc); receiver->rDestroy(receiver); @@ -1290,7 +1290,7 @@ exec_simple_query(const char *query_string) * command the client sent, regardless of rewriting. (But a command * aborted by error will not send an EndCommand report at all.) */ - EndCommand(completionTag, dest); + EndCommand(&qc, dest, false); /* Now we may drop the per-parsetree context, if one was created. */ if (per_parsetree_context) @@ -1352,7 +1352,6 @@ exec_parse_message(const char *query_string, /* string to execute */ MemoryContext oldcontext; List *parsetree_list; RawStmt *raw_parse_tree; - const char *commandTag; List *querytree_list; CachedPlanSource *psrc; bool is_named; @@ -1438,11 +1437,6 @@ exec_parse_message(const char *query_string, /* string to execute */ raw_parse_tree = linitial_node(RawStmt, parsetree_list); - /* - * Get the command name for possible use in status display. - */ - commandTag = CreateCommandTag(raw_parse_tree->stmt); - /* * If we are in an aborted transaction, reject all commands except * COMMIT/ROLLBACK. It is important that this test occur before we @@ -1463,7 +1457,8 @@ exec_parse_message(const char *query_string, /* string to execute */ * Create the CachedPlanSource before we do parse analysis, since it * needs to see the unmodified raw parse tree. */ - psrc = CreateCachedPlan(raw_parse_tree, query_string, commandTag); + psrc = CreateCachedPlan(raw_parse_tree, query_string, + CreateCommandTag(raw_parse_tree->stmt)); /* * Set up a snapshot if parse analysis will need one. @@ -1514,8 +1509,8 @@ exec_parse_message(const char *query_string, /* string to execute */ { /* Empty input string. This is legal. */ raw_parse_tree = NULL; - commandTag = NULL; - psrc = CreateCachedPlan(raw_parse_tree, query_string, commandTag); + psrc = CreateCachedPlan(raw_parse_tree, query_string, + CMDTAG_UNKNOWN); querytree_list = NIL; } @@ -2031,7 +2026,7 @@ exec_execute_message(const char *portal_name, long max_rows) DestReceiver *receiver; Portal portal; bool completed; - char completionTag[COMPLETION_TAG_BUFSIZE]; + QueryCompletion qc; const char *sourceText; const char *prepStmtName; ParamListInfo portalParams; @@ -2058,7 +2053,7 @@ exec_execute_message(const char *portal_name, long max_rows) * If the original query was a null string, just return * EmptyQueryResponse. */ - if (portal->commandTag == NULL) + if (portal->commandTag == CMDTAG_UNKNOWN) { Assert(portal->stmts == NIL); NullCommand(dest); @@ -2104,7 +2099,7 @@ exec_execute_message(const char *portal_name, long max_rows) pgstat_report_activity(STATE_RUNNING, sourceText); - set_ps_display(portal->commandTag, false); + set_ps_display(GetCommandTagName(portal->commandTag), false); if (save_log_statement_stats) ResetUsage(); @@ -2185,7 +2180,7 @@ exec_execute_message(const char *portal_name, long max_rows) !execute_is_fetch && max_rows == FETCH_ALL, receiver, receiver, - completionTag); + &qc); receiver->rDestroy(receiver); @@ -2218,7 +2213,7 @@ exec_execute_message(const char *portal_name, long max_rows) } /* Send appropriate CommandComplete to client */ - EndCommand(completionTag, dest); + EndCommand(&qc, dest, false); } else { -- cgit v1.2.3