v3-0003-Generate-ObjectProperty-from-catalog-files.patch

text/plain

Filename: v3-0003-Generate-ObjectProperty-from-catalog-files.patch
Type: text/plain
Part: 2
Message: Re: generate syscache info automatically

Patch

Format: format-patch
Series: patch v3-0003
Subject: Generate ObjectProperty from catalog files
File+
src/backend/catalog/genbki.pl 167 0
src/backend/catalog/.gitignore 1 0
src/backend/catalog/Makefile 1 1
src/backend/catalog/objectaddress.c 11 11
src/include/catalog/meson.build 2 0
src/tools/pginclude/cpluspluscheck 3 0
src/tools/pginclude/headerscheck 3 0
From a17faafd7c55f446bd3eb99e3451e23f74a06873 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Thu, 31 Aug 2023 09:51:28 +0200
Subject: [PATCH v3 3/3] Generate ObjectProperty from catalog files

Most of the information can be extracted from catalog files and
generated automatically.

TODO: Currently missing: object type and class description.  There are
some workarounds in place.

We also now replace the linear search with a hash function generated
using PerfectHash.  This would allow this lookup table to be used in
more performance-sensitive situations.

Discussion: https://www.postgresql.org/message-id/flat/75ae5875-3abc-dafc-8aec-73247ed41cde@eisentraut.org
---
 src/backend/catalog/.gitignore      |   1 +
 src/backend/catalog/Makefile        |   2 +-
 src/backend/catalog/genbki.pl       | 167 ++++++++++++++++++++++++++++
 src/backend/catalog/objectaddress.c |  22 ++--
 src/include/catalog/meson.build     |   2 +
 src/tools/pginclude/cpluspluscheck  |   3 +
 src/tools/pginclude/headerscheck    |   3 +
 7 files changed, 188 insertions(+), 12 deletions(-)

diff --git a/src/backend/catalog/.gitignore b/src/backend/catalog/.gitignore
index ff65560379..d817798dc0 100644
--- a/src/backend/catalog/.gitignore
+++ b/src/backend/catalog/.gitignore
@@ -1,3 +1,4 @@
+/objectproperty_info.c.h
 /postgres.bki
 /schemapg.h
 /syscache_info.c.h
diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile
index 2c94126ec5..e6c5878e99 100644
--- a/src/backend/catalog/Makefile
+++ b/src/backend/catalog/Makefile
@@ -120,7 +120,7 @@ CATALOG_HEADERS := \
 	pg_subscription.h \
 	pg_subscription_rel.h
 
-GENERATED_HEADERS := $(CATALOG_HEADERS:%.h=%_d.h) schemapg.h syscache_info.h syscache_info.c.h system_fk_info.h
+GENERATED_HEADERS := $(CATALOG_HEADERS:%.h=%_d.h) objectproperty_info.c.h schemapg.h syscache_info.h syscache_info.c.h system_fk_info.h
 
 POSTGRES_BKI_SRCS := $(addprefix $(top_srcdir)/src/include/catalog/, $(CATALOG_HEADERS))
 
diff --git a/src/backend/catalog/genbki.pl b/src/backend/catalog/genbki.pl
index 78f2da690e..199091305c 100644
--- a/src/backend/catalog/genbki.pl
+++ b/src/backend/catalog/genbki.pl
@@ -19,8 +19,10 @@
 
 use FindBin;
 use lib $FindBin::RealBin;
+use lib "$FindBin::RealBin/../../tools";
 
 use Catalog;
+use PerfectHash;
 
 my $output_path = '';
 my $major_version;
@@ -59,6 +61,7 @@
 my %syscaches;
 my %oidcounts;
 my @system_constraints;
+my @object_properties;
 
 foreach my $header (@ARGV)
 {
@@ -133,6 +136,7 @@
 		$oidcounts{ $toast->{toast_oid} }++;
 		$oidcounts{ $toast->{toast_index_oid} }++;
 	}
+	my ($oid_index, $oid_syscache, $name_syscache, $is_nsp_name_unique);
 	foreach my $index (@{ $catalog->{indexing} })
 	{
 		push @index_decls,
@@ -166,7 +170,136 @@
 				nbuckets => $index->{syscache_nbuckets},
 			};
 		}
+
+		if ($index->{index_decl} eq 'btree(oid oid_ops)')
+		{
+			$oid_index = $index->{index_oid_macro};
+			$oid_syscache = $index->{syscache_name};
+		}
+		if ($index->{index_decl} =~ /\(\w+name name_ops(, \w+namespace oid_ops)?\)/)
+		{
+			$name_syscache = $index->{syscache_name};
+			$is_nsp_name_unique = 1 if $index->{is_unique};
+		}
+	}
+
+	my ($attnum_oid, $attnum_name, $attnum_namespace, $attnum_owner, $attnum_acl);
+	foreach my $att (@$schema)
+	{
+		if ($att->{name} eq 'oid' && $att->{type} eq 'oid')
+		{
+			$attnum_oid = "Anum_${catname}_" . $att->{name};
+		}
+		elsif ($att->{name} =~ /^\w{2,4}name$/ && $att->{type} eq 'name')
+		{
+			$attnum_name = "Anum_${catname}_" . $att->{name};
+		}
+		elsif ($att->{name} =~ /^\w{2,4}namespace$/ && $att->{type} eq 'oid' && $att->{lookup} eq 'pg_namespace')
+		{
+			$attnum_namespace = "Anum_${catname}_" . $att->{name};
+		}
+		elsif ($att->{name} =~ /^\w{2,4}owner$/ && $att->{type} eq 'oid' && $att->{lookup} eq 'pg_authid')
+		{
+			$attnum_owner = "Anum_${catname}_" . $att->{name};
+		}
+		elsif ($att->{name} =~ /^\w{2,4}acl$/ && $att->{type} eq '_aclitem')
+		{
+			$attnum_acl = "Anum_${catname}_" . $att->{name};
+		}
+	}
+
+	# XXX hardcoded exceptions
+	# extension doesn't belong to extnamespace
+	$attnum_namespace = undef if $catname eq 'pg_extension';
+	# pg_database owner is spelled datdba
+	$attnum_owner = "Anum_pg_database_datdba" if $catname eq 'pg_database';
+	# XXX?
+	$name_syscache = "SUBSCRIPTIONNAME" if $catname eq 'pg_subscription';
+	# XXX?
+	$is_nsp_name_unique = 1 if $catname eq 'pg_collation';
+	$is_nsp_name_unique = 1 if $catname eq 'pg_opclass';
+	$is_nsp_name_unique = 1 if $catname eq 'pg_opfamily';
+	$is_nsp_name_unique = 1 if $catname eq 'pg_subscription';
+
+	# XXX These catalogs were not covered by the previous hand-maintained table.
+	my @skip = qw(
+		AttrDefaultRelationId EnumRelationId IndexRelationId
+		LargeObjectRelationId ParameterAclRelationId
+		PublicationNamespaceRelationId PublicationRelRelationId
+		InheritsRelationId AggregateRelationId StatisticRelationId
+		StatisticExtDataRelationId DescriptionRelationId
+		DependRelationId DbRoleSettingRelationId
+		SharedDependRelationId SharedDescriptionRelationId
+		TSConfigMapRelationId ForeignTableRelationId
+		ReplicationOriginRelationId InitPrivsRelationId
+		SecLabelRelationId SharedSecLabelRelationId
+		PartitionedRelationId RangeRelationId SequenceRelationId
+		SubscriptionRelRelationId);
+	# XXX This one neither, but if I add it to @skip, PerfectHash will fail. (???)
+	#FIXME: AttributeRelationId
+
+	# XXX hardcoded ObjectType mapping -- where to put this?
+	my %objtypes = (
+		'AccessMethodRelationId' => 'OBJECT_ACCESS_METHOD',
+		'AccessMethodOperatorRelationId' => 'OBJECT_AMOP',
+		'AccessMethodProcedureRelationId' => 'OBJECT_AMPROC',
+		'CastRelationId' => 'OBJECT_CAST',
+		'CollationRelationId' => 'OBJECT_COLLATION',
+		'ConversionRelationId' => 'OBJECT_CONVERSION',
+		'DatabaseRelationId' => 'OBJECT_DATABASE',
+		'DefaultAclRelationId' => 'OBJECT_DEFACL',
+		'ExtensionRelationId' => 'OBJECT_EXTENSION',
+		'ForeignDataWrapperRelationId' => 'OBJECT_FDW',
+		'ForeignServerRelationId' => 'OBJECT_FOREIGN_SERVER',
+		'ProcedureRelationId' => 'OBJECT_FUNCTION',
+		'LanguageRelationId' => 'OBJECT_LANGUAGE',
+		'LargeObjectMetadataRelationId' => 'OBJECT_LARGEOBJECT',
+		'OperatorClassRelationId' => 'OBJECT_OPCLASS',
+		'OperatorRelationId' => 'OBJECT_OPERATOR',
+		'OperatorFamilyRelationId' => 'OBJECT_OPFAMILY',
+		'AuthIdRelationId' => 'OBJECT_ROLE',
+		'RewriteRelationId' => 'OBJECT_RULE',
+		'NamespaceRelationId' => 'OBJECT_SCHEMA',
+		'RelationRelationId' => 'OBJECT_TABLE',
+		'TableSpaceRelationId' => 'OBJECT_TABLESPACE',
+		'TransformRelationId' => 'OBJECT_TRANSFORM',
+		'TriggerRelationId' => 'OBJECT_TRIGGER',
+		'PolicyRelationId' => 'OBJECT_POLICY',
+		'EventTriggerRelationId' => 'OBJECT_EVENT_TRIGGER',
+		'TSConfigRelationId' => 'OBJECT_TSCONFIGURATION',
+		'TSDictionaryRelationId' => 'OBJECT_TSDICTIONARY',
+		'TSParserRelationId' => 'OBJECT_TSPARSER',
+		'TSTemplateRelationId' => 'OBJECT_TSTEMPLATE',
+		'TypeRelationId' => 'OBJECT_TYPE',
+		'PublicationRelationId' => 'OBJECT_PUBLICATION',
+		'SubscriptionRelationId' => 'OBJECT_SUBSCRIPTION',
+		'StatisticExtRelationId' => 'OBJECT_STATISTIC_EXT',
+		'UserMappingRelationId' => 'OBJECT_USER_MAPPING',
+	);
+	my $objtype = $objtypes{$catalog->{relation_oid_macro}};
+
+	# XXX This just uses the catalog name as a string rather than the
+	# previous natural-language description.  This could be changed if
+	# we decide on a place to store this.  But maybe for what we are
+	# using it, this is actually better.
+	my $class_descr = qq{"${catname}"};
+
+	push @object_properties, {
+		class_descr => $class_descr,
+		class_oid => $catalog->{relation_oid_macro},
+		_class_oid => $catalog->{relation_oid},
+		oid_index_oid => $oid_index,
+		oid_catcache_id => $oid_syscache || '-1',
+		name_catcache_id => $name_syscache || '-1',
+		attnum_oid => $attnum_oid,
+		attnum_name => $attnum_name,
+		attnum_namespace => $attnum_namespace,
+		attnum_owner => $attnum_owner,
+		attnum_acl => $attnum_acl,
+		objtype => $objtype,
+		is_nsp_name_unique => $is_nsp_name_unique ? 'true' : 'false',
 	}
+	unless grep { $_ eq $catalog->{relation_oid_macro} } @skip;
 }
 
 # Complain and exit if we found any duplicate OIDs.
@@ -441,6 +574,9 @@
 my $syscache_info_c = $output_path . 'syscache_info.c.h';
 open my $syscache_info_c_fh, '>', $syscache_info_c . $tmpext
   or die "can't open $syscache_info_c$tmpext: $!";
+my $objectproperty_info = $output_path . 'objectproperty_info.c.h';
+open my $objectproperty_info_fh, '>', $objectproperty_info . $tmpext
+  or die "can't open $objectproperty_info$tmpext: $!";
 
 # Generate postgres.bki and pg_*_d.h headers.
 
@@ -810,6 +946,35 @@
 
 print $syscache_info_c_fh "};\n";
 
+# Now generate objectproperty_info
+
+print_boilerplate($objectproperty_info_fh, "objectproperty_info.h", "object property data");
+print $objectproperty_info_fh "\n";
+foreach my $catname (@catnames)
+{
+	print $objectproperty_info_fh qq{#include "catalog/${catname}_d.h"\n};
+}
+print $objectproperty_info_fh "\n";
+print $objectproperty_info_fh "static const ObjectPropertyType ObjectProperty[] =
+{
+";
+
+my @class_oids;
+foreach my $op (@object_properties)
+{
+	print $objectproperty_info_fh "\t{\n";
+	foreach my $p (sort keys %{$op})
+	{
+		printf $objectproperty_info_fh "\t\t.%s = %s,\n", $p, ${$op}{$p} if $p !~ /^_/ && ${$op}{$p};
+	}
+	push @class_oids, pack('N', ${$op}{_class_oid});
+	print $objectproperty_info_fh "\t},\n";
+}
+
+print $objectproperty_info_fh "};\n";
+
+print $objectproperty_info_fh "\nstatic " . PerfectHash::generate_hash_function(\@class_oids, 'objectproperty_hash_func', fixed_key_length => 4);
+
 # We're done emitting data
 close $bki;
 close $schemapg;
@@ -817,6 +982,7 @@
 close $constraints;
 close $syscache_info_h_fh;
 close $syscache_info_c_fh;
+close $objectproperty_info_fh;
 
 # Finally, rename the completed files into place.
 Catalog::RenameTempFile($bkifile, $tmpext);
@@ -825,6 +991,7 @@
 Catalog::RenameTempFile($constraints_file, $tmpext);
 Catalog::RenameTempFile($syscache_info_h, $tmpext);
 Catalog::RenameTempFile($syscache_info_c, $tmpext);
+Catalog::RenameTempFile($objectproperty_info, $tmpext);
 
 exit($num_errors != 0 ? 1 : 0);
 
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index bb4efcad20..6ba84ee86c 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -32,19 +32,10 @@
 #include "catalog/pg_collation.h"
 #include "catalog/pg_constraint.h"
 #include "catalog/pg_conversion.h"
-#include "catalog/pg_database.h"
 #include "catalog/pg_default_acl.h"
-#include "catalog/pg_enum.h"
-#include "catalog/pg_event_trigger.h"
-#include "catalog/pg_extension.h"
-#include "catalog/pg_foreign_data_wrapper.h"
-#include "catalog/pg_foreign_server.h"
 #include "catalog/pg_language.h"
 #include "catalog/pg_largeobject.h"
-#include "catalog/pg_largeobject_metadata.h"
-#include "catalog/pg_namespace.h"
 #include "catalog/pg_opclass.h"
-#include "catalog/pg_operator.h"
 #include "catalog/pg_opfamily.h"
 #include "catalog/pg_parameter_acl.h"
 #include "catalog/pg_policy.h"
@@ -54,8 +45,6 @@
 #include "catalog/pg_publication_rel.h"
 #include "catalog/pg_rewrite.h"
 #include "catalog/pg_statistic_ext.h"
-#include "catalog/pg_subscription.h"
-#include "catalog/pg_tablespace.h"
 #include "catalog/pg_transform.h"
 #include "catalog/pg_trigger.h"
 #include "catalog/pg_ts_config.h"
@@ -119,6 +108,9 @@ typedef struct
 									 * object of this class? */
 } ObjectPropertyType;
 
+#if 1
+#include "catalog/objectproperty_info.c.h"
+#else
 static const ObjectPropertyType ObjectProperty[] =
 {
 	{
@@ -640,6 +632,7 @@ static const ObjectPropertyType ObjectProperty[] =
 		false
 	},
 };
+#endif
 
 /*
  * This struct maps the string object types as returned by
@@ -2791,6 +2784,7 @@ get_object_property_data(Oid class_id)
 {
 	static const ObjectPropertyType *prop_last = NULL;
 	int			index;
+	uint32      hashkey;
 
 	/*
 	 * A shortcut to speed up multiple consecutive lookups of a particular
@@ -2799,7 +2793,13 @@ get_object_property_data(Oid class_id)
 	if (prop_last && prop_last->class_oid == class_id)
 		return prop_last;
 
+#if 1
+	hashkey = pg_hton32(class_id);
+	index = objectproperty_hash_func(&hashkey);
+	if (index >= 0 && index < lengthof(ObjectProperty))
+#else
 	for (index = 0; index < lengthof(ObjectProperty); index++)
+#endif
 	{
 		if (ObjectProperty[index].class_oid == class_id)
 		{
diff --git a/src/include/catalog/meson.build b/src/include/catalog/meson.build
index 39d8e94ae2..3362733b5a 100644
--- a/src/include/catalog/meson.build
+++ b/src/include/catalog/meson.build
@@ -103,6 +103,7 @@ bki_data_f = files(bki_data)
 
 input = []
 output_files = [
+  'objectproperty_info.c.h',
   'postgres.bki',
   'system_constraints.sql',
   'schemapg.h',
@@ -111,6 +112,7 @@ output_files = [
   'system_fk_info.h',
 ]
 output_install = [
+  dir_data,
   dir_data,
   dir_data,
   dir_include_server / 'catalog',
diff --git a/src/tools/pginclude/cpluspluscheck b/src/tools/pginclude/cpluspluscheck
index 56ed423567..49e3ca7a7b 100755
--- a/src/tools/pginclude/cpluspluscheck
+++ b/src/tools/pginclude/cpluspluscheck
@@ -119,6 +119,9 @@ do
 	test "$f" = src/include/common/unicode_nonspacing_table.h && continue
 	test "$f" = src/include/common/unicode_east_asian_fw_table.h && continue
 
+	test "$f" = src/backend/catalog/objectproperty_info.c.h && continue
+	test "$f" = src/include/catalog/objectproperty_info.c.h && continue
+
 	test "$f" = src/backend/catalog/syscache_info.c.h && continue
 	test "$f" = src/backend/catalog/syscache_info.h && continue
 	test "$f" = src/include/catalog/syscache_info.c.h && continue
diff --git a/src/tools/pginclude/headerscheck b/src/tools/pginclude/headerscheck
index 477e4dd7e6..a1ea2ef692 100755
--- a/src/tools/pginclude/headerscheck
+++ b/src/tools/pginclude/headerscheck
@@ -114,6 +114,9 @@ do
 	test "$f" = src/include/common/unicode_nonspacing_table.h && continue
 	test "$f" = src/include/common/unicode_east_asian_fw_table.h && continue
 
+	test "$f" = src/backend/catalog/objectproperty_info.c.h && continue
+	test "$f" = src/include/catalog/objectproperty_info.c.h && continue
+
 	test "$f" = src/backend/catalog/syscache_info.c.h && continue
 	test "$f" = src/backend/catalog/syscache_info.h && continue
 	test "$f" = src/include/catalog/syscache_info.c.h && continue
-- 
2.41.0