From b53fa22d12dbf7b104284866802923838f97ad2e Mon Sep 17 00:00:00 2001
From: Matthias van de Meent <boekewurm+postgres@gmail.com>
Date: Wed, 3 Jan 2024 02:17:19 +0100
Subject: [PATCH v1 3/7] Nodesupport: add support for custom default values

Initial testing on typmod values shows that pg_rewrite's ev_action
column data shrinks by about 4% with only these changes.
---
 src/backend/nodes/gen_node_support.pl | 86 +++++++++++++++++----------
 src/backend/nodes/outfuncs.c          |  2 +
 src/backend/nodes/readfuncs.c         |  2 +
 src/include/nodes/parsenodes.h        |  2 +-
 src/include/nodes/pathnodes.h         |  2 +-
 src/include/nodes/primnodes.h         | 22 +++----
 6 files changed, 73 insertions(+), 43 deletions(-)

diff --git a/src/backend/nodes/gen_node_support.pl b/src/backend/nodes/gen_node_support.pl
index c7091d6bf2..5586368475 100644
--- a/src/backend/nodes/gen_node_support.pl
+++ b/src/backend/nodes/gen_node_support.pl
@@ -362,6 +362,12 @@ foreach my $infile (@ARGV)
 						{
 							$manual_nodetag_number{$in_struct} = $1;
 						}
+						elsif ($attr =~ /^default\(([\w\d."'-]+)\)$/)
+						{
+						}
+						elsif ($attr =~ /^default_ref\(([\w\d."'-]+)\)$/)
+						{
+						}
 						else
 						{
 							die
@@ -436,7 +442,7 @@ foreach my $infile (@ARGV)
 			}
 			# normal struct field
 			elsif ($line =~
-				/^\s*(.+)\s*\b(\w+)(\[[\w\s+]+\])?\s*(?:pg_node_attr\(([\w(), ]*)\))?;/
+				/^\s*(.+)\s*\b(\w+)(\[[\w\s+]+\])?\s*(?:pg_node_attr\(([\w\d(), ."'-]*)\))?;/
 			  )
 			{
 				if ($is_node_struct)
@@ -468,6 +474,8 @@ foreach my $infile (@ARGV)
 							if (   $attr !~ /^array_size\(\w+\)$/
 								&& $attr !~ /^copy_as\(\w+\)$/
 								&& $attr !~ /^read_as\(\w+\)$/
+								&& $attr !~ /^default\([\w\d."'-]+\)$/
+								&& $attr !~ /^default_ref\([\w\d."'-]+\)$/
 								&& !elem $attr,
 								qw(copy_as_scalar
 								equal_as_scalar
@@ -494,7 +502,7 @@ foreach my $infile (@ARGV)
 			}
 			# function pointer field
 			elsif ($line =~
-				/^\s*([\w\s*]+)\s*\(\*(\w+)\)\s*\((.*)\)\s*(?:pg_node_attr\(([\w(), ]*)\))?;/
+				/^\s*([\w\s*]+)\s*\(\*(\w+)\)\s*\((.*)\)\s*(?:pg_node_attr\(([\w\d(), ."'-]*)\))?;/
 			  )
 			{
 				if ($is_node_struct)
@@ -969,6 +977,11 @@ _read${n}(void)
 		my $array_size_field;
 		my $read_as_field;
 		my $read_write_ignore = 0;
+		# macro suffix ("_DEFAULT" for manual default overrides) and default
+		# value argument.
+		my $s = "";
+		my $d = "";
+
 		foreach my $a (@a)
 		{
 			if ($a =~ /^array_size\(([\w.]+)\)$/)
@@ -987,6 +1000,19 @@ _read${n}(void)
 			{
 				$read_write_ignore = 1;
 			}
+			elsif ($a =~ /^default\(([\w\d+."'-]+)\)$/)
+			{
+				$d = ", $1";
+			}
+			elsif ($a =~ /^default_ref\(([\w\d+."'-]+)\)$/)
+			{
+				$d = ", NODE_FIELD($1)";
+			}
+		}
+
+		if (!($d eq ""))
+		{
+			$s = "_DEFAULT";
 		}
 
 		if ($read_write_ignore)
@@ -1007,13 +1033,13 @@ _read${n}(void)
 		# select instructions by field type
 		if ($t eq 'bool')
 		{
-			print $off "\tWRITE_BOOL_FIELD($f);\n";
-			print $rff "\tREAD_BOOL_FIELD($f);\n" unless $no_read;
+			print $off "\tWRITE_BOOL_FIELD$s($f$d);\n";
+			print $rff "\tREAD_BOOL_FIELD$s($f$d);\n" unless $no_read;
 		}
 		elsif ($t eq 'int' && $f =~ 'location$')
 		{
-			print $off "\tWRITE_LOCATION_FIELD($f);\n";
-			print $rff "\tREAD_LOCATION_FIELD($f);\n" unless $no_read;
+			print $off "\tWRITE_LOCATION_FIELD$s($f$d);\n";
+			print $rff "\tREAD_LOCATION_FIELD$s($f$d);\n" unless $no_read;
 		}
 		elsif ($t eq 'int'
 			|| $t eq 'int16'
@@ -1021,8 +1047,8 @@ _read${n}(void)
 			|| $t eq 'AttrNumber'
 			|| $t eq 'StrategyNumber')
 		{
-			print $off "\tWRITE_INT_FIELD($f);\n";
-			print $rff "\tREAD_INT_FIELD($f);\n" unless $no_read;
+			print $off "\tWRITE_INT_FIELD$s($f$d);\n";
+			print $rff "\tREAD_INT_FIELD$s($f$d);\n" unless $no_read;
 		}
 		elsif ($t eq 'uint32'
 			|| $t eq 'bits32'
@@ -1030,44 +1056,44 @@ _read${n}(void)
 			|| $t eq 'Index'
 			|| $t eq 'SubTransactionId')
 		{
-			print $off "\tWRITE_UINT_FIELD($f);\n";
-			print $rff "\tREAD_UINT_FIELD($f);\n" unless $no_read;
+			print $off "\tWRITE_UINT_FIELD$s($f$d);\n";
+			print $rff "\tREAD_UINT_FIELD$s($f$d);\n" unless $no_read;
 		}
 		elsif ($t eq 'uint64'
 			|| $t eq 'AclMode')
 		{
-			print $off "\tWRITE_UINT64_FIELD($f);\n";
-			print $rff "\tREAD_UINT64_FIELD($f);\n" unless $no_read;
+			print $off "\tWRITE_UINT64_FIELD$s($f$d);\n";
+			print $rff "\tREAD_UINT64_FIELD$s($f$d);\n" unless $no_read;
 		}
 		elsif ($t eq 'Oid' || $t eq 'RelFileNumber')
 		{
-			print $off "\tWRITE_OID_FIELD($f);\n";
-			print $rff "\tREAD_OID_FIELD($f);\n" unless $no_read;
+			print $off "\tWRITE_OID_FIELD$s($f$d);\n";
+			print $rff "\tREAD_OID_FIELD$s($f$d);\n" unless $no_read;
 		}
 		elsif ($t eq 'long')
 		{
-			print $off "\tWRITE_LONG_FIELD($f);\n";
-			print $rff "\tREAD_LONG_FIELD($f);\n" unless $no_read;
+			print $off "\tWRITE_LONG_FIELD$s($f$d);\n";
+			print $rff "\tREAD_LONG_FIELD$s($f$d);\n" unless $no_read;
 		}
 		elsif ($t eq 'char')
 		{
-			print $off "\tWRITE_CHAR_FIELD($f);\n";
-			print $rff "\tREAD_CHAR_FIELD($f);\n" unless $no_read;
+			print $off "\tWRITE_CHAR_FIELD$s($f$d);\n";
+			print $rff "\tREAD_CHAR_FIELD$s($f$d);\n" unless $no_read;
 		}
 		elsif ($t eq 'double')
 		{
-			print $off "\tWRITE_FLOAT_FIELD($f);\n";
-			print $rff "\tREAD_FLOAT_FIELD($f);\n" unless $no_read;
+			print $off "\tWRITE_FLOAT_FIELD$s($f$d);\n";
+			print $rff "\tREAD_FLOAT_FIELD$s($f$d);\n" unless $no_read;
 		}
 		elsif ($t eq 'Cardinality')
 		{
-			print $off "\tWRITE_FLOAT_FIELD($f);\n";
-			print $rff "\tREAD_FLOAT_FIELD($f);\n" unless $no_read;
+			print $off "\tWRITE_FLOAT_FIELD$s($f$d);\n";
+			print $rff "\tREAD_FLOAT_FIELD$s($f$d);\n" unless $no_read;
 		}
 		elsif ($t eq 'Cost')
 		{
-			print $off "\tWRITE_FLOAT_FIELD($f);\n";
-			print $rff "\tREAD_FLOAT_FIELD($f);\n" unless $no_read;
+			print $off "\tWRITE_FLOAT_FIELD$s($f$d);\n";
+			print $rff "\tREAD_FLOAT_FIELD$s($f$d);\n" unless $no_read;
 		}
 		elsif ($t eq 'QualCost')
 		{
@@ -1078,13 +1104,13 @@ _read${n}(void)
 		}
 		elsif ($t eq 'Selectivity')
 		{
-			print $off "\tWRITE_FLOAT_FIELD($f);\n";
-			print $rff "\tREAD_FLOAT_FIELD($f);\n" unless $no_read;
+			print $off "\tWRITE_FLOAT_FIELD$s($f$d);\n";
+			print $rff "\tREAD_FLOAT_FIELD$s($f$d);\n" unless $no_read;
 		}
 		elsif ($t eq 'char*')
 		{
-			print $off "\tWRITE_STRING_FIELD($f);\n";
-			print $rff "\tREAD_STRING_FIELD($f);\n" unless $no_read;
+			print $off "\tWRITE_STRING_FIELD($f$d);\n";
+			print $rff "\tREAD_STRING_FIELD($f$d);\n" unless $no_read;
 		}
 		elsif ($t eq 'Bitmapset*' || $t eq 'Relids')
 		{
@@ -1093,8 +1119,8 @@ _read${n}(void)
 		}
 		elsif (elem $t, @enum_types)
 		{
-			print $off "\tWRITE_ENUM_FIELD($f, $t);\n";
-			print $rff "\tREAD_ENUM_FIELD($f, $t);\n" unless $no_read;
+			print $off "\tWRITE_ENUM_FIELD$s($f, $t$d);\n";
+			print $rff "\tREAD_ENUM_FIELD$s($f, $t$d);\n" unless $no_read;
 		}
 		# arrays of scalar types
 		elsif ($t =~ /^(\w+)(\*|\[\w+\])$/ and elem $1, @scalar_types)
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 29f4e43581..73f1298dee 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -193,6 +193,8 @@ static void outDouble(StringInfo str, double d);
 #define WRITE_BOOL_ARRAY(fldname, len) \
 	(node->fldname == NULL ? (0) : WRITE_BOOL_ARRAY_DIRECT(fldname, len))
 
+#define NODE_FIELD(fldname) (node->fldname)
+
 #define booltostr(x)  ((x) ? "true" : "false")
 
 
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index 74a2204389..dd1e505bd7 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -256,6 +256,8 @@
 #define READ_BOOL_ARRAY(fldname, len) \
 	READ_BOOL_ARRAY_DEFAULT(fldname, len, NULL)
 
+#define NODE_FIELD(fldname) (local_node->fldname)
+
 /* Routine exit */
 #define READ_DONE() \
 	return local_node
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index e494309da8..b9f122b46c 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -1608,7 +1608,7 @@ typedef struct CTECycleClause
 	int			location;
 	/* These fields are set during parse analysis: */
 	Oid			cycle_mark_type;	/* common type of _value and _default */
-	int			cycle_mark_typmod;
+	int			cycle_mark_typmod pg_node_attr(default(-1));
 	Oid			cycle_mark_collation;
 	Oid			cycle_mark_neop;	/* <> operator for type */
 } CTECycleClause;
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index ed85dc7414..e688fc2b79 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -3379,7 +3379,7 @@ typedef struct AggTransInfo
 	Oid			aggtranstype;
 
 	/* Additional data about transtype */
-	int32		aggtranstypmod;
+	int32		aggtranstypmod pg_node_attr(default(-1));
 	int			transtypeLen;
 	bool		transtypeByVal;
 
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index bb930afb52..c9b30b1b0d 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -248,7 +248,7 @@ typedef struct Var
 	/* pg_type OID for the type of this var */
 	Oid			vartype pg_node_attr(query_jumble_ignore);
 	/* pg_attribute typmod value */
-	int32		vartypmod pg_node_attr(query_jumble_ignore);
+	int32		vartypmod pg_node_attr(query_jumble_ignore, default(-1));
 	/* OID of collation, or InvalidOid if none */
 	Oid			varcollid pg_node_attr(query_jumble_ignore);
 
@@ -297,7 +297,7 @@ typedef struct Const
 	/* pg_type OID of the constant's datatype */
 	Oid			consttype;
 	/* typmod value, if any */
-	int32		consttypmod pg_node_attr(query_jumble_ignore);
+	int32		consttypmod pg_node_attr(query_jumble_ignore, default(-1));
 	/* OID of collation, or InvalidOid if none */
 	Oid			constcollid pg_node_attr(query_jumble_ignore);
 	/* typlen of the constant's datatype */
@@ -363,7 +363,7 @@ typedef struct Param
 	int			paramid;		/* numeric ID for parameter */
 	Oid			paramtype;		/* pg_type OID of parameter's datatype */
 	/* typmod value, if known */
-	int32		paramtypmod pg_node_attr(query_jumble_ignore);
+	int32		paramtypmod pg_node_attr(query_jumble_ignore, default(-1));
 	/* OID of collation, or InvalidOid if none */
 	Oid			paramcollid pg_node_attr(query_jumble_ignore);
 	/* token location, or -1 if unknown */
@@ -621,7 +621,7 @@ typedef struct SubscriptingRef
 	/* type of the SubscriptingRef's result */
 	Oid			refrestype pg_node_attr(query_jumble_ignore);
 	/* typmod of the result */
-	int32		reftypmod pg_node_attr(query_jumble_ignore);
+	int32		reftypmod pg_node_attr(query_jumble_ignore, default(-1));
 	/* collation of result, or InvalidOid if none */
 	Oid			refcollid pg_node_attr(query_jumble_ignore);
 	/* expressions that evaluate to upper container indexes */
@@ -1065,7 +1065,7 @@ typedef struct FieldSelect
 	/* type of the field (result type of this node) */
 	Oid			resulttype pg_node_attr(query_jumble_ignore);
 	/* output typmod (usually -1) */
-	int32		resulttypmod pg_node_attr(query_jumble_ignore);
+	int32		resulttypmod pg_node_attr(query_jumble_ignore, default(-1));
 	/* OID of collation of the field */
 	Oid			resultcollid pg_node_attr(query_jumble_ignore);
 } FieldSelect;
@@ -1119,7 +1119,7 @@ typedef struct RelabelType
 	Expr	   *arg;			/* input expression */
 	Oid			resulttype;		/* output type of coercion expression */
 	/* output typmod (usually -1) */
-	int32		resulttypmod pg_node_attr(query_jumble_ignore);
+	int32		resulttypmod pg_node_attr(query_jumble_ignore, default(-1));
 	/* OID of collation, or InvalidOid if none */
 	Oid			resultcollid pg_node_attr(query_jumble_ignore);
 	/* how to display this node */
@@ -1169,7 +1169,7 @@ typedef struct ArrayCoerceExpr
 	Expr	   *elemexpr;		/* expression representing per-element work */
 	Oid			resulttype;		/* output type of coercion (an array type) */
 	/* output typmod (also element typmod) */
-	int32		resulttypmod pg_node_attr(query_jumble_ignore);
+	int32		resulttypmod pg_node_attr(query_jumble_ignore, default(-1));
 	/* OID of collation, or InvalidOid if none */
 	Oid			resultcollid pg_node_attr(query_jumble_ignore);
 	/* how to display this node */
@@ -1495,7 +1495,7 @@ typedef struct SQLValueFunction
 	 * include this Oid in the query jumbling.
 	 */
 	Oid			type pg_node_attr(query_jumble_ignore);
-	int32		typmod;
+	int32		typmod pg_node_attr(default(-1));
 	int			location;		/* token location, or -1 if unknown */
 } SQLValueFunction;
 
@@ -1547,7 +1547,7 @@ typedef struct XmlExpr
 	bool		indent;
 	/* target type/typmod for XMLSERIALIZE */
 	Oid			type pg_node_attr(query_jumble_ignore);
-	int32		typmod pg_node_attr(query_jumble_ignore);
+	int32		typmod pg_node_attr(query_jumble_ignore, default(-1));
 	/* token location, or -1 if unknown */
 	int			location;
 } XmlExpr;
@@ -1597,7 +1597,7 @@ typedef struct JsonReturning
 	NodeTag		type;
 	JsonFormat *format;			/* output JSON format */
 	Oid			typid;			/* target type Oid */
-	int32		typmod;			/* target type modifier */
+	int32		typmod pg_node_attr(default(-1)); /* target type modifier */
 } JsonReturning;
 
 /*
@@ -1760,7 +1760,7 @@ typedef struct CoerceToDomain
 	Expr	   *arg;			/* input expression */
 	Oid			resulttype;		/* domain type ID (result type) */
 	/* output typmod (currently always -1) */
-	int32		resulttypmod pg_node_attr(query_jumble_ignore);
+	int32		resulttypmod pg_node_attr(query_jumble_ignore, default(-1));
 	/* OID of collation, or InvalidOid if none */
 	Oid			resultcollid pg_node_attr(query_jumble_ignore);
 	/* how to display this node */
-- 
2.40.1

