From 42ca7750e2b89caa3aee0c9ab7479a7f29953fff Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Tue, 22 Aug 2017 11:33:27 +0900
Subject: [PATCH v23 1/5] Some interface changes for
 partition_bound_{cmp/bsearch}

Introduces a notion of PartitionBoundCmpArg, which replaces the set
of arguments void *probe and bool probe_is_bound of both
partition_bound_cmp and partition_bound_bsearch.  It wasn't possible
before to specify the number of datums when a non-bound type of
probe is passed.  Slightly tweaking the existing interface to allow
specifying the same seems awkward.  So, instead encapsulate that
into PartitionBoundCmpArg.  Also, modify partition_rbound_datum_cmp
to compare caller-specifed number of datums, instead of
key->partnatts datums.
---
 src/backend/catalog/partition.c | 166 +++++++++++++++++++++++++++++-----------
 1 file changed, 123 insertions(+), 43 deletions(-)

diff --git a/src/backend/catalog/partition.c b/src/backend/catalog/partition.c
index e69bbc0345..de2b53e0c8 100644
--- a/src/backend/catalog/partition.c
+++ b/src/backend/catalog/partition.c
@@ -138,6 +138,31 @@ typedef struct PartitionRangeBound
 	bool		lower;			/* this is the lower (vs upper) bound */
 } PartitionRangeBound;
 
+/*
+ * PartitionBoundCmpArg - Caller-defined argument to be passed to
+ *						  partition_bound_cmp()
+ *
+ * The first (fixed) argument involved in a comparison is the partition bound
+ * found in the catalog, while an instance of the following struct describes
+ * either a new partition bound being compared against existing bounds
+ * (caller should set is_bound to true and set bound), or a new tuple's
+ * partition key specified in datums (caller should set ndatums to the number
+ * of valid datums that are passed in the array).
+ */
+typedef struct PartitionBoundCmpArg
+{
+	bool	is_bound;
+	union
+	{
+		PartitionListValue	   *lbound;
+		PartitionRangeBound	   *rbound;
+		PartitionHashBound	   *hbound;
+	}	bound;
+
+	Datum  *datums;
+	int		ndatums;
+} PartitionBoundCmpArg;
+
 static int32 qsort_partition_hbound_cmp(const void *a, const void *b);
 static int32 qsort_partition_list_value_cmp(const void *a, const void *b,
 							   void *arg);
@@ -170,14 +195,15 @@ static int32 partition_rbound_cmp(PartitionKey key,
 					 bool lower1, PartitionRangeBound *b2);
 static int32 partition_rbound_datum_cmp(PartitionKey key,
 						   Datum *rb_datums, PartitionRangeDatumKind *rb_kind,
-						   Datum *tuple_datums);
+						   Datum *tuple_datums, int n_tuple_datums);
 
 static int32 partition_bound_cmp(PartitionKey key,
 					PartitionBoundInfo boundinfo,
-					int offset, void *probe, bool probe_is_bound);
+					int offset, PartitionBoundCmpArg *arg);
 static int partition_bound_bsearch(PartitionKey key,
 						PartitionBoundInfo boundinfo,
-						void *probe, bool probe_is_bound, bool *is_equal);
+						PartitionBoundCmpArg *arg,
+						bool *is_equal);
 static int	get_partition_bound_num_indexes(PartitionBoundInfo b);
 static int	get_greatest_modulus(PartitionBoundInfo b);
 static uint64 compute_hash_value(PartitionKey key, Datum *values, bool *isnull);
@@ -985,6 +1011,8 @@ check_new_partition_bound(char *relname, Relation parent,
 								valid_modulus = true;
 					int			prev_modulus,	/* Previous largest modulus */
 								next_modulus;	/* Next largest modulus */
+					PartitionHashBound hbound;
+					PartitionBoundCmpArg arg;
 
 					/*
 					 * Check rule that every modulus must be a factor of the
@@ -999,8 +1027,14 @@ check_new_partition_bound(char *relname, Relation parent,
 					 * less than or equal to spec->modulus and
 					 * spec->remainder.
 					 */
-					offset = partition_bound_bsearch(key, boundinfo, spec,
-													 true, &equal);
+					memset(&hbound, 0, sizeof(PartitionHashBound));
+					hbound.modulus = spec->modulus;
+					hbound.remainder = spec->remainder;
+					memset(&arg, 0, sizeof(PartitionBoundCmpArg));
+					arg.is_bound = true;
+					arg.bound.hbound = &hbound;
+					offset = partition_bound_bsearch(key, boundinfo, &arg,
+													 &equal);
 					if (offset < 0)
 					{
 						next_modulus = DatumGetInt32(datums[0][0]);
@@ -1073,10 +1107,16 @@ check_new_partition_bound(char *relname, Relation parent,
 						{
 							int			offset;
 							bool		equal;
-
+							PartitionListValue lbound;
+							PartitionBoundCmpArg arg;
+
+							memset(&lbound, 0, sizeof(PartitionListValue));
+							lbound.value = val->constvalue;
+							memset(&arg, 0, sizeof(PartitionBoundCmpArg));
+							arg.is_bound = true;
+							arg.bound.lbound = &lbound;
 							offset = partition_bound_bsearch(key, boundinfo,
-															 &val->constvalue,
-															 true, &equal);
+															 &arg, &equal);
 							if (offset >= 0 && equal)
 							{
 								overlap = true;
@@ -1127,6 +1167,7 @@ check_new_partition_bound(char *relname, Relation parent,
 					PartitionBoundInfo boundinfo = partdesc->boundinfo;
 					int			offset;
 					bool		equal;
+					PartitionBoundCmpArg	arg;
 
 					Assert(boundinfo &&
 						   boundinfo->strategy == PARTITION_STRATEGY_RANGE &&
@@ -1148,8 +1189,11 @@ check_new_partition_bound(char *relname, Relation parent,
 					 * since the index array is initialised with an extra -1
 					 * at the end.
 					 */
-					offset = partition_bound_bsearch(key, boundinfo, lower,
-													 true, &equal);
+					memset(&arg, 0, sizeof(PartitionBoundCmpArg));
+					arg.is_bound = true;
+					arg.bound.rbound = lower;
+					offset = partition_bound_bsearch(key, boundinfo, &arg,
+													 &equal);
 
 					if (boundinfo->indexes[offset + 1] < 0)
 					{
@@ -1163,9 +1207,9 @@ check_new_partition_bound(char *relname, Relation parent,
 						{
 							int32		cmpval;
 
+							arg.bound.rbound = upper;
 							cmpval = partition_bound_cmp(key, boundinfo,
-														 offset + 1, upper,
-														 true);
+														 offset + 1, &arg);
 							if (cmpval < 0)
 							{
 								/*
@@ -2537,12 +2581,15 @@ get_partition_for_tuple(Relation relation, Datum *values, bool *isnull)
 			else
 			{
 				bool		equal = false;
+				PartitionBoundCmpArg	arg;
 
+				memset(&arg, 0, sizeof(PartitionBoundCmpArg));
+				arg.is_bound = false;
+				arg.datums = values;
+				arg.ndatums = key->partnatts;
 				bound_offset = partition_bound_bsearch(key,
 													   partdesc->boundinfo,
-													   values,
-													   false,
-													   &equal);
+													   &arg, &equal);
 				if (bound_offset >= 0 && equal)
 					part_index = partdesc->boundinfo->indexes[bound_offset];
 			}
@@ -2569,11 +2616,15 @@ get_partition_for_tuple(Relation relation, Datum *values, bool *isnull)
 
 				if (!range_partkey_has_null)
 				{
+					PartitionBoundCmpArg	arg;
+
+					memset(&arg, 0, sizeof(PartitionBoundCmpArg));
+					arg.is_bound = false;
+					arg.datums = values;
+					arg.ndatums = key->partnatts;
 					bound_offset = partition_bound_bsearch(key,
 														   partdesc->boundinfo,
-														   values,
-														   false,
-														   &equal);
+														   &arg, &equal);
 
 					/*
 					 * The bound at bound_offset is less than or equal to the
@@ -2845,12 +2896,12 @@ partition_rbound_cmp(PartitionKey key,
 static int32
 partition_rbound_datum_cmp(PartitionKey key,
 						   Datum *rb_datums, PartitionRangeDatumKind *rb_kind,
-						   Datum *tuple_datums)
+						   Datum *tuple_datums, int n_tuple_datums)
 {
 	int			i;
 	int32		cmpval = -1;
 
-	for (i = 0; i < key->partnatts; i++)
+	for (i = 0; i < n_tuple_datums; i++)
 	{
 		if (rb_kind[i] == PARTITION_RANGE_DATUM_MINVALUE)
 			return -1;
@@ -2872,11 +2923,11 @@ partition_rbound_datum_cmp(PartitionKey key,
  * partition_bound_cmp
  *
  * Return whether the bound at offset in boundinfo is <, =, or > the argument
- * specified in *probe.
+ * specified in *arg.
  */
 static int32
 partition_bound_cmp(PartitionKey key, PartitionBoundInfo boundinfo,
-					int offset, void *probe, bool probe_is_bound)
+					int offset, PartitionBoundCmpArg *arg)
 {
 	Datum	   *bound_datums = boundinfo->datums[offset];
 	int32		cmpval = -1;
@@ -2885,25 +2936,55 @@ partition_bound_cmp(PartitionKey key, PartitionBoundInfo boundinfo,
 	{
 		case PARTITION_STRATEGY_HASH:
 			{
-				PartitionBoundSpec *spec = (PartitionBoundSpec *) probe;
+				int		modulus,
+						remainder;
+
+				if (arg->is_bound)
+				{
+					modulus = arg->bound.hbound->modulus;
+					remainder = arg->bound.hbound->remainder;
+				}
+				else
+				{
+					modulus = DatumGetInt32(arg->datums[0]);
+					remainder = DatumGetInt32(arg->datums[1]);
+				}
 
 				cmpval = partition_hbound_cmp(DatumGetInt32(bound_datums[0]),
 											  DatumGetInt32(bound_datums[1]),
-											  spec->modulus, spec->remainder);
+											  modulus, remainder);
 				break;
 			}
 		case PARTITION_STRATEGY_LIST:
-			cmpval = DatumGetInt32(FunctionCall2Coll(&key->partsupfunc[0],
-													 key->partcollation[0],
-													 bound_datums[0],
-													 *(Datum *) probe));
-			break;
+			{
+				Datum	listdatum;
+
+				if (arg->is_bound)
+					listdatum = arg->bound.lbound->value;
+				else
+				{
+					if (arg->ndatums >= 1)
+						listdatum = arg->datums[0];
+					/*
+					 * If there's no tuple datum to compare with the bound,
+					 * consider the latter to be greater.
+					 */
+					else
+						return 1;
+				}
+
+				cmpval = DatumGetInt32(FunctionCall2Coll(&key->partsupfunc[0],
+														 key->partcollation[0],
+														 bound_datums[0],
+														 listdatum));
+				break;
+			}
 
 		case PARTITION_STRATEGY_RANGE:
 			{
 				PartitionRangeDatumKind *kind = boundinfo->kind[offset];
 
-				if (probe_is_bound)
+				if (arg->is_bound)
 				{
 					/*
 					 * We need to pass whether the existing bound is a lower
@@ -2914,12 +2995,13 @@ partition_bound_cmp(PartitionKey key, PartitionBoundInfo boundinfo,
 
 					cmpval = partition_rbound_cmp(key,
 												  bound_datums, kind, lower,
-												  (PartitionRangeBound *) probe);
+												  arg->bound.rbound);
 				}
 				else
 					cmpval = partition_rbound_datum_cmp(key,
 														bound_datums, kind,
-														(Datum *) probe);
+														arg->datums,
+														arg->ndatums);
 				break;
 			}
 
@@ -2933,20 +3015,19 @@ partition_bound_cmp(PartitionKey key, PartitionBoundInfo boundinfo,
 
 /*
  * Binary search on a collection of partition bounds. Returns greatest
- * bound in array boundinfo->datums which is less than or equal to *probe.
- * If all bounds in the array are greater than *probe, -1 is returned.
+ * bound in array boundinfo->datums which is less than or equal to *arg.
+ * If all bounds in the array are greater than *arg, -1 is returned.
  *
- * *probe could either be a partition bound or a Datum array representing
- * the partition key of a tuple being routed; probe_is_bound tells which.
- * We pass that down to the comparison function so that it can interpret the
- * contents of *probe accordingly.
+ * *arg may contain either a partition bound struct or a Datum array
+ * representing the partition key of a tuple being routed.  We simply pass
+ * that down to partition_bound_cmp where it is interpreted appropriately.
  *
- * *is_equal is set to whether the bound at the returned index is equal with
- * *probe.
+ * *is_equal is set to whether the bound at the returned index is exactly
+ * equal to *arg.
  */
 static int
 partition_bound_bsearch(PartitionKey key, PartitionBoundInfo boundinfo,
-						void *probe, bool probe_is_bound, bool *is_equal)
+						PartitionBoundCmpArg *arg, bool *is_equal)
 {
 	int			lo,
 				hi,
@@ -2959,8 +3040,7 @@ partition_bound_bsearch(PartitionKey key, PartitionBoundInfo boundinfo,
 		int32		cmpval;
 
 		mid = (lo + hi + 1) / 2;
-		cmpval = partition_bound_cmp(key, boundinfo, mid, probe,
-									 probe_is_bound);
+		cmpval = partition_bound_cmp(key, boundinfo, mid, arg);
 		if (cmpval <= 0)
 		{
 			lo = mid;
-- 
2.11.0

