From d1e883fa81ebc50b211cbcf9573fd39454169cee Mon Sep 17 00:00:00 2001
From: "Chao Li (HighGo Inc.)" <li.evan.chao@gmail.com>
Date: Thu, 31 Jul 2025 17:02:32 +0800
Subject: [PATCH v2] Add support for dumping raw parse tree with
 debug_print_raw_parse

This patch introduces a small change to log the raw parse tree in the
same way we currently log the parse tree, rewritten tree, and plan tree.
While tracing some queries, I found that being able to inspect the raw
parse tree is also helpful for understanding query transformation.

Although the raw parse tree can be inspected via a debugger, having it
logged simplifies the workflow for those interested in this stage of
query processing, without requiring a debugging session.

To avoid unnecessary log noise for users not interested in this detail,
a new GUC option, "debug_print_raw_parse", has been added.

When starting the PostgreSQL process with "-d N", and N is 3 or higher,
debug_print_raw_parse is enabled automatically, alongside
debug_print_parse.

Author: Chao Li <li.evan.chao@gmail.com>
Discussion: https://www.postgresql.org/message-id/CAEoWx2mcO0Gpo4vd8kPMAFWeJLSp0MeUUnaLdE1x0tSVd-VzUw%40mail.gmail.com
---
 doc/src/sgml/config.sgml                      |  8 +++++++-
 src/backend/tcop/postgres.c                   |  7 +++++++
 src/backend/utils/misc/guc_tables.c           | 10 ++++++++++
 src/backend/utils/misc/postgresql.conf.sample |  1 +
 src/include/utils/guc.h                       |  1 +
 5 files changed, 26 insertions(+), 1 deletion(-)

diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 20ccb2d6b54..4370e8307f2 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -7382,6 +7382,11 @@ local0.*    /var/log/postgresql
      </varlistentry>
 
      <varlistentry id="guc-debug-print-parse">
+      <term><varname>debug_print_raw_parse</varname> (<type>boolean</type>)
+      <indexterm>
+       <primary><varname>debug_print_raw_parse</varname> configuration parameter</primary>
+      </indexterm>
+      </term>
       <term><varname>debug_print_parse</varname> (<type>boolean</type>)
       <indexterm>
        <primary><varname>debug_print_parse</varname> configuration parameter</primary>
@@ -7421,7 +7426,8 @@ local0.*    /var/log/postgresql
       <listitem>
        <para>
         When set, <varname>debug_pretty_print</varname> indents the messages
-        produced by <varname>debug_print_parse</varname>,
+        produced by <varname>debug_print_raw_parse</varname>,
+        <varname>debug_print_parse</varname>,
         <varname>debug_print_rewritten</varname>, or
         <varname>debug_print_plan</varname>.  This results in more readable
         but much longer output than the <quote>compact</quote> format used when
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 0cecd464902..d356830f756 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -649,6 +649,10 @@ pg_parse_query(const char *query_string)
 
 	TRACE_POSTGRESQL_QUERY_PARSE_DONE(query_string);
 
+	if (Debug_print_raw_parse)
+		elog_node_display(LOG, "raw parse tree", raw_parsetree_list,
+						  Debug_pretty_print);
+
 	return raw_parsetree_list;
 }
 
@@ -3697,7 +3701,10 @@ set_debug_options(int debug_flag, GucContext context, GucSource source)
 	if (debug_flag >= 2)
 		SetConfigOption("log_statement", "all", context, source);
 	if (debug_flag >= 3)
+	{
+		SetConfigOption("debug_print_raw_parse", "true", context, source);
 		SetConfigOption("debug_print_parse", "true", context, source);
+	}
 	if (debug_flag >= 4)
 		SetConfigOption("debug_print_plan", "true", context, source);
 	if (debug_flag >= 5)
diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c
index d14b1678e7f..f4e0b6a5274 100644
--- a/src/backend/utils/misc/guc_tables.c
+++ b/src/backend/utils/misc/guc_tables.c
@@ -507,6 +507,7 @@ bool		AllowAlterSystem = true;
 bool		log_duration = false;
 bool		Debug_print_plan = false;
 bool		Debug_print_parse = false;
+bool		Debug_print_raw_parse = false;
 bool		Debug_print_rewritten = false;
 bool		Debug_pretty_print = true;
 
@@ -1385,6 +1386,15 @@ struct config_bool ConfigureNamesBool[] =
 		NULL, NULL, NULL
 	},
 #endif							/* DEBUG_NODE_TESTS_ENABLED */
+	{
+		{"debug_print_raw_parse", PGC_USERSET, LOGGING_WHAT,
+			gettext_noop("Logs each query's raw parse tree."),
+			NULL
+		},
+		&Debug_print_raw_parse,
+		false,
+		NULL, NULL, NULL
+	},
 	{
 		{"debug_print_parse", PGC_USERSET, LOGGING_WHAT,
 			gettext_noop("Logs each query's parse tree."),
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index a9d8293474a..26c08693564 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -581,6 +581,7 @@
 
 # - What to Log -
 
+#debug_print_raw_parse = off
 #debug_print_parse = off
 #debug_print_rewritten = off
 #debug_print_plan = off
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index f619100467d..d06ddade7f0 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -247,6 +247,7 @@ typedef enum
 /* GUC vars that are actually defined in guc_tables.c, rather than elsewhere */
 extern PGDLLIMPORT bool Debug_print_plan;
 extern PGDLLIMPORT bool Debug_print_parse;
+extern PGDLLIMPORT bool Debug_print_raw_parse;
 extern PGDLLIMPORT bool Debug_print_rewritten;
 extern PGDLLIMPORT bool Debug_pretty_print;
 
-- 
2.39.5 (Apple Git-154)

