my $output_path = '.';
-GetOptions(
- 'outdir:s' => \$output_path)
+GetOptions('outdir:s' => \$output_path)
or die "$0: wrong arguments";
$type =~ s/\s*$//;
# strip space between type and "*" (pointer) */
$type =~ s/\s+\*$/*/;
+ # strip space between type and "**" (array of pointers) */
+ $type =~ s/\s+\*\*$/**/;
die
"$infile:$lineno: cannot parse data type in \"$line\"\n"
# nodetags.h
push @output_files, 'nodetags.h';
-open my $nt, '>', "$output_path/nodetags.h$tmpext" or die "$output_path/nodetags.h$tmpext: $!";
+open my $nt, '>', "$output_path/nodetags.h$tmpext"
+ or die "$output_path/nodetags.h$tmpext: $!";
printf $nt $header_comment, 'nodetags.h';
unless $equal_ignore || $t eq 'CoercionForm';
}
}
- # scalar type pointer
- elsif ($t =~ /(\w+)\*/ and elem $1, @scalar_types)
+ # arrays of scalar types
+ elsif ($t =~ /^(\w+)\*$/ and elem $1, @scalar_types)
{
my $tt = $1;
if (!defined $array_size_field)
print $eff "\tCOMPARE_SCALAR_FIELD($f);\n" unless $equal_ignore;
}
# node type
- elsif ($t =~ /(\w+)\*/ and elem $1, @node_types)
+ elsif (($t =~ /^(\w+)\*$/ or $t =~ /^struct\s+(\w+)\*$/)
+ and elem $1, @node_types)
{
print $cff "\tCOPY_NODE_FIELD($f);\n" unless $copy_ignore;
print $eff "\tCOMPARE_NODE_FIELD($f);\n" unless $equal_ignore;
}
# array (inline)
- elsif ($t =~ /\w+\[/)
+ elsif ($t =~ /^\w+\[\w+\]$/)
{
print $cff "\tCOPY_ARRAY_FIELD($f);\n" unless $copy_ignore;
print $eff "\tCOMPARE_ARRAY_FIELD($f);\n" unless $equal_ignore;
my @a = @{ $node_type_info{$n}->{field_attrs}{$f} };
# extract per-field attributes
- my $read_write_ignore = 0;
+ my $array_size_field;
my $read_as_field;
+ my $read_write_ignore = 0;
foreach my $a (@a)
{
- if ($a =~ /^read_as\(([\w.]+)\)$/)
+ if ($a =~ /^array_size\(([\w.]+)\)$/)
+ {
+ $array_size_field = $1;
+ }
+ elsif ($a =~ /^read_as\(([\w.]+)\)$/)
{
$read_as_field = $1;
}
print $off "\tWRITE_ENUM_FIELD($f, $t);\n";
print $rff "\tREAD_ENUM_FIELD($f, $t);\n" unless $no_read;
}
- # arrays
- elsif ($t =~ /(\w+)(\*|\[)/ and elem $1, @scalar_types)
+ # arrays of scalar types
+ elsif ($t =~ /^(\w+)(\*|\[\w+\])$/ and elem $1, @scalar_types)
{
my $tt = uc $1;
- my $array_size_field;
- foreach my $a (@a)
- {
- if ($a =~ /^array_size\(([\w.]+)\)$/)
- {
- $array_size_field = $1;
- last;
- }
- }
if (!defined $array_size_field)
{
die "no array size defined for $n.$f of type $t\n";
. "\t\toutBitmapset(str, NULL);\n";
}
# node type
- elsif ($t =~ /(\w+)\*/ and elem $1, @node_types)
+ elsif (($t =~ /^(\w+)\*$/ or $t =~ /^struct\s+(\w+)\*$/)
+ and elem $1, @node_types)
{
print $off "\tWRITE_NODE_FIELD($f);\n";
print $rff "\tREAD_NODE_FIELD($f);\n" unless $no_read;
}
+ # arrays of node pointers (currently supported for write only)
+ elsif (($t =~ /^(\w+)\*\*$/ or $t =~ /^struct\s+(\w+)\*\*$/)
+ and elem($1, @node_types))
+ {
+ if (!defined $array_size_field)
+ {
+ die "no array size defined for $n.$f of type $t\n";
+ }
+ if ($node_type_info{$n}->{field_types}{$array_size_field} eq
+ 'List*')
+ {
+ print $off
+ "\tWRITE_NODE_ARRAY($f, list_length(node->$array_size_field));\n";
+ print $rff
+ "\tREAD_NODE_ARRAY($f, list_length(local_node->$array_size_field));\n"
+ unless $no_read;
+ }
+ else
+ {
+ print $off
+ "\tWRITE_NODE_ARRAY($f, node->$array_size_field);\n";
+ print $rff
+ "\tREAD_NODE_ARRAY($f, local_node->$array_size_field);\n"
+ unless $no_read;
+ }
+ }
elsif ($t eq 'struct CustomPathMethods*'
|| $t eq 'struct CustomScanMethods*')
{
(appendStringInfoString(str, " :" CppAsString(fldname) " "), \
outBitmapset(str, node->fldname))
+/* Write a variable-length array (not a List) of Node pointers */
+#define WRITE_NODE_ARRAY(fldname, len) \
+ (appendStringInfoString(str, " :" CppAsString(fldname) " "), \
+ writeNodeArray(str, (const Node * const *) node->fldname, len))
+
/* Write a variable-length array of AttrNumber */
#define WRITE_ATTRNUMBER_ARRAY(fldname, len) \
(appendStringInfoString(str, " :" CppAsString(fldname) " "), \
WRITE_SCALAR_ARRAY(writeIntCols, int, " %d",)
WRITE_SCALAR_ARRAY(writeBoolCols, bool, " %s", booltostr)
+/*
+ * Print an array (not a List) of Node pointers.
+ *
+ * The decoration is identical to that of scalar arrays, but we can't
+ * quite use appendStringInfo() in the loop.
+ */
+static void
+writeNodeArray(StringInfo str, const Node *const *arr, int len)
+{
+ if (arr != NULL)
+ {
+ appendStringInfoChar(str, '(');
+ for (int i = 0; i < len; i++)
+ {
+ appendStringInfoChar(str, ' ');
+ outNode(str, arr[i]);
+ }
+ appendStringInfoChar(str, ')');
+ }
+ else
+ appendStringInfoString(str, "<>");
+}
+
/*
* Print a List.
*/
* planned.
*
* Not all fields are printed. (In some cases, there is no print support for
- * the field type.)
+ * the field type; in others, doing so would lead to infinite recursion.)
*----------
*/
typedef struct PlannerGlobal
* either here or in that header, whichever is read first.
*
* Not all fields are printed. (In some cases, there is no print support for
- * the field type.)
+ * the field type; in others, doing so would lead to infinite recursion or
+ * bloat dump output more than seems useful.)
*----------
*/
#ifndef HAVE_PLANNERINFO_TYPEDEF
* does not correspond to a base relation, such as a join RTE or an
* unreferenced view RTE; or if the RelOptInfo hasn't been made yet.
*/
- struct RelOptInfo **simple_rel_array pg_node_attr(read_write_ignore);
+ struct RelOptInfo **simple_rel_array pg_node_attr(array_size(simple_rel_array_size));
/* allocated size of array */
- int simple_rel_array_size pg_node_attr(read_write_ignore);
+ int simple_rel_array_size;
/*
* simple_rte_array is the same length as simple_rel_array and holds
* pointers to the associated rangetable entries. Using this is a shade
- * faster than using rt_fetch(), mostly due to fewer indirections.
+ * faster than using rt_fetch(), mostly due to fewer indirections. (Not
+ * printed because it'd be redundant with parse->rtable.)
*/
RangeTblEntry **simple_rte_array pg_node_attr(read_write_ignore);
* append_rel_array is the same length as the above arrays, and holds
* pointers to the corresponding AppendRelInfo entry indexed by
* child_relid, or NULL if the rel is not an appendrel child. The array
- * itself is not allocated if append_rel_list is empty.
+ * itself is not allocated if append_rel_list is empty. (Not printed
+ * because it'd be redundant with append_rel_list.)
*/
struct AppendRelInfo **append_rel_array pg_node_attr(read_write_ignore);
* join_cur_level is the current level. New join-relation RelOptInfos are
* automatically added to the join_rel_level[join_cur_level] list.
* join_rel_level is NULL if not in use.
+ *
+ * Note: we've already printed all baserel and joinrel RelOptInfos above,
+ * so we don't dump join_rel_level or other lists of RelOptInfos.
*/
/* lists of join-relation RelOptInfos */
List **join_rel_level pg_node_attr(read_write_ignore);
/*
* Fields filled during create_plan() for use in setrefs.c
*/
- /* for GroupingFunc fixup */
- AttrNumber *grouping_map pg_node_attr(array_size(update_colnos), read_write_ignore);
+ /* for GroupingFunc fixup (can't print: array length not known here) */
+ AttrNumber *grouping_map pg_node_attr(read_write_ignore);
/* List of MinMaxAggInfos */
List *minmax_aggs;
/* PARAM_EXEC ID for the work table */
int wt_param_id;
/* a path for non-recursive term */
- struct Path *non_recursive_path pg_node_attr(read_write_ignore);
+ struct Path *non_recursive_path;
/*
* These fields are workspace for createplan.c
/*
* These fields are workspace for setrefs.c. Each is an array
- * corresponding to glob->subplans.
+ * corresponding to glob->subplans. (We could probably teach
+ * gen_node_support.pl how to determine the array length, but it doesn't
+ * seem worth the trouble, so just mark them read_write_ignore.)
*/
bool *isAltSubplan pg_node_attr(read_write_ignore);
bool *isUsedSubplan pg_node_attr(read_write_ignore);
* Number of partitions; -1 if not yet set; in case of a join relation 0
* means it's considered unpartitioned
*/
- int nparts pg_node_attr(read_write_ignore);
+ int nparts;
/* Partition bounds */
struct PartitionBoundInfoData *boundinfo pg_node_attr(read_write_ignore);
/* True if partition bounds were created by partition_bounds_merge() */
bool partbounds_merged;
/* Partition constraint, if not the root */
- List *partition_qual pg_node_attr(read_write_ignore);
+ List *partition_qual;
/*
* Array of RelOptInfos of partitions, stored in the same order as bounds
+ * (don't print, too bulky and duplicative)
*/
struct RelOptInfo **part_rels pg_node_attr(read_write_ignore);
Bitmapset *live_parts;
/* Relids set of all partition relids */
Relids all_partrels;
+
+ /*
+ * These arrays are of length partkey->partnatts, which we don't have at
+ * hand, so don't try to print
+ */
+
/* Non-nullable partition key expressions */
List **partexprs pg_node_attr(read_write_ignore);
/* Nullable partition key expressions */
int nkeycolumns;
/*
- * array fields aren't really worth the trouble to print
- */
-
- /*
- * column numbers of index's attributes both key and included columns, or
- * 0
+ * table column numbers of index's columns (both key and included
+ * columns), or 0 for expression columns
*/
- int *indexkeys pg_node_attr(read_write_ignore);
+ int *indexkeys pg_node_attr(array_size(ncolumns));
/* OIDs of collations of index columns */
- Oid *indexcollations pg_node_attr(read_write_ignore);
+ Oid *indexcollations pg_node_attr(array_size(nkeycolumns));
/* OIDs of operator families for columns */
- Oid *opfamily pg_node_attr(read_write_ignore);
+ Oid *opfamily pg_node_attr(array_size(nkeycolumns));
/* OIDs of opclass declared input data types */
- Oid *opcintype pg_node_attr(read_write_ignore);
+ Oid *opcintype pg_node_attr(array_size(nkeycolumns));
/* OIDs of btree opfamilies, if orderable */
- Oid *sortopfamily pg_node_attr(read_write_ignore);
+ Oid *sortopfamily pg_node_attr(array_size(nkeycolumns));
/* is sort order descending? */
- bool *reverse_sort pg_node_attr(read_write_ignore);
+ bool *reverse_sort pg_node_attr(array_size(nkeycolumns));
/* do NULLs come first in the sort order? */
- bool *nulls_first pg_node_attr(read_write_ignore);
+ bool *nulls_first pg_node_attr(array_size(nkeycolumns));
/* opclass-specific options for columns */
bytea **opclassoptions pg_node_attr(read_write_ignore);
/* which index cols can be returned in an index-only scan? */
- bool *canreturn pg_node_attr(read_write_ignore);
+ bool *canreturn pg_node_attr(array_size(ncolumns));
/* OID of the access method (in pg_am) */
Oid relam;
/*
* Remaining fields are copied from the index AM's API struct
- * (IndexAmRoutine). We don't bother to dump them.
+ * (IndexAmRoutine).
*/
- bool amcanorderbyop pg_node_attr(read_write_ignore);
- bool amoptionalkey pg_node_attr(read_write_ignore);
- bool amsearcharray pg_node_attr(read_write_ignore);
- bool amsearchnulls pg_node_attr(read_write_ignore);
+ bool amcanorderbyop;
+ bool amoptionalkey;
+ bool amsearcharray;
+ bool amsearchnulls;
/* does AM have amgettuple interface? */
- bool amhasgettuple pg_node_attr(read_write_ignore);
+ bool amhasgettuple;
/* does AM have amgetbitmap interface? */
- bool amhasgetbitmap pg_node_attr(read_write_ignore);
- bool amcanparallel pg_node_attr(read_write_ignore);
+ bool amhasgetbitmap;
+ bool amcanparallel;
/* does AM have ammarkpos interface? */
- bool amcanmarkpos pg_node_attr(read_write_ignore);
+ bool amcanmarkpos;
/* AM's cost estimator */
/* Rather than include amapi.h here, we declare amcostestimate like this */
void (*amcostestimate) () pg_node_attr(read_write_ignore);
Oid statOid;
/* includes child relations */
- bool inherit pg_node_attr(read_write_ignore);
+ bool inherit;
- /*
- * back-link to statistic's table; don't print, infinite recursion on plan
- * tree dump
- */
+ /* back-link to statistic's table; don't print, else infinite recursion */
RelOptInfo *rel pg_node_attr(read_write_ignore);
/* statistics kind of this entry */