From 02f83ec98ae362e006f2f5ae178a445a8c142289 Mon Sep 17 00:00:00 2001
From: Amul Sul <sulamul@gmail.com>
Date: Thu, 16 Nov 2017 16:51:34 +0530
Subject: [PATCH 1/3] argument validation v3

---
 src/backend/catalog/partition.c | 65 +++++++++++++++++++++++++++++++++++------
 1 file changed, 56 insertions(+), 9 deletions(-)

diff --git a/src/backend/catalog/partition.c b/src/backend/catalog/partition.c
index ce29ba2eda..ea93646509 100644
--- a/src/backend/catalog/partition.c
+++ b/src/backend/catalog/partition.c
@@ -3103,15 +3103,41 @@ satisfies_hash_partition(PG_FUNCTION_ARGS)
 		int16		nkeys;
 		FmgrInfo	partsupfunc[PARTITION_MAX_KEYS];
 	}			ColumnsHashData;
-	Oid			parentId = PG_GETARG_OID(0);
-	int			modulus = PG_GETARG_INT32(1);
-	int			remainder = PG_GETARG_INT32(2);
+	Oid			parentId;
+	int			modulus;
+	int			remainder;
 	short		nkeys = PG_NARGS() - 3;
 	int			i;
 	Datum		seed = UInt64GetDatum(HASH_PARTITION_SEED);
 	ColumnsHashData *my_extra;
 	uint64		rowHash = 0;
 
+	/*----------
+	 * Error out if any of the following violated:
+	 *
+	 *  1. Parent id, modulus, and the remainder should not be null.
+	 * 	2. Parent id must be valid relation id,
+	 * 	3. Modulus must be a positive integer and
+	 * 	4. Remainder must be a non-negative integer less than the modulus.
+	 *----------
+	 */
+	if (!(PG_ARGISNULL(0) || PG_ARGISNULL(1) || PG_ARGISNULL(2)))
+	{
+		parentId = PG_GETARG_OID(0);
+		modulus = PG_GETARG_INT32(1);
+		remainder = PG_GETARG_INT32(2);
+
+		if (!OidIsValid(parentId) || modulus <= 0 || remainder < 0 ||
+			modulus <= remainder)
+			ereport(ERROR,
+					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+					 errmsg("invalid hash partition bound")));
+	}
+	else
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+				 errmsg("parent relation id, modulus and the remainder cannot be null")));
+
 	/*
 	 * Cache hash function information.
 	 */
@@ -3121,7 +3147,33 @@ satisfies_hash_partition(PG_FUNCTION_ARGS)
 	{
 		Relation	parent;
 		PartitionKey key;
-		int j;
+		int			j;
+
+		/* Open parent relation and fetch partition keyinfo */
+		parent = heap_open(parentId, AccessShareLock);
+		key = RelationGetPartitionKey(parent);
+
+		if (parent->rd_rel->relkind != RELKIND_PARTITIONED_TABLE ||
+			key->strategy != PARTITION_STRATEGY_HASH)
+		{
+			heap_close(parent, AccessShareLock);
+			ereport(ERROR,
+					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+					 errmsg("\"%s\" is not a hash partitioned table",
+							get_rel_name(parentId))));
+		}
+
+		/* complain if too few column values; we ignore extras, however */
+		if (key->partnatts > nkeys)
+		{
+			heap_close(parent, AccessShareLock);
+			ereport(ERROR,
+					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+					 errmsg("value missing for partition column %d",
+							(nkeys + 1))));
+		}
+		else
+			nkeys = key->partnatts;
 
 		fcinfo->flinfo->fn_extra =
 			MemoryContextAllocZero(fcinfo->flinfo->fn_mcxt,
@@ -3131,11 +3183,6 @@ satisfies_hash_partition(PG_FUNCTION_ARGS)
 		my_extra->nkeys = nkeys;
 		my_extra->relid = parentId;
 
-		/* Open parent relation and fetch partition keyinfo */
-		parent = heap_open(parentId, AccessShareLock);
-		key = RelationGetPartitionKey(parent);
-
-		Assert(key->partnatts == nkeys);
 		for (j = 0; j < nkeys; ++j)
 			fmgr_info_copy(&my_extra->partsupfunc[j],
 						   key->partsupfunc,
-- 
2.14.1

