diff --git a/src/backend/utils/Gen_fmgrtab.pl b/src/backend/utils/Gen_fmgrtab.pl
index cafe408..9fceb60 100644
*** a/src/backend/utils/Gen_fmgrtab.pl
--- b/src/backend/utils/Gen_fmgrtab.pl
*************** use Catalog;
*** 18,23 ****
--- 18,24 ----
  
  use strict;
  use warnings;
+ use PerfectHash;
  
  # Collect arguments
  my @input_files;
*************** foreach my $s (sort { $a->{oid} <=> $b->
*** 219,237 ****
  	print $pfh "extern Datum $s->{prosrc}(PG_FUNCTION_ARGS);\n";
  }
  
! # Create the fmgr_builtins table, collect data for fmgr_builtin_oid_index
  print $tfh "\nconst FmgrBuiltin fmgr_builtins[] = {\n";
  my %bmap;
  $bmap{'t'} = 'true';
  $bmap{'f'} = 'false';
! my @fmgr_builtin_oid_index;
  my $fmgr_count = 0;
  foreach my $s (sort { $a->{oid} <=> $b->{oid} } @fmgr)
  {
  	print $tfh
  	  "  { $s->{oid}, $s->{nargs}, $bmap{$s->{strict}}, $bmap{$s->{retset}}, \"$s->{prosrc}\", $s->{prosrc} }";
  
! 	$fmgr_builtin_oid_index[ $s->{oid} ] = $fmgr_count++;
  
  	if ($fmgr_count <= $#fmgr)
  	{
--- 220,244 ----
  	print $pfh "extern Datum $s->{prosrc}(PG_FUNCTION_ARGS);\n";
  }
  
! # Create the fmgr_builtins table, collect data for hash function
  print $tfh "\nconst FmgrBuiltin fmgr_builtins[] = {\n";
  my %bmap;
  $bmap{'t'} = 'true';
  $bmap{'f'} = 'false';
! my @fmgr_builtin_oids;
! my $prev_oid = 0;
  my $fmgr_count = 0;
  foreach my $s (sort { $a->{oid} <=> $b->{oid} } @fmgr)
  {
  	print $tfh
  	  "  { $s->{oid}, $s->{nargs}, $bmap{$s->{strict}}, $bmap{$s->{retset}}, \"$s->{prosrc}\", $s->{prosrc} }";
  
! 	die "duplicate OIDs" if $s->{oid} <= $prev_oid;
! 	$prev_oid = $s->{oid};
! 
! 	push @fmgr_builtin_oids, pack("n", $s->{oid});
! 
! 	$fmgr_count++;
  
  	if ($fmgr_count <= $#fmgr)
  	{
*************** print $tfh "};\n";
*** 246,283 ****
  
  print $tfh qq|
  const int fmgr_nbuiltins = (sizeof(fmgr_builtins) / sizeof(FmgrBuiltin));
- |;
  
- 
- # Create fmgr_builtins_oid_index table.
- #
- # Note that the array has to be filled up to FirstGenbkiObjectId,
- # as we can't rely on zero initialization as 0 is a valid mapping.
- print $tfh qq|
- const uint16 fmgr_builtin_oid_index[FirstGenbkiObjectId] = {
  |;
  
- for (my $i = 0; $i < $FirstGenbkiObjectId; $i++)
- {
- 	my $oid = $fmgr_builtin_oid_index[$i];
  
! 	# fmgr_builtin_oid_index is sparse, map nonexistant functions to
! 	# InvalidOidBuiltinMapping
! 	if (not defined $oid)
! 	{
! 		$oid = 'InvalidOidBuiltinMapping';
! 	}
  
! 	if ($i + 1 == $FirstGenbkiObjectId)
! 	{
! 		print $tfh "  $oid\n";
! 	}
! 	else
! 	{
! 		print $tfh "  $oid,\n";
! 	}
! }
! print $tfh "};\n";
  
  
  # And add the file footers.
--- 253,267 ----
  
  print $tfh qq|
  const int fmgr_nbuiltins = (sizeof(fmgr_builtins) / sizeof(FmgrBuiltin));
  
  |;
  
  
! # Create perfect hash function for searching fmgr_builtin by OID.
  
! print $tfh PerfectHash::generate_hash_function(\@fmgr_builtin_oids,
! 					       "fmgr_builtin_oid_hash",
! 					       0);
  
  
  # And add the file footers.
diff --git a/src/backend/utils/fmgr/fmgr.c b/src/backend/utils/fmgr/fmgr.c
index b41649f..ad93032 100644
*** a/src/backend/utils/fmgr/fmgr.c
--- b/src/backend/utils/fmgr/fmgr.c
*************** extern Datum fmgr_security_definer(PG_FU
*** 72,92 ****
  static const FmgrBuiltin *
  fmgr_isbuiltin(Oid id)
  {
! 	uint16		index;
  
  	/* fast lookup only possible if original oid still assigned */
  	if (id >= FirstGenbkiObjectId)
  		return NULL;
  
  	/*
! 	 * Lookup function data. If there's a miss in that range it's likely a
! 	 * nonexistant function, returning NULL here will trigger an ERROR later.
  	 */
! 	index = fmgr_builtin_oid_index[id];
! 	if (index == InvalidOidBuiltinMapping)
  		return NULL;
  
! 	return &fmgr_builtins[index];
  }
  
  /*
--- 72,103 ----
  static const FmgrBuiltin *
  fmgr_isbuiltin(Oid id)
  {
! 	const FmgrBuiltin *result;
! 	uint16		hashkey;
! 	int index;
  
  	/* fast lookup only possible if original oid still assigned */
  	if (id >= FirstGenbkiObjectId)
  		return NULL;
  
  	/*
! 	 * Lookup function data.  The hash key for this is the low-order 16 bits
! 	 * of the OID, in network byte order.
  	 */
! 	hashkey = htons(id);
! 	index = fmgr_builtin_oid_hash(&hashkey, sizeof(hashkey));
! 
! 	/* Out-of-range hash result means definitely no match */
! 	if (index < 0 || index >= fmgr_nbuiltins)
  		return NULL;
  
! 	result = &fmgr_builtins[index];
! 
! 	/* We have to verify the match, though */
! 	if (id != result->foid)
! 		return NULL;
! 
! 	return result;
  }
  
  /*
diff --git a/src/include/utils/fmgrtab.h b/src/include/utils/fmgrtab.h
index a778f88..f27aff5 100644
*** a/src/include/utils/fmgrtab.h
--- b/src/include/utils/fmgrtab.h
*************** extern const FmgrBuiltin fmgr_builtins[]
*** 36,46 ****
  
  extern const int fmgr_nbuiltins;	/* number of entries in table */
  
! /*
!  * Mapping from a builtin function's oid to the index in the fmgr_builtins
!  * array.
!  */
! #define InvalidOidBuiltinMapping PG_UINT16_MAX
! extern const uint16 fmgr_builtin_oid_index[FirstGenbkiObjectId];
  
  #endif							/* FMGRTAB_H */
--- 36,41 ----
  
  extern const int fmgr_nbuiltins;	/* number of entries in table */
  
! extern int fmgr_builtin_oid_hash(const void *key, size_t keylen);
  
  #endif							/* FMGRTAB_H */
diff --git a/src/tools/PerfectHash.pm b/src/tools/PerfectHash.pm
index 34d55cf..862357b 100644
*** a/src/tools/PerfectHash.pm
--- b/src/tools/PerfectHash.pm
*************** sub generate_hash_function
*** 77,83 ****
  	# but these two multipliers are chosen to be cheap to calculate via
  	# shift-and-add, so don't change them except at great need.
  	my $hash_mult1 = 31;
! 	my $hash_mult2 = 37;
  
  	# We just try successive hash seed values until we find one that works.
  	# (Commonly, random seeds are tried, but we want reproducible results
--- 77,83 ----
  	# but these two multipliers are chosen to be cheap to calculate via
  	# shift-and-add, so don't change them except at great need.
  	my $hash_mult1 = 31;
! 	my $hash_mult2 = 1029;
  
  	# We just try successive hash seed values until we find one that works.
  	# (Commonly, random seeds are tried, but we want reproducible results
