From c142dc590431da977757c7402a6443c9afd3548c Mon Sep 17 00:00:00 2001
From: Peter Geoghegan <peter.geoghegan86@gmail.com>
Date: Mon, 11 May 2015 15:37:54 -0700
Subject: [PATCH 1/2] Refactor parse analysis of ON CONFLICT inference

Defer lookup of the opfamily and input type of a user specified opclass
until the optimizer selects among available unique indexes.
---
 contrib/pg_stat_statements/pg_stat_statements.c |  3 +--
 src/backend/nodes/copyfuncs.c                   |  3 +--
 src/backend/nodes/equalfuncs.c                  |  3 +--
 src/backend/nodes/outfuncs.c                    |  3 +--
 src/backend/nodes/readfuncs.c                   |  3 +--
 src/backend/optimizer/util/plancat.c            | 20 +++++++++++++++-----
 src/backend/parser/parse_clause.c               | 14 +++-----------
 src/include/nodes/primnodes.h                   |  3 +--
 8 files changed, 24 insertions(+), 28 deletions(-)

diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index c4d3ee5..3cc687b 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -2645,8 +2645,7 @@ JumbleExpr(pgssJumbleState *jstate, Node *node)
 				InferenceElem *ie = (InferenceElem *) node;
 
 				APP_JUMB(ie->infercollid);
-				APP_JUMB(ie->inferopfamily);
-				APP_JUMB(ie->inferopcinputtype);
+				APP_JUMB(ie->inferopclass);
 				JumbleExpr(jstate, ie->expr);
 			}
 			break;
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index fa7d286..94f79ef 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -1838,8 +1838,7 @@ _copyInferenceElem(const InferenceElem *from)
 
 	COPY_NODE_FIELD(expr);
 	COPY_SCALAR_FIELD(infercollid);
-	COPY_SCALAR_FIELD(inferopfamily);
-	COPY_SCALAR_FIELD(inferopcinputtype);
+	COPY_SCALAR_FIELD(inferopclass);
 
 	return newnode;
 }
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index d7928a9..f19251e 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -702,8 +702,7 @@ _equalInferenceElem(const InferenceElem *a, const InferenceElem *b)
 {
 	COMPARE_NODE_FIELD(expr);
 	COMPARE_SCALAR_FIELD(infercollid);
-	COMPARE_SCALAR_FIELD(inferopfamily);
-	COMPARE_SCALAR_FIELD(inferopcinputtype);
+	COMPARE_SCALAR_FIELD(inferopclass);
 
 	return true;
 }
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 66fee3e..c47a637 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -1473,8 +1473,7 @@ _outInferenceElem(StringInfo str, const InferenceElem *node)
 
 	WRITE_NODE_FIELD(expr);
 	WRITE_OID_FIELD(infercollid);
-	WRITE_OID_FIELD(inferopfamily);
-	WRITE_OID_FIELD(inferopcinputtype);
+	WRITE_OID_FIELD(inferopclass);
 }
 
 static void
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index 6fd9d46..f5a40fb 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -1214,8 +1214,7 @@ _readInferenceElem(void)
 
 	READ_NODE_FIELD(expr);
 	READ_OID_FIELD(infercollid);
-	READ_OID_FIELD(inferopfamily);
-	READ_OID_FIELD(inferopcinputtype);
+	READ_OID_FIELD(inferopclass);
 
 	READ_DONE();
 }
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index b425680..cbb4776 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -633,7 +633,7 @@ infer_arbiter_indexes(PlannerInfo *root)
 			 * index definition.
 			 */
 			if (elem->infercollid != InvalidOid ||
-				elem->inferopfamily != InvalidOid ||
+				elem->inferopclass != InvalidOid ||
 				list_member(idxExprs, elem->expr))
 				continue;
 
@@ -709,23 +709,33 @@ infer_collation_opclass_match(InferenceElem *elem, Relation idxRel,
 							  Bitmapset *inferAttrs, List *idxExprs)
 {
 	AttrNumber	natt;
+	Oid			inferopfamily = InvalidOid;		/* OID of att opfamily */
+	Oid			inferopcinputtype = InvalidOid;		/* OID of att opfamily */
 
 	/*
 	 * If inference specification element lacks collation/opclass, then no
 	 * need to check for exact match.
 	 */
-	if (elem->infercollid == InvalidOid && elem->inferopfamily == InvalidOid)
+	if (elem->infercollid == InvalidOid && elem->inferopclass == InvalidOid)
 		return true;
 
+	/*
+	 * Lookup opfamily and input type, for matching indexes
+	 */
+	if (elem->inferopclass)
+	{
+		inferopfamily = get_opclass_family(elem->inferopclass);
+		inferopcinputtype = get_opclass_input_type(elem->inferopclass);
+	}
+
 	for (natt = 1; natt <= idxRel->rd_att->natts; natt++)
 	{
 		Oid		opfamily = idxRel->rd_opfamily[natt - 1];
 		Oid		opcinputtype = idxRel->rd_opcintype[natt - 1];
 		Oid		collation = idxRel->rd_indcollation[natt - 1];
 
-		if (elem->inferopfamily != InvalidOid &&
-			(elem->inferopfamily != opfamily ||
-			 elem->inferopcinputtype != opcinputtype))
+		if (elem->inferopclass != InvalidOid &&
+			(inferopfamily != opfamily || inferopcinputtype != opcinputtype))
 		{
 			/* Attribute needed to match opclass, but didn't */
 			continue;
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c
index a90bcf4..c8af5ab 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -2730,18 +2730,10 @@ resolve_unique_index_expr(ParseState *pstate, InferClause *infer,
 												  exprLocation(pInfer->expr));
 
 		if (!ielem->opclass)
-		{
-			pInfer->inferopfamily = InvalidOid;
-			pInfer->inferopcinputtype = InvalidOid;
-		}
+			pInfer->inferopclass = InvalidOid;
 		else
-		{
-			Oid		opclass = get_opclass_oid(BTREE_AM_OID, ielem->opclass,
-											  false);
-
-			pInfer->inferopfamily = get_opclass_family(opclass);
-			pInfer->inferopcinputtype = get_opclass_input_type(opclass);
-		}
+			pInfer->inferopclass = get_opclass_oid(BTREE_AM_OID,
+												   ielem->opclass, false);
 
 		result = lappend(result, pInfer);
 	}
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index a5467c5..9f3a726 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -1198,8 +1198,7 @@ typedef struct InferenceElem
 	Expr		xpr;
 	Node	   *expr;				/* expression to infer from, or NULL */
 	Oid			infercollid;		/* OID of collation, or InvalidOid */
-	Oid			inferopfamily;		/* OID of att opfamily, or InvalidOid */
-	Oid			inferopcinputtype;	/* OID of att input type, or InvalidOid */
+	Oid			inferopclass;		/* OID of att opclass, or InvalidOid */
 } InferenceElem;
 
 /*--------------------
-- 
1.9.1

