From b0ebef9526a2abb162e877bc3b73d8194ffb1d2f Mon Sep 17 00:00:00 2001 From: amit Date: Fri, 8 Dec 2017 19:09:31 +0900 Subject: [PATCH v3] In get_partition_operator(), avoid RelabelType in some cases We never have pg_am catalog entries with "real" array, enum, record, range types as leftop and rightop types. Instead, operators manipulating such types have entries with "pseudo-types" listed as leftop and rightop types. For example, for enums, all operator entries are marked with anyenum as their leftop and rightop types. So, if we pass "real" type OIDs to get_opfamily_member(), we get back an InvalidOid for the aforementioned type categories. We'd normally ask the caller of get_partition_operator to add a RelabelType in such case. But we don't need to in these cases, as the rest of the system doesn't. This fixes the issue that the constraint exclusion code would reject matching partition key quals with restrictions due to these extraneous RelabelType nodes surrounding partition key expressions generated by partition.c. Also, ruleutils.c can resolve the operator names properly when deparsing an internally generated partition qual expressions. --- src/backend/catalog/partition.c | 12 ++++++- src/test/regress/expected/create_table.out | 2 +- src/test/regress/expected/partition_prune.out | 45 +++++++++++++++++++++++++++ src/test/regress/sql/partition_prune.sql | 18 +++++++++++ 4 files changed, 75 insertions(+), 2 deletions(-) diff --git a/src/backend/catalog/partition.c b/src/backend/catalog/partition.c index fcf7655553..cf71ba174e 100644 --- a/src/backend/catalog/partition.c +++ b/src/backend/catalog/partition.c @@ -1605,7 +1605,17 @@ get_partition_operator(PartitionKey key, int col, StrategyNumber strategy, elog(ERROR, "missing operator %d(%u,%u) in opfamily %u", strategy, key->partopcintype[col], key->partopcintype[col], key->partopfamily[col]); - *need_relabel = true; + + /* + * For certain type categories, there don't exist pg_amop entries with + * the given type OID as the operator's left and right operand type. + * Instead, the entries have corresponding pseudo-types listed as the + * left and right operand type; for example, anyenum for an enum type. + * For such cases, it's not necessary to add the RelabelType node, + * because other parts of the sytem won't add one either. + */ + if (get_typtype(key->partopcintype[col]) != TYPTYPE_PSEUDO) + *need_relabel = true; } else *need_relabel = false; diff --git a/src/test/regress/expected/create_table.out b/src/test/regress/expected/create_table.out index 39a963888d..7764da3152 100644 --- a/src/test/regress/expected/create_table.out +++ b/src/test/regress/expected/create_table.out @@ -880,6 +880,6 @@ 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; diff --git a/src/test/regress/expected/partition_prune.out b/src/test/regress/expected/partition_prune.out index 348719bd62..cf25c8ec86 100644 --- a/src/test/regress/expected/partition_prune.out +++ b/src/test/regress/expected/partition_prune.out @@ -1088,4 +1088,49 @@ explain (costs off) select * from boolpart where a is not unknown; Filter: (a IS NOT UNKNOWN) (7 rows) +-- array type list partition key +create table arrpart (a int[]) partition by list (a); +create table arrpart1 partition of arrpart for values in ('{1}'); +create table arrpart2 partition of arrpart for values in ('{2, 3}', '{4, 5}'); +explain (costs off) select * from arrpart where a = '{1}'; + QUERY PLAN +---------------------------------------- + Append + -> Seq Scan on arrpart1 + Filter: (a = '{1}'::integer[]) +(3 rows) + +explain (costs off) select * from arrpart where a = '{1, 2}'; + QUERY PLAN +-------------------------- + Result + One-Time Filter: false +(2 rows) + +explain (costs off) select * from arrpart where a in ('{4, 5}', '{1}'); + QUERY PLAN +---------------------------------------------------------------------- + Append + -> Seq Scan on arrpart1 + Filter: ((a = '{4,5}'::integer[]) OR (a = '{1}'::integer[])) + -> Seq Scan on arrpart2 + Filter: ((a = '{4,5}'::integer[]) OR (a = '{1}'::integer[])) +(5 rows) + +drop table arrpart; +-- enum type list partition key +create type colors as enum ('green', 'blue'); +create table enumpart (a colors) partition by list (a); +create table enumpart_green partition of enumpart for values in ('green'); +create table enumpart_blue partition of enumpart for values in ('blue'); +explain (costs off) select * from enumpart where a = 'blue'; + QUERY PLAN +-------------------------------------- + Append + -> Seq Scan on enumpart_blue + Filter: (a = 'blue'::colors) +(3 rows) + +drop table enumpart; +drop type colors; drop table lp, coll_pruning, rlp, mc3p, mc2p, boolpart; diff --git a/src/test/regress/sql/partition_prune.sql b/src/test/regress/sql/partition_prune.sql index 514f8e5ce1..abe1b56c80 100644 --- a/src/test/regress/sql/partition_prune.sql +++ b/src/test/regress/sql/partition_prune.sql @@ -152,4 +152,22 @@ explain (costs off) select * from boolpart where a is not true and a is not fals explain (costs off) select * from boolpart where a is unknown; explain (costs off) select * from boolpart where a is not unknown; +-- array type list partition key +create table arrpart (a int[]) partition by list (a); +create table arrpart1 partition of arrpart for values in ('{1}'); +create table arrpart2 partition of arrpart for values in ('{2, 3}', '{4, 5}'); +explain (costs off) select * from arrpart where a = '{1}'; +explain (costs off) select * from arrpart where a = '{1, 2}'; +explain (costs off) select * from arrpart where a in ('{4, 5}', '{1}'); +drop table arrpart; + +-- enum type list partition key +create type colors as enum ('green', 'blue'); +create table enumpart (a colors) partition by list (a); +create table enumpart_green partition of enumpart for values in ('green'); +create table enumpart_blue partition of enumpart for values in ('blue'); +explain (costs off) select * from enumpart where a = 'blue'; +drop table enumpart; +drop type colors; + drop table lp, coll_pruning, rlp, mc3p, mc2p, boolpart; -- 2.11.0