diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c
index 5f46415..c490364 100644
*** a/src/backend/optimizer/path/indxpath.c
--- b/src/backend/optimizer/path/indxpath.c
***************
*** 35,40 ****
--- 35,41 ----
  #include "optimizer/var.h"
  #include "utils/builtins.h"
  #include "utils/bytea.h"
+ #include "utils/fmgroids.h"
  #include "utils/lsyscache.h"
  #include "utils/pg_locale.h"
  #include "utils/selfuncs.h"
***************
*** 44,49 ****
--- 45,53 ----
  #define IndexCollMatchesExprColl(idxcollation, exprcollation) \
  	((idxcollation) == InvalidOid || (idxcollation) == (exprcollation))
  
+ /* XXX this ought to be available from fmgroids.h, but it isn't */
+ #define F_NAME_VARCHAR 1401
+ 
  /* Whether we are looking for plain indexscan, bitmap scan, or either */
  typedef enum
  {
*************** static bool ec_member_matches_indexcol(P
*** 172,177 ****
--- 176,189 ----
  						   void *arg);
  static bool match_boolean_index_clause(Node *clause, int indexcol,
  						   IndexOptInfo *index);
+ static bool match_name_index_clause(Node *leftop,
+ 						Node *rightop,
+ 						Relids left_relids,
+ 						Relids right_relids,
+ 						Oid expr_op,
+ 						bool plain_op,
+ 						int indexcol,
+ 						IndexOptInfo *index);
  static bool match_special_index_operator(Expr *clause,
  							 Oid opfamily, Oid idxcollation,
  							 bool indexkey_on_left);
*************** match_clause_to_indexcol(IndexOptInfo *i
*** 2474,2479 ****
--- 2486,2504 ----
  		return false;
  	}
  
+ 	/*
+ 	 * If we didn't match above, perhaps it is a textual operator that we
+ 	 * could convert to a name operator.
+ 	 */
+ 	if (opfamily == NAME_BTREE_FAM_OID)
+ 	{
+ 		if (match_name_index_clause(leftop, rightop,
+ 									left_relids, right_relids,
+ 									expr_op, plain_op,
+ 									indexcol, index))
+ 			return true;
+ 	}
+ 
  	return false;
  }
  
*************** match_index_to_operand(Node *operand,
*** 3331,3337 ****
   * because constant simplification does the reverse transformation;
   * without this code there'd be no way to use such an index at all.)
   *
!  * Three routines are provided here:
   *
   * match_special_index_operator() is just an auxiliary function for
   * match_clause_to_indexcol(); after the latter fails to recognize a
--- 3356,3372 ----
   * because constant simplification does the reverse transformation;
   * without this code there'd be no way to use such an index at all.)
   *
!  * Another thing we do here is to support indexing of textual comparisons to
!  * "name" columns, for instance "WHERE pg_class.relname::text = something".
!  * We can handle that by replacing the text operator with a name operator.
!  *
!  * Because this infrastructure was designed for the lossy-operator case,
!  * we'll end up applying the original operator as a qpqual condition even
!  * though it is redundant in the "boolean" and "name" cases.  This is
!  * annoying, but such cases don't come up often enough to justify refactoring
!  * to avoid it (at least, not yet).
!  *
!  * Four routines are provided here:
   *
   * match_special_index_operator() is just an auxiliary function for
   * match_clause_to_indexcol(); after the latter fails to recognize a
*************** match_index_to_operand(Node *operand,
*** 3342,3353 ****
   * match_boolean_index_clause() similarly detects clauses that can be
   * converted into boolean equality operators.
   *
   * expand_indexqual_conditions() converts a list of RestrictInfo nodes
   * (with implicit AND semantics across list elements) into a list of clauses
   * that the executor can actually handle.  For operators that are members of
   * the index's opfamily this transformation is a no-op, but clauses recognized
!  * by match_special_index_operator() or match_boolean_index_clause() must be
!  * converted into one or more "regular" indexqual conditions.
   */
  
  /*
--- 3377,3391 ----
   * match_boolean_index_clause() similarly detects clauses that can be
   * converted into boolean equality operators.
   *
+  * match_name_index_clause() similarly detects clauses that can be
+  * converted into name comparison operators.
+  *
   * expand_indexqual_conditions() converts a list of RestrictInfo nodes
   * (with implicit AND semantics across list elements) into a list of clauses
   * that the executor can actually handle.  For operators that are members of
   * the index's opfamily this transformation is a no-op, but clauses recognized
!  * by the above routines must be converted into one or more "regular"
!  * indexqual conditions.
   */
  
  /*
*************** match_boolean_index_clause(Node *clause,
*** 3393,3398 ****
--- 3431,3523 ----
  }
  
  /*
+  * extract_name_from_text_coercion
+  *	  Helper function for match_name_index_clause.
+  *
+  * If the given operand represents coercion of a "name" value to "text"
+  * or "varchar", return the "name" subexpression.  Else return NULL.
+  */
+ static Node *
+ extract_name_from_text_coercion(Node *operand)
+ {
+ 	/* Ignore any RelabelType node above the operand */
+ 	if (operand && IsA(operand, RelabelType))
+ 		operand = (Node *) ((RelabelType *) operand)->arg;
+ 
+ 	/* Match if it's a call to name_text(), in either of its guises */
+ 	if (operand && IsA(operand, FuncExpr) &&
+ 		(((FuncExpr *) operand)->funcid == F_NAME_TEXT ||
+ 		 ((FuncExpr *) operand)->funcid == F_NAME_VARCHAR))
+ 	{
+ 		Assert(list_length(((FuncExpr *) operand)->args) == 1);
+ 		return (Node *) linitial(((FuncExpr *) operand)->args);
+ 	}
+ 
+ 	return NULL;
+ }
+ 
+ /*
+  * match_name_index_clause
+  *	  Recognize restriction clauses that can be matched to a "name" index.
+  *
+  * This should be called only when the index's operator family is
+  * NAME_BTREE_FAM_OID.  We check to see if the clause is a textual comparison
+  * clause that can be converted into a name comparison matching the index.
+  * Since this is called after match_clause_to_indexcol has disassembled the
+  * clause, we rely on that work rather than re-disassembling the clause.
+  *
+  * Converting texteq is safe because text and name have the same notion of
+  * equality, viz bitwise.  If we ever support collations in which text
+  * equality is not bitwise, we'd need to reject texteq clauses using such
+  * collations.  We cannot convert textual inequality clauses because they
+  * might use a different sort order.  (XXX: maybe convert if C locale?)
+  */
+ static bool
+ match_name_index_clause(Node *leftop,
+ 						Node *rightop,
+ 						Relids left_relids,
+ 						Relids right_relids,
+ 						Oid expr_op,
+ 						bool plain_op,
+ 						int indexcol,
+ 						IndexOptInfo *index)
+ {
+ 	Index		index_relid = index->rel->relid;
+ 	Node	   *nameop;
+ 
+ 	/*
+ 	 * For the moment, only consider text equality.
+ 	 */
+ 	if (expr_op != TextEqualOperator)
+ 		return false;
+ 
+ 	/* We don't support ScalarArrayOp either */
+ 	if (!plain_op)
+ 		return false;
+ 
+ 	/*
+ 	 * Check to see if we have (indexkey::text = constant), following the same
+ 	 * rules as in match_clause_to_indexcol about what is a constant.
+ 	 */
+ 	if ((nameop = extract_name_from_text_coercion(leftop)) != NULL &&
+ 		match_index_to_operand(nameop, indexcol, index) &&
+ 		!bms_is_member(index_relid, right_relids) &&
+ 		!contain_volatile_functions(rightop))
+ 		return true;
+ 
+ 	/*
+ 	 * Also try (constant = indexkey::text).
+ 	 */
+ 	if ((nameop = extract_name_from_text_coercion(rightop)) != NULL &&
+ 		match_index_to_operand(nameop, indexcol, index) &&
+ 		!bms_is_member(index_relid, left_relids) &&
+ 		!contain_volatile_functions(leftop))
+ 		return true;
+ 
+ 	return false;
+ }
+ 
+ /*
   * match_special_index_operator
   *	  Recognize restriction clauses that can be used to generate
   *	  additional indexscanable qualifications.
*************** expand_boolean_index_clause(Node *clause
*** 3732,3738 ****
   * The input is a single RestrictInfo, the output a list of RestrictInfos.
   *
   * In the base case this is just list_make1(), but we have to be prepared to
!  * expand special cases that were accepted by match_special_index_operator().
   */
  static List *
  expand_indexqual_opclause(RestrictInfo *rinfo, Oid opfamily, Oid idxcollation)
--- 3857,3864 ----
   * The input is a single RestrictInfo, the output a list of RestrictInfos.
   *
   * In the base case this is just list_make1(), but we have to be prepared to
!  * expand special cases that were accepted by match_special_index_operator()
!  * or match_name_index_clause().
   */
  static List *
  expand_indexqual_opclause(RestrictInfo *rinfo, Oid opfamily, Oid idxcollation)
*************** expand_indexqual_opclause(RestrictInfo *
*** 3814,3819 ****
--- 3940,3990 ----
  											patt->constvalue);
  			}
  			break;
+ 
+ 			/*
+ 			 * This is in lots of opclasses, but we should only change it if
+ 			 * it was matched to a "name" index.
+ 			 */
+ 		case TextEqualOperator:
+ 			if (opfamily == NAME_BTREE_FAM_OID)
+ 			{
+ 				Node	   *nameop;
+ 				bool		leftisname = false;
+ 				bool		rightisname = false;
+ 				Oid			new_op;
+ 				Expr	   *opexpr;
+ 
+ 				/* Drop any coercion to text on either side */
+ 				if ((nameop = extract_name_from_text_coercion(leftop)) != NULL)
+ 				{
+ 					leftop = nameop;
+ 					leftisname = true;
+ 				}
+ 				if ((nameop = extract_name_from_text_coercion(rightop)) != NULL)
+ 				{
+ 					rightop = nameop;
+ 					rightisname = true;
+ 				}
+ 				/* Choose new operator, construct replacement clause */
+ 				if (leftisname)
+ 				{
+ 					if (rightisname)
+ 						new_op = NameEqualOperator;
+ 					else
+ 						new_op = NameEqualTextOperator;
+ 				}
+ 				else
+ 				{
+ 					/* Should not be here unless one side was coerced */
+ 					Assert(rightisname);
+ 					new_op = TextEqualNameOperator;
+ 				}
+ 				opexpr = make_opclause(new_op, BOOLOID, false,
+ 									   (Expr *) leftop, (Expr *) rightop,
+ 									   InvalidOid, InvalidOid);
+ 				return list_make1(make_simple_restrictinfo(opexpr));
+ 			}
+ 			break;
  	}
  
  	/* Default case: just make a list of the unmodified indexqual */
