Commit 4b40e44f authored by Tom Lane's avatar Tom Lane

Fix failure with textual partition hash keys.

Commit 5e1963fb overlooked two places in partbounds.c that now
need to pass a collation identifier to the hash functions for
a partition key column.

Amit Langote, per report from Jesper Pedersen

Discussion: https://postgr.es/m/a620f85a-42ab-e0f3-3337-b04b97e2e2f5@redhat.com
parent 47169c25
...@@ -2742,7 +2742,8 @@ compute_partition_hash_value(int partnatts, FmgrInfo *partsupfunc, Oid *partcoll ...@@ -2742,7 +2742,8 @@ compute_partition_hash_value(int partnatts, FmgrInfo *partsupfunc, Oid *partcoll
* datatype-specific hash functions of each partition key * datatype-specific hash functions of each partition key
* attribute. * attribute.
*/ */
hash = FunctionCall2Coll(&partsupfunc[i], partcollation[i], values[i], seed); hash = FunctionCall2Coll(&partsupfunc[i], partcollation[i],
values[i], seed);
/* Form a single 64-bit hash value */ /* Form a single 64-bit hash value */
rowHash = hash_combine64(rowHash, DatumGetUInt64(hash)); rowHash = hash_combine64(rowHash, DatumGetUInt64(hash));
...@@ -2777,7 +2778,8 @@ satisfies_hash_partition(PG_FUNCTION_ARGS) ...@@ -2777,7 +2778,8 @@ satisfies_hash_partition(PG_FUNCTION_ARGS)
int16 variadic_typlen; int16 variadic_typlen;
bool variadic_typbyval; bool variadic_typbyval;
char variadic_typalign; char variadic_typalign;
FmgrInfo partsupfunc[PARTITION_MAX_KEYS]; Oid partcollid[PARTITION_MAX_KEYS];
FmgrInfo partsupfunc[FLEXIBLE_ARRAY_MEMBER];
} ColumnsHashData; } ColumnsHashData;
Oid parentId; Oid parentId;
int modulus; int modulus;
...@@ -2850,6 +2852,8 @@ satisfies_hash_partition(PG_FUNCTION_ARGS) ...@@ -2850,6 +2852,8 @@ satisfies_hash_partition(PG_FUNCTION_ARGS)
my_extra = (ColumnsHashData *) fcinfo->flinfo->fn_extra; my_extra = (ColumnsHashData *) fcinfo->flinfo->fn_extra;
my_extra->relid = parentId; my_extra->relid = parentId;
my_extra->nkeys = key->partnatts; my_extra->nkeys = key->partnatts;
memcpy(my_extra->partcollid, key->partcollation,
key->partnatts * sizeof(Oid));
/* check argument types and save fmgr_infos */ /* check argument types and save fmgr_infos */
for (j = 0; j < key->partnatts; ++j) for (j = 0; j < key->partnatts; ++j)
...@@ -2866,7 +2870,6 @@ satisfies_hash_partition(PG_FUNCTION_ARGS) ...@@ -2866,7 +2870,6 @@ satisfies_hash_partition(PG_FUNCTION_ARGS)
&key->partsupfunc[j], &key->partsupfunc[j],
fcinfo->flinfo->fn_mcxt); fcinfo->flinfo->fn_mcxt);
} }
} }
else else
{ {
...@@ -2885,6 +2888,7 @@ satisfies_hash_partition(PG_FUNCTION_ARGS) ...@@ -2885,6 +2888,7 @@ satisfies_hash_partition(PG_FUNCTION_ARGS)
&my_extra->variadic_typlen, &my_extra->variadic_typlen,
&my_extra->variadic_typbyval, &my_extra->variadic_typbyval,
&my_extra->variadic_typalign); &my_extra->variadic_typalign);
my_extra->partcollid[0] = key->partcollation[0];
/* check argument types */ /* check argument types */
for (j = 0; j < key->partnatts; ++j) for (j = 0; j < key->partnatts; ++j)
...@@ -2926,11 +2930,10 @@ satisfies_hash_partition(PG_FUNCTION_ARGS) ...@@ -2926,11 +2930,10 @@ satisfies_hash_partition(PG_FUNCTION_ARGS)
if (PG_ARGISNULL(argno)) if (PG_ARGISNULL(argno))
continue; continue;
Assert(OidIsValid(my_extra->partsupfunc[i].fn_oid)); hash = FunctionCall2Coll(&my_extra->partsupfunc[i],
my_extra->partcollid[i],
hash = FunctionCall2(&my_extra->partsupfunc[i], PG_GETARG_DATUM(argno),
PG_GETARG_DATUM(argno), seed);
seed);
/* Form a single 64-bit hash value */ /* Form a single 64-bit hash value */
rowHash = hash_combine64(rowHash, DatumGetUInt64(hash)); rowHash = hash_combine64(rowHash, DatumGetUInt64(hash));
...@@ -2965,11 +2968,10 @@ satisfies_hash_partition(PG_FUNCTION_ARGS) ...@@ -2965,11 +2968,10 @@ satisfies_hash_partition(PG_FUNCTION_ARGS)
if (isnull[i]) if (isnull[i])
continue; continue;
Assert(OidIsValid(my_extra->partsupfunc[0].fn_oid)); hash = FunctionCall2Coll(&my_extra->partsupfunc[0],
my_extra->partcollid[0],
hash = FunctionCall2(&my_extra->partsupfunc[0], datum[i],
datum[i], seed);
seed);
/* Form a single 64-bit hash value */ /* Form a single 64-bit hash value */
rowHash = hash_combine64(rowHash, DatumGetUInt64(hash)); rowHash = hash_combine64(rowHash, DatumGetUInt64(hash));
......
...@@ -99,6 +99,20 @@ ERROR: number of partitioning columns (2) does not match number of partition ke ...@@ -99,6 +99,20 @@ ERROR: number of partitioning columns (2) does not match number of partition ke
SELECT satisfies_hash_partition('mcinthash'::regclass, 4, 0, SELECT satisfies_hash_partition('mcinthash'::regclass, 4, 0,
variadic array[now(), now()]); variadic array[now(), now()]);
ERROR: column 1 of the partition key has type "integer", but supplied value is of type "timestamp with time zone" ERROR: column 1 of the partition key has type "integer", but supplied value is of type "timestamp with time zone"
-- check satisfies_hash_partition passes correct collation
create table text_hashp (a text) partition by hash (a);
create table text_hashp0 partition of text_hashp for values with (modulus 2, remainder 0);
create table text_hashp1 partition of text_hashp for values with (modulus 2, remainder 1);
-- The result here should always be true, because 'xxx' must belong to
-- one of the two defined partitions
select satisfies_hash_partition('text_hashp'::regclass, 2, 0, 'xxx'::text) OR
satisfies_hash_partition('text_hashp'::regclass, 2, 1, 'xxx'::text) AS satisfies;
satisfies
-----------
t
(1 row)
-- cleanup -- cleanup
DROP TABLE mchash; DROP TABLE mchash;
DROP TABLE mcinthash; DROP TABLE mcinthash;
DROP TABLE text_hashp;
...@@ -75,6 +75,16 @@ SELECT satisfies_hash_partition('mcinthash'::regclass, 4, 0, ...@@ -75,6 +75,16 @@ SELECT satisfies_hash_partition('mcinthash'::regclass, 4, 0,
SELECT satisfies_hash_partition('mcinthash'::regclass, 4, 0, SELECT satisfies_hash_partition('mcinthash'::regclass, 4, 0,
variadic array[now(), now()]); variadic array[now(), now()]);
-- check satisfies_hash_partition passes correct collation
create table text_hashp (a text) partition by hash (a);
create table text_hashp0 partition of text_hashp for values with (modulus 2, remainder 0);
create table text_hashp1 partition of text_hashp for values with (modulus 2, remainder 1);
-- The result here should always be true, because 'xxx' must belong to
-- one of the two defined partitions
select satisfies_hash_partition('text_hashp'::regclass, 2, 0, 'xxx'::text) OR
satisfies_hash_partition('text_hashp'::regclass, 2, 1, 'xxx'::text) AS satisfies;
-- cleanup -- cleanup
DROP TABLE mchash; DROP TABLE mchash;
DROP TABLE mcinthash; DROP TABLE mcinthash;
DROP TABLE text_hashp;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment