hash-v21-hash-part-constraint-v1.patch

text/plain

Filename: hash-v21-hash-part-constraint-v1.patch
Type: text/plain
Part: 0
Message: Re: [POC] hash partitioning

Patch

Format: format-patch
Series: patch v21-0003
Subject: Make constraint exclusion work with hash partitions
File+
src/backend/catalog/partition.c 77 27
src/include/catalog/pg_proc.h 4 2
src/include/fmgr.h 1 0
From 7773ba29d73e2e5cdb4fa7fee68c4598b70bf22f Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Thu, 28 Sep 2017 13:26:00 +0900
Subject: [PATCH 3/3] Make constraint exclusion work with hash partitions

---
 src/backend/catalog/partition.c | 104 +++++++++++++++++++++++++++++-----------
 src/include/catalog/pg_proc.h   |   6 ++-
 src/include/fmgr.h              |   1 +
 3 files changed, 82 insertions(+), 29 deletions(-)

diff --git a/src/backend/catalog/partition.c b/src/backend/catalog/partition.c
index a085a7a0be..ba437c13c8 100644
--- a/src/backend/catalog/partition.c
+++ b/src/backend/catalog/partition.c
@@ -28,6 +28,7 @@
 #include "catalog/pg_inherits.h"
 #include "catalog/pg_inherits_fn.h"
 #include "catalog/pg_opclass.h"
+#include "catalog/pg_operator.h"
 #include "catalog/pg_partitioned_table.h"
 #include "catalog/pg_type.h"
 #include "commands/tablecmds.h"
@@ -174,7 +175,8 @@ static void get_partition_dispatch_recurse(Relation rel, Relation parent,
 static uint64 compute_hash_value(PartitionKey key, Datum *values, bool *isnull);
 
 /* SQL-callable function for use in hash partition CHECK constraints */
-PG_FUNCTION_INFO_V1(satisfies_hash_partition);
+PG_FUNCTION_INFO_V1(hash_partition_modulus);
+PG_FUNCTION_INFO_V1(hash_partition_hash);
 
 /*
  * RelationBuildPartitionDesc
@@ -1705,14 +1707,14 @@ make_partition_op_expr(PartitionKey key, int keynum,
  * This function will return one of the following in the form of an
  * expression:
  *
- * for p_p1: satisfies_hash_partition(2, 1, hash_fn_1_extended(a, HASH_SEED),
- * 											hash_fn_2_extended(b, HASH_SEED))
- * for p_p2: satisfies_hash_partition(4, 2, hash_fn_1_extended(a, HASH_SEED),
- * 											hash_fn_2_extended(b, HASH_SEED))
- * for p_p3: satisfies_hash_partition(8, 0, hash_fn_1_extended(a, HASH_SEED),
- * 											hash_fn_2_extended(b, HASH_SEED))
- * for p_p4: satisfies_hash_partition(8, 4, hash_fn_1_extended(a, HASH_SEED),
- * 											hash_fn_2_extended(b, HASH_SEED))
+ * for p_p1: hash_partition_hash(hash_fn_1_extended(a, HASH_SEED),
+ *								 hash_fn_2_extended(b, HASH_SEED)) % 4 = 1
+ * for p_p2: hash_partition_hash(hash_fn_1_extended(a, HASH_SEED),
+ * 								 hash_fn_2_extended(b, HASH_SEED)) % 4 = 2
+ * for p_p3: hash_partition_hash(hash_fn_1_extended(a, HASH_SEED),
+ * 								 hash_fn_2_extended(b, HASH_SEED)) % 8 = 0
+ * for p_p4: hash_partition_hash(hash_fn_1_extended(a, HASH_SEED),
+ * 								 hash_fn_2_extended(b, HASH_SEED)) % 8 = 4
  *
  * where hash_fn_1_extended and hash_fn_2_extended are datatype-specific hash
  * functions(extended version) for columns a and b respectively and HASH_SEED
@@ -1722,11 +1724,13 @@ static List *
 get_qual_for_hash(Relation parent, PartitionBoundSpec *spec)
 {
 	PartitionKey key = RelationGetPartitionKey(parent);
-	FuncExpr   *fexpr;
+	FuncExpr   *hash_fexpr,
+			   *mod_fexpr;
+	Expr	   *opexpr;
 	Node	   *modulusConst;
 	Node	   *remainderConst;
 	Node	   *hashSeedConst;
-	List	   *args;
+	List	   *args = NIL;
 	ListCell   *partexprs_item;
 	int			i;
 
@@ -1758,13 +1762,13 @@ get_qual_for_hash(Relation parent, PartitionBoundSpec *spec)
 									   false,
 									   FLOAT8PASSBYVAL);
 
-	args = list_make2(modulusConst, remainderConst);
 	partexprs_item = list_head(key->partexprs);
 
 	/* Add an argument for each key column. */
 	for (i = 0; i < key->partnatts; i++)
 	{
 		Node	   *keyCol;
+		FuncExpr   *fexpr;
 
 		/* Left operand */
 		if (key->partattrs[i] != 0)
@@ -1794,14 +1798,26 @@ get_qual_for_hash(Relation parent, PartitionBoundSpec *spec)
 		args = lappend(args, fexpr);
 	}
 
-	fexpr = makeFuncExpr(F_SATISFIES_HASH_PARTITION,
-						 BOOLOID,
-						 args,
-						 InvalidOid,
-						 InvalidOid,
-						 COERCE_EXPLICIT_CALL);
+	hash_fexpr = makeFuncExpr(F_HASH_PARTITION_HASH,
+							  INT8OID,
+							  args,
+							  InvalidOid,
+							  InvalidOid,
+							  COERCE_EXPLICIT_CALL);
+	mod_fexpr = makeFuncExpr(F_HASH_PARTITION_MODULUS,
+							 INT4OID,
+							 list_make2(hash_fexpr, modulusConst),
+							 InvalidOid,
+							 InvalidOid,
+							 COERCE_EXPLICIT_CALL);
+
+	/* Make an fexpr = true expression */
+	opexpr = make_opclause(Int4EqualOperator, BOOLOID, false,
+						   (Expr *) mod_fexpr,
+						   (Expr *) remainderConst,
+						   InvalidOid, InvalidOid);
 
-	return list_make1(fexpr);
+	return list_make1(opexpr);
 }
 
 /*
@@ -3273,7 +3289,43 @@ compute_hash_value(PartitionKey key, Datum *values, bool *isnull)
 }
 
 /*
- * satisfies_hash_partition
+ * hash_partition_modulus
+ *
+ * This is a SQL-callable function for use in hash partition constraint that
+ * takes as arguments a 64-bit hash value and modulus and returns the
+ * remainder obtained by dividing the hash value with modulus.
+ */
+Datum
+hash_partition_modulus(PG_FUNCTION_ARGS)
+{
+	uint64		arg1 = PG_GETARG_UINT64(0);
+	int32		arg2 = PG_GETARG_INT32(1);
+
+	if (arg2 == 0)
+	{
+		ereport(ERROR,
+				(errcode(ERRCODE_DIVISION_BY_ZERO),
+				 errmsg("division by zero")));
+		/* ensure compiler realizes we mustn't reach the division (gcc bug) */
+		PG_RETURN_NULL();
+	}
+
+	/*
+	 * Some machines throw a floating-point exception for INT_MIN % -1, which
+	 * is a bit silly since the correct answer is perfectly well-defined,
+	 * namely zero.  (It's not clear this ever happens when dealing with
+	 * int16, but we might as well have the test for safety.)
+	 */
+	if (arg2 == -1)
+		PG_RETURN_INT32(0);
+
+	/* No overflow is possible */
+
+	PG_RETURN_INT32(arg1 % arg2);
+}
+
+/*
+ * hash_partition_hash
  *
  * This is a SQL-callable function for use in hash partition constraints takes
  * an already computed hash values of each partition key attribute, and combine
@@ -3285,11 +3337,9 @@ compute_hash_value(PartitionKey key, Datum *values, bool *isnull)
  * See get_qual_for_hash() for usage.
  */
 Datum
-satisfies_hash_partition(PG_FUNCTION_ARGS)
+hash_partition_hash(PG_FUNCTION_ARGS)
 {
-	int			modulus = PG_GETARG_INT32(0);
-	int			remainder = PG_GETARG_INT32(1);
-	short		nkeys = PG_NARGS() - 2;
+	short		nkeys = PG_NARGS();
 	int			i;
 	Datum		hash_array[PARTITION_MAX_KEYS];
 	bool		isnull[PARTITION_MAX_KEYS];
@@ -3301,14 +3351,14 @@ satisfies_hash_partition(PG_FUNCTION_ARGS)
 		 * Partition key attribute's hash values start from third argument of
 		 * function.
 		 */
-		isnull[i] = PG_ARGISNULL(i + 2);
+		isnull[i] = PG_ARGISNULL(i);
 
 		if (!isnull[i])
-			hash_array[i] = PG_GETARG_DATUM(i + 2);
+			hash_array[i] = PG_GETARG_DATUM(i);
 	}
 
 	/* Form a single 64-bit hash value */
 	rowHash = mix_hash_value(nkeys, hash_array, isnull);
 
-	PG_RETURN_BOOL(rowHash % modulus == remainder);
+	PG_RETURN_UINT64(rowHash);
 }
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 470b1f6482..fa7e9a6f2b 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -5523,8 +5523,10 @@ DATA(insert OID = 3354 (  pg_ls_waldir				 PGNSP PGUID 12 10 20 0 0 f f f f t t
 DESCR("list of files in the WAL directory");
 
 /* hash partitioning constraint function */
-DATA(insert OID = 5028 ( satisfies_hash_partition PGNSP PGUID 12 1 0 2276 0 f f f f f f i s 3 0 16 "23 23 1007" _null_ _null_ _null_ _null_ _null_ satisfies_hash_partition _null_ _null_ _null_ ));
-DESCR("hash partition CHECK constraint");
+DATA(insert OID = 315 (  hash_partition_modulus		   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 23 "20 23" _null_ _null_ _null_ _null_ _null_ hash_partition_modulus _null_ _null_ _null_ ));
+DESCR("to use in hash partition CHECK constraint");
+DATA(insert OID = 5028 ( hash_partition_hash PGNSP PGUID 12 1 0 2276 0 f f f f f f i s 1 0 20 "1007" _null_ _null_ _null_ _null_ _null_ hash_partition_hash _null_ _null_ _null_ ));
+DESCR("to use in hash partition CHECK constraint");
 
 /*
  * Symbolic values for provolatile column: these indicate whether the result
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index b604a5c162..7535f95382 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -245,6 +245,7 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena *datum);
 #define PG_GETARG_FLOAT4(n)  DatumGetFloat4(PG_GETARG_DATUM(n))
 #define PG_GETARG_FLOAT8(n)  DatumGetFloat8(PG_GETARG_DATUM(n))
 #define PG_GETARG_INT64(n)	 DatumGetInt64(PG_GETARG_DATUM(n))
+#define PG_GETARG_UINT64(n)	 DatumGetUInt64(PG_GETARG_DATUM(n))
 /* use this if you want the raw, possibly-toasted input datum: */
 #define PG_GETARG_RAW_VARLENA_P(n)	((struct varlena *) PG_GETARG_POINTER(n))
 /* use this if you want the input datum de-toasted: */
-- 
2.11.0