From 9f0dff4e6f3c7e8204a73ef0734e38056de08571 Mon Sep 17 00:00:00 2001 From: amit Date: Tue, 8 May 2018 14:31:37 +0900 Subject: [PATCH v1] Fix how get_partition_operator looks up the operator Instead of looking up using the underlying partition key's type as the operator's lefttype and righttype, use the partition operator class declared input type, which works reliably even in the cases where pseudo-types are involved. Also, make its decision whether a RelableType is needed depend on a different criteria than what's currently there. That is, only add a RelabelType if the partition key's type is different from the selected operator's input types. --- src/backend/catalog/partition.c | 49 +++++++++++++----------------- src/test/regress/expected/create_table.out | 2 +- 2 files changed, 22 insertions(+), 29 deletions(-) diff --git a/src/backend/catalog/partition.c b/src/backend/catalog/partition.c index 17704f36b9..5603a5d992 100644 --- a/src/backend/catalog/partition.c +++ b/src/backend/catalog/partition.c @@ -1176,40 +1176,33 @@ get_partition_operator(PartitionKey key, int col, StrategyNumber strategy, Oid operoid; /* - * First check if there exists an operator of the given strategy, with - * this column's type as both its lefttype and righttype, in the - * partitioning operator family specified for the column. + * Get the operator in the partitioning operator family using the operator + * class declared input type as both its lefttype and righttype. */ operoid = get_opfamily_member(key->partopfamily[col], - key->parttypid[col], - key->parttypid[col], + key->partopcintype[col], + key->partopcintype[col], strategy); + if (!OidIsValid(operoid)) + elog(ERROR, "missing operator %d(%u,%u) in partition opfamily %u", + strategy, key->partopcintype[col], key->partopcintype[col], + key->partopfamily[col]); /* - * If one doesn't exist, we must resort to using an operator in the same - * operator family but with the operator class declared input type. It is - * OK to do so, because the column's type is known to be binary-coercible - * with the operator class input type (otherwise, the operator class in - * question would not have been accepted as the partitioning operator - * class). We must however inform the caller to wrap the non-Const - * expression with a RelabelType node to denote the implicit coercion. It - * ensures that the resulting expression structurally matches similarly - * processed expressions within the optimizer. + * If the partition key column is not of the same type as what the + * operator expects, we'll need to tell the caller to wrap the non-Const + * expression with a RelableType node in most cases, because that's what + * the parser would do for similar expressions (such as WHERE clauses + * involving this column and operator.) The intention is to make the + * expression that we generate here structurally match with expression + * generated elsewhere. We don't need the RelableType node for certain + * types though, because parse_coerce.c won't emit one either. */ - if (!OidIsValid(operoid)) - { - operoid = get_opfamily_member(key->partopfamily[col], - key->partopcintype[col], - key->partopcintype[col], - strategy); - if (!OidIsValid(operoid)) - elog(ERROR, "missing operator %d(%u,%u) in opfamily %u", - strategy, key->partopcintype[col], key->partopcintype[col], - key->partopfamily[col]); - *need_relabel = true; - } - else - *need_relabel = false; + *need_relabel = (key->parttypid[col] != key->partopcintype[col] && + !(key->partopcintype[col] == ANYARRAYOID || + key->partopcintype[col] == ANYENUMOID || + key->partopcintype[col] == ANYRANGEOID || + key->partopcintype[col] == RECORDOID)); return operoid; } diff --git a/src/test/regress/expected/create_table.out b/src/test/regress/expected/create_table.out index 68dda4c0db..1caa3afbbf 100644 --- a/src/test/regress/expected/create_table.out +++ b/src/test/regress/expected/create_table.out @@ -808,7 +808,7 @@ CREATE TABLE arrlp12 PARTITION OF arrlp FOR VALUES IN ('{1}', '{2}'); --------+-----------+-----------+----------+---------+----------+--------------+------------- a | integer[] | | | | extended | | Partition of: arrlp FOR VALUES IN ('{1}', '{2}') -Partition constraint: ((a IS NOT NULL) AND (((a)::anyarray OPERATOR(pg_catalog.=) '{1}'::integer[]) OR ((a)::anyarray OPERATOR(pg_catalog.=) '{2}'::integer[]))) +Partition constraint: ((a IS NOT NULL) AND ((a = '{1}'::integer[]) OR (a = '{2}'::integer[]))) DROP TABLE arrlp; -- partition on boolean column -- 2.11.0