>> Move the definition of RelationData into utils/rel_internal.h.  Otherwise,
>> gen_node_support.pl cannot process rel.h after the anonymous unions are
>> introduced by the following commit, because the script does not support
>> parsing anonymous unions.
> 
> I really dislike this.  Why not do it the other way around, and put the
> one struct that gen_node_support.pl wants in a separate file instead?
> As in the attached WIP.  New file name TBD, of course.
That's indeed nicer.

I had moved struct RelationData to rel_internal.h as a quick workaround
when I started to be able to make progress without bothering. Now it's
time to fix this properly.

We can do what you suggest, or alternatively, teach gen_node_support.pl
to skip anonymous structs/unions in non-node structs. Then we can keep
all code as before in rel.h. See attached patch.

Once we settle on how to go forward, I'll update the main patch set.

--
David Geier
From 1f4b8568604b80f401044b8faa7a0bee567e2037 Mon Sep 17 00:00:00 2001
From: David Geier <[email protected]>
Date: Sun, 18 Oct 2026 13:33:35 +0200
Subject: [PATCH v1] gen_node_support.pl skips anonymous structs/unions

---
 src/backend/nodes/gen_node_support.pl | 33 +++++++++++++++++++++++++++
 src/include/utils/rel.h               | 13 +++++++++++
 2 files changed, 46 insertions(+)

diff --git a/src/backend/nodes/gen_node_support.pl 
b/src/backend/nodes/gen_node_support.pl
index 0b766272018..a2d198f72b3 100644
--- a/src/backend/nodes/gen_node_support.pl
+++ b/src/backend/nodes/gen_node_support.pl
@@ -193,6 +193,9 @@ foreach my $infile (@ARGV)
        my %my_field_types;
        my %my_field_attrs;
 
+       # nesting depth of an anonymous union/struct; the outermost level is 1
+       my $anon_nest = 0;
+
        # open file with name from command line, which may have a path prefix
        open my $ifh, '<', $infile or die "could not open \"$infile\": $!";
 
@@ -229,6 +232,34 @@ foreach my $infile (@ARGV)
                next if $line eq '';
                next if $line =~ /^#(define|ifdef|endif)/;
 
+               # Skip anonymous union/struct blocks. These are only allowed in
+               # non-node structs, whose fields we do not process.  Anonymous 
unions
+               # are not supported in node structs because their copy, equal, 
and
+               # serialization functions cannot be generated automatically.
+               if ($in_struct)
+               {
+                       if ($anon_nest > 0)
+                       {
+                               $anon_nest += ($line =~ tr/{//) - ($line =~ 
tr/}//);
+                               next;
+                       }
+                       elsif ($anon_nest == -1)
+                       {
+                               die "$infile:$lineno: expected '{' after 
anonymous union/struct\n"
+                                 unless $line =~ /^\s*\{\s*$/;
+                               $anon_nest = 1;
+                               next;
+                       }
+                       elsif ($line =~ /^\s*(?:union|struct)(?:\s*\{)?\s*$/)
+                       {
+                               die
+                                 "$infile:$lineno: anonymous union/struct not 
supported in node struct \"$in_struct\"\n"
+                                 if $is_node_struct;
+                               $anon_nest = ($line =~ /\{/) ? 1 : -1;
+                               next;
+                       }
+               }
+
                # within a struct, don't process until we have whole logical 
line
                if ($in_struct && $subline > 0)
                {
@@ -421,6 +452,7 @@ foreach my $infile (@ARGV)
                                @my_fields = ();
                                %my_field_types = ();
                                %my_field_attrs = ();
+                               $anon_nest = 0;
                        }
                        # normal struct field
                        elsif ($line =~
@@ -532,6 +564,7 @@ foreach my $infile (@ARGV)
                                $in_struct = $1;
                                $in_struct_lineno = $lineno;
                                $subline = 0;
+                               $anon_nest = 0;
                        }
                        # one node type typedef'ed directly from another
                        elsif ($line =~ /^typedef (\w+) (\w+);$/ and elem $1, 
@node_types)
diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h
index 7b8c2b1e362..54d1b653133 100644
--- a/src/include/utils/rel.h
+++ b/src/include/utils/rel.h
@@ -54,6 +54,19 @@ typedef LockInfoData *LockInfo;
 
 typedef struct RelationData
 {
+       union
+       {
+               struct
+               {
+                       int Foo;
+               };
+
+               struct
+               {
+                       long Bar;
+               };
+       };
+
        RelFileLocator rd_locator;      /* relation physical identifier */
        SMgrRelation rd_smgr;           /* cached file handle, or NULL */
        int                     rd_refcnt;              /* reference count */
-- 
2.55.0

Reply via email to