flat_copy_node.patch

text/plain

Filename: flat_copy_node.patch
Type: text/plain
Part: 0
Message: Re: unrecognized node type while displaying a Path due to dangling pointer

Patch

Same data as JSON: GET /api/v1/attachments/:id/patch the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes. API reference →
Format: unified
File+
src/backend/nodes/copyfuncs.c 45 0
src/backend/nodes/gen_node_support.pl 23 0
src/backend/nodes/.gitignore 1 0
src/backend/nodes/Makefile 1 1
src/backend/optimizer/plan/planner.c 9 1
src/include/Makefile 2 1
src/include/nodes/meson.build 2 1
src/include/nodes/nodes.h 1 0
src/tools/msvc/clean.bat 1 0
src/tools/msvc/Solution.pm 8 0
src/tools/pginclude/cpluspluscheck 4 0
src/tools/pginclude/headerscheck 4 0
diff --git a/src/backend/nodes/.gitignore b/src/backend/nodes/.gitignore
index 0c14b5697b..91cbd2cf24 100644
--- a/src/backend/nodes/.gitignore
+++ b/src/backend/nodes/.gitignore
@@ -1,4 +1,5 @@
 /node-support-stamp
+/nodesizes.h
 /nodetags.h
 /*funcs.funcs.c
 /*funcs.switch.c
diff --git a/src/backend/nodes/Makefile b/src/backend/nodes/Makefile
index 0a95e683d0..46ce62f828 100644
--- a/src/backend/nodes/Makefile
+++ b/src/backend/nodes/Makefile
@@ -99,4 +99,4 @@ queryjumblefuncs.o: queryjumblefuncs.c queryjumblefuncs.funcs.c queryjumblefuncs
 readfuncs.o:  readfuncs.c readfuncs.funcs.c readfuncs.switch.c | node-support-stamp
 
 maintainer-clean: clean
-	rm -f node-support-stamp $(addsuffix funcs.funcs.c,copy equal out queryjumble read) $(addsuffix funcs.switch.c,copy equal out queryjumble read) nodetags.h
+	rm -f node-support-stamp $(addsuffix funcs.funcs.c,copy equal out queryjumble read) $(addsuffix funcs.switch.c,copy equal out queryjumble read) nodesizes.h nodetags.h
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index f2568ff5e6..ccd4cbfa01 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -15,9 +15,54 @@
 
 #include "postgres.h"
 
+#include "access/amapi.h"
+#include "access/tableam.h"
+#include "access/tsmapi.h"
+#include "commands/event_trigger.h"
+#include "commands/trigger.h"
+#include "foreign/fdwapi.h"
 #include "miscadmin.h"
+#include "nodes/execnodes.h"
+#include "nodes/extensible.h"
+#include "nodes/miscnodes.h"
+#include "nodes/parsenodes.h"
+#include "nodes/pathnodes.h"
+#include "nodes/plannodes.h"
+#include "nodes/replnodes.h"
+#include "nodes/supportnodes.h"
+#include "nodes/tidbitmap.h"
 #include "utils/datum.h"
 
+static const Size flat_node_sizes[] = {
+	0, /* T_Invalid */
+#include "nodes/nodesizes.h"
+};
+
+/*
+ * copyObjectFlat
+ *		Allocate a new copy of the Node type denoted by 'from' and flat copy the
+ *		contents of it into the newly allocated node and return it.
+ */
+void *
+copyObjectFlat(const void *from)
+{
+	Size		size;
+	void	   *retval;
+	NodeTag		tag = nodeTag(from);
+
+	if ((unsigned int) tag >= lengthof(flat_node_sizes))
+	{
+		elog(ERROR, "unrecognized node type: %d", (int) tag);
+		return NULL;
+	}
+
+	/* XXX how to handle ExtensibleNodes? Can we just deep copy? */
+	size = flat_node_sizes[tag];
+	retval = palloc(size);
+	memcpy(retval, from, size);
+
+	return retval;
+}
 
 /*
  * Macros to simplify copying of different kinds of fields.  Use these
diff --git a/src/backend/nodes/gen_node_support.pl b/src/backend/nodes/gen_node_support.pl
index 72c7963578..e9a759c5a0 100644
--- a/src/backend/nodes/gen_node_support.pl
+++ b/src/backend/nodes/gen_node_support.pl
@@ -2,6 +2,7 @@
 #----------------------------------------------------------------------
 #
 # Generate node support files:
+# - nodesizes.h
 # - nodetags.h
 # - copyfuncs
 # - equalfuncs
@@ -599,6 +600,28 @@ my $header_comment =
  */
 ';
 
+# nodesizes.h
+
+push @output_files, 'nodesizes.h';
+open my $ns, '>', "$output_path/nodesizes.h$tmpext"
+  or die "$output_path/nodesizes.h$tmpext: $!";
+
+printf $ns $header_comment, 'nodesizes.h';
+
+foreach my $n (@node_types)
+{
+	next if elem $n, @abstract_types;
+	if (defined $manual_nodetag_number{$n})
+	{
+		print $ns "\tsizeof(T_${n}),\n";
+	}
+	else
+	{
+		print $ns "\tsizeof(${n}),\n";
+	}
+}
+
+close $ns;
 
 # nodetags.h
 
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 44efb1f4eb..2bfcddbce2 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -5143,7 +5143,15 @@ create_ordered_paths(PlannerInfo *root,
 												input_path->pathkeys, &presorted_keys);
 
 		if (is_sorted)
-			sorted_path = input_path;
+		{
+			/*
+			 * Perform a flat copy of the already-sorted node so as not to reference an
+			 * existing Path from another RelOptInfo.  The add_path() call below may
+			 * pfree this path, which would be problematic when it's still referenced
+			 * by input_rel.
+			 */
+			sorted_path = copyObjectFlat(input_path);
+		}
 		else
 		{
 			/*
diff --git a/src/include/Makefile b/src/include/Makefile
index 5d213187e2..283ae311b3 100644
--- a/src/include/Makefile
+++ b/src/include/Makefile
@@ -44,6 +44,7 @@ install: all installdirs
 	$(INSTALL_DATA) pg_config.h     '$(DESTDIR)$(includedir_server)'
 	$(INSTALL_DATA) pg_config_ext.h '$(DESTDIR)$(includedir_server)'
 	$(INSTALL_DATA) pg_config_os.h  '$(DESTDIR)$(includedir_server)'
+	$(INSTALL_DATA) nodes/nodesizes.h '$(DESTDIR)$(includedir_server)/nodes'
 	$(INSTALL_DATA) nodes/nodetags.h '$(DESTDIR)$(includedir_server)/nodes'
 	$(INSTALL_DATA) utils/errcodes.h '$(DESTDIR)$(includedir_server)/utils'
 	$(INSTALL_DATA) utils/fmgroids.h '$(DESTDIR)$(includedir_server)/utils'
@@ -75,7 +76,7 @@ clean:
 	rm -f storage/lwlocknames.h utils/probes.h utils/wait_event_types.h
 	rm -f catalog/schemapg.h catalog/system_fk_info.h
 	rm -f catalog/pg_*_d.h catalog/header-stamp
-	rm -f nodes/nodetags.h nodes/header-stamp
+	rm -f nodes/nodesizes.h nodes/nodetags.h nodes/header-stamp
 
 distclean maintainer-clean: clean
 	rm -f pg_config.h pg_config_ext.h pg_config_os.h stamp-h stamp-ext-h
diff --git a/src/include/nodes/meson.build b/src/include/nodes/meson.build
index 626dc696d5..cc25d99701 100644
--- a/src/include/nodes/meson.build
+++ b/src/include/nodes/meson.build
@@ -31,7 +31,7 @@ foreach i : node_support_input_i
 endforeach
 
 node_support_output = [
-  'nodetags.h',
+  'nodesizes.h', 'nodetags.h',
   'outfuncs.funcs.c', 'outfuncs.switch.c',
   'readfuncs.funcs.c', 'readfuncs.switch.c',
   'copyfuncs.funcs.c', 'copyfuncs.switch.c',
@@ -39,6 +39,7 @@ node_support_output = [
   'queryjumblefuncs.funcs.c', 'queryjumblefuncs.switch.c',
 ]
 node_support_install = [
+  dir_include_server / 'nodes',
   dir_include_server / 'nodes',
   false, false,
   false, false,
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index f8e8fe699a..a325e15dcd 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -235,6 +235,7 @@ extern int16 *readAttrNumberCols(int numCols);
 /*
  * nodes/copyfuncs.c
  */
+extern void *copyObjectFlat(const void *from);
 extern void *copyObjectImpl(const void *from);
 
 /* cast result back to argument type, if supported by compiler */
diff --git a/src/tools/msvc/Solution.pm b/src/tools/msvc/Solution.pm
index 1cbc857e35..52b71e5f84 100644
--- a/src/tools/msvc/Solution.pm
+++ b/src/tools/msvc/Solution.pm
@@ -847,6 +847,14 @@ EOF
 		close($f);
 	}
 
+	if (IsNewer(
+			'src/include/nodes/nodesizes.h',
+			'src/backend/nodes/nodesizes.h'))
+	{
+		copyFile('src/backend/nodes/nodesizes.h',
+			'src/include/nodes/nodesizes.h');
+	}
+
 	if (IsNewer(
 			'src/include/nodes/nodetags.h',
 			'src/backend/nodes/nodetags.h'))
diff --git a/src/tools/msvc/clean.bat b/src/tools/msvc/clean.bat
index 7cb23ea894..f38e0f8dd2 100755
--- a/src/tools/msvc/clean.bat
+++ b/src/tools/msvc/clean.bat
@@ -41,6 +41,7 @@ REM Delete files created with GenerateFiles() in Solution.pm
 if exist src\include\pg_config.h del /q src\include\pg_config.h
 if exist src\include\pg_config_ext.h del /q src\include\pg_config_ext.h
 if exist src\include\pg_config_os.h del /q src\include\pg_config_os.h
+if exist src\include\nodes\nodesizes.h del /q src\include\nodes\nodesizes.h
 if exist src\include\nodes\nodetags.h del /q src\include\nodes\nodetags.h
 if exist src\include\utils\errcodes.h del /q src\include\utils\errcodes.h
 if exist src\include\utils\fmgroids.h del /q src\include\utils\fmgroids.h
diff --git a/src/tools/pginclude/cpluspluscheck b/src/tools/pginclude/cpluspluscheck
index 4e09c4686b..a5f999c5da 100755
--- a/src/tools/pginclude/cpluspluscheck
+++ b/src/tools/pginclude/cpluspluscheck
@@ -97,6 +97,10 @@ do
 	# sepgsql.h depends on headers that aren't there on most platforms.
 	test "$f" = contrib/sepgsql/sepgsql.h && continue
 
+	# nodesizes.h cannot be included standalone: it's just a code fragment.
+	test "$f" = src/include/nodes/nodesizes.h && continue
+	test "$f" = src/backend/nodes/nodesizes.h && continue
+
 	# nodetags.h cannot be included standalone: it's just a code fragment.
 	test "$f" = src/include/nodes/nodetags.h && continue
 	test "$f" = src/backend/nodes/nodetags.h && continue
diff --git a/src/tools/pginclude/headerscheck b/src/tools/pginclude/headerscheck
index 8dee1b5670..18cb54dbb1 100755
--- a/src/tools/pginclude/headerscheck
+++ b/src/tools/pginclude/headerscheck
@@ -92,6 +92,10 @@ do
 	# sepgsql.h depends on headers that aren't there on most platforms.
 	test "$f" = contrib/sepgsql/sepgsql.h && continue
 
+	# nodesizes.h cannot be included standalone: it's just a code fragment.
+	test "$f" = src/include/nodes/nodesizes.h && continue
+	test "$f" = src/backend/nodes/nodesizes.h && continue
+
 	# nodetags.h cannot be included standalone: it's just a code fragment.
 	test "$f" = src/include/nodes/nodetags.h && continue
 	test "$f" = src/backend/nodes/nodetags.h && continue