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