Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 7c0eb3c

Browse files
committed
Tighten up parsing logic in gen_node_support.pl.
Teach this script to handle function pointer fields honestly. Previously they were just silently ignored, but that's not likely to be a behavior we can accept indefinitely. This mostly entails fixing it so that a field declaration spanning multiple lines can be parsed, because we have a bunch of such fields that're laid out that way. But that's a good improvement in its own right. With that change and a minor regex adjustment, the only struct it fails to parse in the node-defining headers is A_Const, because of the embedded union. The path of least resistance is to move that union declaration outside the struct. Having done those things, we can make it error out if it finds any within-struct syntax it doesn't understand, which seems like a pretty important property for robustness. This commit doesn't change the output files at all; it's just in the way of future-proofing. Discussion: https://postgr.es/m/2593369.1657759779@sss.pgh.pa.us
1 parent 5794491 commit 7c0eb3c

File tree

3 files changed

+90
-20
lines changed

3 files changed

+90
-20
lines changed

src/backend/nodes/gen_node_support.pl

+73-4
Original file line numberDiff line numberDiff line change
@@ -213,15 +213,39 @@ sub elem
213213
}
214214
$file_content .= $raw_file_content;
215215

216-
my $lineno = 0;
216+
my $lineno = 0;
217+
my $prevline = '';
217218
foreach my $line (split /\n/, $file_content)
218219
{
220+
# per-physical-line processing
219221
$lineno++;
220222
chomp $line;
221223
$line =~ s/\s*$//;
222224
next if $line eq '';
223225
next if $line =~ /^#(define|ifdef|endif)/;
224226

227+
# within a struct, don't process until we have whole logical line
228+
if ($in_struct && $subline > 0)
229+
{
230+
if ($line =~ /;$/)
231+
{
232+
# found the end, re-attach any previous line(s)
233+
$line = $prevline . $line;
234+
$prevline = '';
235+
}
236+
elsif ($prevline eq ''
237+
&& $line =~ /^\s*pg_node_attr\(([\w(), ]*)\)$/)
238+
{
239+
# special case: node-attributes line doesn't end with semi
240+
}
241+
else
242+
{
243+
# set it aside for a moment
244+
$prevline .= $line . ' ';
245+
next;
246+
}
247+
}
248+
225249
# we are analyzing a struct definition
226250
if ($in_struct)
227251
{
@@ -394,7 +418,7 @@ sub elem
394418
}
395419
# normal struct field
396420
elsif ($line =~
397-
/^\s*(.+)\s*\b(\w+)(\[\w+\])?\s*(?:pg_node_attr\(([\w(), ]*)\))?;/
421+
/^\s*(.+)\s*\b(\w+)(\[[\w\s+]+\])?\s*(?:pg_node_attr\(([\w(), ]*)\))?;/
398422
)
399423
{
400424
if ($is_node_struct)
@@ -441,13 +465,46 @@ sub elem
441465
$my_field_attrs{$name} = \@attrs;
442466
}
443467
}
444-
else
468+
# function pointer field
469+
elsif ($line =~
470+
/^\s*([\w\s*]+)\s*\(\*(\w+)\)\s*\((.*)\)\s*(?:pg_node_attr\(([\w(), ]*)\))?;/
471+
)
445472
{
446473
if ($is_node_struct)
447474
{
448-
#warn "$infile:$lineno: could not parse \"$line\"\n";
475+
my $type = $1;
476+
my $name = $2;
477+
my $args = $3;
478+
my $attrs = $4;
479+
480+
my @attrs;
481+
if ($attrs)
482+
{
483+
@attrs = split /,\s*/, $attrs;
484+
foreach my $attr (@attrs)
485+
{
486+
if ( $attr !~ /^copy_as\(\w+\)$/
487+
&& $attr !~ /^read_as\(\w+\)$/
488+
&& !elem $attr,
489+
qw(equal_ignore read_write_ignore))
490+
{
491+
die
492+
"$infile:$lineno: unrecognized attribute \"$attr\"\n";
493+
}
494+
}
495+
}
496+
497+
push @my_fields, $name;
498+
$my_field_types{$name} = 'function pointer';
499+
$my_field_attrs{$name} = \@attrs;
449500
}
450501
}
502+
else
503+
{
504+
# We're not too picky about what's outside structs,
505+
# but we'd better understand everything inside.
506+
die "$infile:$lineno: could not parse \"$line\"\n";
507+
}
451508
}
452509
# not in a struct
453510
else
@@ -709,6 +766,12 @@ sub elem
709766
unless $equal_ignore;
710767
}
711768
}
769+
elsif ($t eq 'function pointer')
770+
{
771+
# we can copy and compare as a scalar
772+
print $cff "\tCOPY_SCALAR_FIELD($f);\n" unless $copy_ignore;
773+
print $eff "\tCOMPARE_SCALAR_FIELD($f);\n" unless $equal_ignore;
774+
}
712775
# node type
713776
elsif ($t =~ /(\w+)\*/ and elem $1, @node_types)
714777
{
@@ -980,6 +1043,12 @@ sub elem
9801043
unless $no_read;
9811044
}
9821045
}
1046+
elsif ($t eq 'function pointer')
1047+
{
1048+
# We don't print these, and we can't read them either
1049+
die "cannot read function pointer in struct \"$n\" field \"$f\"\n"
1050+
unless $no_read;
1051+
}
9831052
# Special treatments of several Path node fields
9841053
elsif ($t eq 'RelOptInfo*' && elem 'write_only_relids', @a)
9851054
{

src/include/nodes/parsenodes.h

+14-14
Original file line numberDiff line numberDiff line change
@@ -303,26 +303,26 @@ typedef struct A_Expr
303303

304304
/*
305305
* A_Const - a literal constant
306+
*
307+
* Value nodes are inline for performance. You can treat 'val' as a node,
308+
* as in IsA(&val, Integer). 'val' is not valid if isnull is true.
306309
*/
310+
union ValUnion
311+
{
312+
Node node;
313+
Integer ival;
314+
Float fval;
315+
Boolean boolval;
316+
String sval;
317+
BitString bsval;
318+
};
319+
307320
typedef struct A_Const
308321
{
309322
pg_node_attr(custom_copy_equal, custom_read_write, no_read)
310323

311324
NodeTag type;
312-
313-
/*
314-
* Value nodes are inline for performance. You can treat 'val' as a node,
315-
* as in IsA(&val, Integer). 'val' is not valid if isnull is true.
316-
*/
317-
union ValUnion
318-
{
319-
Node node;
320-
Integer ival;
321-
Float fval;
322-
Boolean boolval;
323-
String sval;
324-
BitString bsval;
325-
} val;
325+
union ValUnion val;
326326
bool isnull; /* SQL NULL constant */
327327
int location; /* token location, or -1 if unknown */
328328
} A_Const;

src/include/nodes/pathnodes.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -1098,7 +1098,7 @@ struct IndexOptInfo
10981098

10991099
/*
11001100
* Remaining fields are copied from the index AM's API struct
1101-
* (IndexAmRoutine)
1101+
* (IndexAmRoutine). We don't bother to dump them.
11021102
*/
11031103
bool amcanorderbyop pg_node_attr(read_write_ignore);
11041104
bool amoptionalkey pg_node_attr(read_write_ignore);
@@ -1111,8 +1111,9 @@ struct IndexOptInfo
11111111
bool amcanparallel pg_node_attr(read_write_ignore);
11121112
/* does AM have ammarkpos interface? */
11131113
bool amcanmarkpos pg_node_attr(read_write_ignore);
1114+
/* AM's cost estimator */
11141115
/* Rather than include amapi.h here, we declare amcostestimate like this */
1115-
void (*amcostestimate) (); /* AM's cost estimator */
1116+
void (*amcostestimate) () pg_node_attr(read_write_ignore);
11161117
};
11171118

11181119
/*

0 commit comments

Comments
 (0)