Hi Hackers,

When reading dumped parse/query/plan trees, sometime we want to know what exact type/operator/function an OID stands for. I just added a new feature that will add some OID descriptions to the dump trees, like:

```

      :scan.scanrelid 1
      :indexid 16474 # index orders_pkey
      :indexqual (
         {OPEXPR
         :opno 521 # operator >(integer,integer)
         :opfuncid 147 # function int4gt(integer,integer)
         :opresulttype 16 # type boolean
         :opretset false
         :opcollid 0

```

The patch file is attached.

Best regards,

--
Chao Li (Evan)
HighGo Software Co., Ltd.
https://www.highgo.com/
From 182a6020b7b9f5733c773f0f04e472b59c223144 Mon Sep 17 00:00:00 2001
From: "Chao Li (Evan)" <l...@highgo.com>
Date: Fri, 22 Aug 2025 13:55:13 +0800
Subject: [PATCH v1] Add OID descriptions to dumped parse/query/plan trees

Include descriptions for certain OIDs in dumped trees, using "#" in the
style of code comments. This makes the trees easier to read. For example:

```
  :scan.scanrelid 1
  :indexid 16474 # index orders_pkey
  :indexqual (
     {OPEXPR
     :opno 521 # operator >(integer,integer)
     :opfuncid 147 # function int4gt(integer,integer)
     :opresulttype 16 # type boolean
     :opretset false
     :opcollid 0
```

This patch also fixes a trivial bug where an extra whitespace was added
when dumping an array, for example:

```
  :sort.numCols 2
  :sort.sortColIdx ( 1 4)
  :sort.sortOperators ( 97 1754)
  :sort.collations ( 0 0)
  :sort.nullsFirst ( false false)
```

The unnecessary whitespace is now removed.

Author: Li Chao <l...@highgo.com>
---
 src/backend/nodes/outfuncs.c | 99 +++++++++++++++++++++++++++++++++---
 1 file changed, 91 insertions(+), 8 deletions(-)

diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index eaf391fc2ab..7c0314e7e4a 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -17,6 +17,11 @@
 #include <ctype.h>
 
 #include "access/attnum.h"
+#include "catalog/objectaddress.h"
+#include "catalog/pg_class.h"
+#include "catalog/pg_operator.h"
+#include "catalog/pg_proc.h"
+#include "catalog/pg_type.h"
 #include "common/shortest_dec.h"
 #include "lib/stringinfo.h"
 #include "miscadmin.h"
@@ -30,6 +35,8 @@ static bool write_location_fields = false;
 
 static void outChar(StringInfo str, char c);
 static void outDouble(StringInfo str, double d);
+static char *oidToString(const char *attName, Oid oid);
+static char *oidArrayToString(const char *attName, const Oid *oids, int len);
 
 
 /*
@@ -64,7 +71,12 @@ static void outDouble(StringInfo str, double d);
 
 /* Write an OID field (don't hard-wire assumption that OID is same as uint) */
 #define WRITE_OID_FIELD(fldname) \
-       appendStringInfo(str, " :" CppAsString(fldname) " %u", node->fldname)
+       { \
+               char * s = oidToString(CppAsString(fldname), node->fldname); \
+               appendStringInfo(str, " :" CppAsString(fldname) " %u", 
node->fldname); \
+               if (s != NULL) \
+                       appendStringInfo(str, " # %s", s); \
+       }
 
 /* Write a long-integer field */
 #define WRITE_LONG_FIELD(fldname) \
@@ -121,8 +133,12 @@ static void outDouble(StringInfo str, double d);
 
 /* Write a variable-length array of Oid */
 #define WRITE_OID_ARRAY(fldname, len) \
-       (appendStringInfoString(str, " :" CppAsString(fldname) " "), \
-        writeOidCols(str, node->fldname, len))
+       { \
+               char *s = oidArrayToString(CppAsString(fldname), node->fldname, 
len); \
+               appendStringInfoString(str, " :" CppAsString(fldname) " "); \
+               writeOidCols(str, node->fldname, len); \
+               if (s != NULL) appendStringInfo(str, " # %s", s); \
+       }
 
 /* Write a variable-length array of Index */
 #define WRITE_INDEX_ARRAY(fldname, len) \
@@ -222,6 +238,69 @@ outDouble(StringInfo str, double d)
        appendStringInfoString(str, buf);
 }
 
+static char *
+oidToString(const char *attName, Oid oid)
+{
+       ObjectAddress ob;
+
+       ob.objectId = oid;
+       ob.objectSubId = 0;
+       if ((strncmp(attName, "opno", 5) == 0) ||
+               (strncmp(attName, "eqop", 5) == 0) ||
+               (strncmp(attName, "sortop", 7) == 0) ||
+               (strncmp(attName, "sort.sortOperators", 19) == 0))
+       {
+               ob.classId = OperatorRelationId;
+       }
+       else if ((strncmp(attName, "opfuncid", 9) == 0) ||
+                        (strncmp(attName, "funcid", 7) == 0))
+       {
+               ob.classId = ProcedureRelationId;
+       }
+       else if ((strncmp(attName, "opresulttype", 13) == 0) ||
+                        (strncmp(attName, "vartype", 8) == 0) ||
+                        (strncmp(attName, "consttype", 10) == 0) ||
+                        (strncmp(attName, "funcresulttype", 15) == 0))
+       {
+               ob.classId = TypeRelationId;
+       }
+       else if ((strncmp(attName, "relid", 5) == 0) ||
+                        (strncmp(attName, "indexid", 8) == 0))
+       {
+               ob.classId = RelationRelationId;
+       }
+       else
+       {
+               return NULL;
+       }
+       return getObjectDescription(&ob, true);
+}
+
+static char *
+oidArrayToString(const char *attName, const Oid *oids, int len)
+{
+       StringInfoData str;
+       int                     i;
+       char       *desc;
+
+       initStringInfo(&str);
+       for (i = 0; i < len; i++)
+       {
+               desc = oidToString(attName, oids[i]);
+               if (desc != NULL)
+               {
+                       if (i > 0)
+                               appendStringInfoString(&str, ", ");
+                       appendStringInfo(&str, "%s", desc);
+               }
+               else
+               {
+                       return NULL;
+               }
+       }
+       return str.data;
+}
+
 /*
  * common implementation for scalar-array-writing functions
  *
@@ -238,18 +317,22 @@ fnname(StringInfo str, const datatype *arr, int len) \
        { \
                appendStringInfoChar(str, '('); \
                for (int i = 0; i < len; i++) \
+               { \
                        appendStringInfo(str, fmtstr, convfunc(arr[i])); \
+                       if (i < len - 1) \
+                               appendStringInfoChar(str, ' '); \
+               } \
                appendStringInfoChar(str, ')'); \
        } \
        else \
                appendStringInfoString(str, "<>"); \
 }
 
-WRITE_SCALAR_ARRAY(writeAttrNumberCols, AttrNumber, " %d",)
-WRITE_SCALAR_ARRAY(writeOidCols, Oid, " %u",)
-WRITE_SCALAR_ARRAY(writeIndexCols, Index, " %u",)
-WRITE_SCALAR_ARRAY(writeIntCols, int, " %d",)
-WRITE_SCALAR_ARRAY(writeBoolCols, bool, " %s", booltostr)
+WRITE_SCALAR_ARRAY(writeAttrNumberCols, AttrNumber, "%d",)
+WRITE_SCALAR_ARRAY(writeOidCols, Oid, "%u",)
+WRITE_SCALAR_ARRAY(writeIndexCols, Index, "%u",)
+WRITE_SCALAR_ARRAY(writeIntCols, int, "%d",)
+WRITE_SCALAR_ARRAY(writeBoolCols, bool, "%s", booltostr)
 
 /*
  * Print an array (not a List) of Node pointers.
-- 
2.39.5 (Apple Git-154)

Reply via email to