From 0ff27333555ad98ad3380b9b15e99e2e6c8bea0d Mon Sep 17 00:00:00 2001
From: Bruce Momjian <bruce@momjian.us>
Date: Sat, 20 Feb 1999 18:01:02 +0000
Subject: [PATCH] Update pathkeys comparison function.

---
 src/backend/optimizer/path/pathkeys.c |  4 +-
 src/backend/optimizer/util/keys.c     | 76 +++++++++++++++------------
 src/backend/optimizer/util/pathnode.c | 26 ++++-----
 3 files changed, 57 insertions(+), 49 deletions(-)

diff --git a/src/backend/optimizer/path/pathkeys.c b/src/backend/optimizer/path/pathkeys.c
index e19eeec01ff..f1ea6cbae68 100644
--- a/src/backend/optimizer/path/pathkeys.c
+++ b/src/backend/optimizer/path/pathkeys.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/path/pathkeys.c,v 1.3 1999/02/20 16:32:35 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/path/pathkeys.c,v 1.4 1999/02/20 18:01:01 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -54,7 +54,7 @@ static List *new_matching_subkeys(Var *subkey, List *considered_subkeys,
  *	{ {tab1.col1, tab2.col1} }.  This allows future joins to use either Var
  *	as a pre-sorted key to prevent Mergejoins from having to re-sort the Path.
  *	They are equal, so they are both primary sort keys.  This is why pathkeys
- *	is a List of Lists.
+ *	is a List of Lists.  -- bjm
  */
  
 /****************************************************************************
diff --git a/src/backend/optimizer/util/keys.c b/src/backend/optimizer/util/keys.c
index 123b6dc4cb4..c921c24c0d1 100644
--- a/src/backend/optimizer/util/keys.c
+++ b/src/backend/optimizer/util/keys.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/util/Attic/keys.c,v 1.18 1999/02/19 02:05:16 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/util/Attic/keys.c,v 1.19 1999/02/20 18:01:02 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -110,62 +110,70 @@ extract_join_key(JoinKey *jk, int outer_or_inner)
  *	  Returns t iff two sets of path keys are equivalent.  They are
  *	  equivalent if the first Var nodes match the second Var nodes.
  *
- *	  XXX		It isn't necessary to check that each sublist exactly contain
- *				the same elements because if the routine that built these
- *				sublists together is correct, having one element in common
- *				implies having all elements in common.
- *		Huh? bjm
+ *	See the top of optimizer/path/pathkeys.c for a description of pathkeys.
+ *	Each pathkey is ordered by its join order, so they not pre-ordered to
+ *	match.  We must search them ourselves.
  *
+ *	This gets called a lot, so it is optimized.
  */
 bool
 pathkeys_match(List *keys1, List *keys2, int *better_key)
 {
 	List	   *key1,
-			   *key2,
-			   *key1a,
-			   *key2a;
+			   *key2;
+	bool		key1_subsetof_key2 = true,
+				key2_subsetof_key1 = true;
 
 	for (key1 = keys1, key2 = keys2;
 		 key1 != NIL && key2 != NIL;
 		 key1 = lnext(key1), key2 = lnext(key2))
 	{
-		for (key1a = lfirst(key1), key2a = lfirst(key2);
-			 key1a != NIL && key2a != NIL;
-			 key1a = lnext(key1a), key2a = lnext(key2a))
-			if (!equal(lfirst(key1a), lfirst(key2a)))
+		List *i;
+
+		if (key1_subsetof_key2)
+			foreach(i, lfirst(key1))
 			{
-				*better_key = 0;
-				return false;
+				Var	*subkey = lfirst(i);
+				if (!member(subkey, lfirst(key2)))
+				{
+					key1_subsetof_key2 = false;
+					break;
+				}
 			}
-		if (key1a != NIL && key2a == NIL)
-		{
-			*better_key = 1;
-			return true;
-		}
-		if (key1a == NIL && key2a != NIL)
-		{
-			*better_key = 2;
-			return true;
-		}
+
+		if (key2_subsetof_key1)
+			foreach(i, lfirst(key2))
+			{
+				Var	*subkey = lfirst(i);
+				if (!member(subkey, lfirst(key1)))
+				{
+					key2_subsetof_key1 = false;
+					break;
+				}
+			}
+		if (!key1_subsetof_key2 && !key2_subsetof_key1)
+			break;	/* no need to continue comparisons. */
 	}
 
-	/* Now the result should be true if list keys2 has at least as many
-	 * entries as keys1, ie, we did not fall off the end of keys2 first.
-	 * If key1 is now NIL then we hit the end of keys1 before or at the
-	 * same time as the end of keys2.
-	 */
-	if (key1 != NIL && key2 == NIL)
+	if (!key1_subsetof_key2 && !key2_subsetof_key1)
 	{
-		*better_key = 1;
-		return true;
+		*better_key = 0;
+		return false;
 	}
-	if (key1 == NIL && key2 != NIL)
+	if (key1_subsetof_key2 && !key2_subsetof_key1)
 	{
 		*better_key = 2;
 		return true;
 	}
+	if (!key1_subsetof_key2 && key2_subsetof_key1)
+	{
+		*better_key = 1;
+		return true;
+	}
+
 	*better_key = 0;
 	return true;
+
 }
 
 /*
diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c
index 9041a9fe9b7..d94e124193e 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/util/pathnode.c,v 1.37 1999/02/18 00:49:38 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/util/pathnode.c,v 1.38 1999/02/20 18:01:02 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -172,15 +172,15 @@ better_path(Path *new_path, List *unique_paths, bool *is_new)
 	{
 		path = (Path *) lfirst(temp);
 
-#if 0
-/*def OPTDUP_DEBUG*/
+#ifdef OPTDUP_DEBUG
 		if (!pathkeys_match(new_path->pathkeys, path->pathkeys, &better_key) ||
 		    better_key != 0)
 		{
-			printf("oldpath\n");
-			pprint(path->pathkeys);
+			printf("betterkey = %d\n", better_key);
 			printf("newpath\n");
 			pprint(new_path->pathkeys);
+			printf("oldpath\n");
+			pprint(path->pathkeys);
 			if (path->pathkeys && new_path->pathkeys &&
 				length(lfirst(path->pathkeys)) >= 2/* &&
 				length(lfirst(path->pathkeys)) <
@@ -191,10 +191,10 @@ better_path(Path *new_path, List *unique_paths, bool *is_new)
 			&better_sort) ||
 			better_sort != 0)
 		{
-			printf("oldord\n");
-			pprint(path->pathorder);
 			printf("neword\n");
 			pprint(new_path->pathorder);
+			printf("oldord\n");
+			pprint(path->pathorder);
 		}
 #endif
 
@@ -204,8 +204,8 @@ better_path(Path *new_path, List *unique_paths, bool *is_new)
 			&better_sort))
 		{
 			/*
-			 * Replace pathkeys that match exactly, (1,2), (1,2).
-			 * Replace pathkeys (1,2) with (1,2,3) if the latter is not
+			 * Replace pathkeys that match exactly, {{1,2}}, {{1,2}}
+			 * Replace pathkeys {{1,2}}with {{1,2,3}}} if the latter is not
 			 * more expensive and replace unordered path with ordered
 			 * path if it is not more expensive.  Favor sorted keys
 			 * over unsorted keys in the same way.
@@ -221,10 +221,10 @@ better_path(Path *new_path, List *unique_paths, bool *is_new)
 			{
 #ifdef OPTDUP_DEBUG
 				printf("replace with new %p old %p better key %d better sort %d\n", &new_path, &path, better_key, better_sort);
-				printf("old\n");
-				pprint(path);
 				printf("new\n");
 				pprint(new_path);
+				printf("old\n");
+				pprint(path);
 #endif
 				*is_new = false;
 				return path;
@@ -241,10 +241,10 @@ better_path(Path *new_path, List *unique_paths, bool *is_new)
 			{
 #ifdef OPTDUP_DEBUG
 				printf("skip new %p old %p better key %d better sort %d\n", &new_path, &path, better_key, better_sort);
-				printf("old\n");
-				pprint(path);
 				printf("new\n");
 				pprint(new_path);
+				printf("old\n");
+				pprint(path);
 #endif
 				*is_new = false;
 				return NULL;
-- 
GitLab