*** a/src/backend/catalog/partition.c --- b/src/backend/catalog/partition.c *************** *** 1625,1642 **** make_partition_op_expr(PartitionKey key, int keynum, { case PARTITION_STRATEGY_LIST: { ! ScalarArrayOpExpr *saopexpr; ! /* Build leftop = ANY (rightop) */ ! saopexpr = makeNode(ScalarArrayOpExpr); ! saopexpr->opno = operoid; ! saopexpr->opfuncid = get_opcode(operoid); ! saopexpr->useOr = true; ! saopexpr->inputcollid = key->partcollation[keynum]; ! saopexpr->args = list_make2(arg1, arg2); ! saopexpr->location = -1; ! result = (Expr *) saopexpr; break; } --- 1625,1684 ---- { case PARTITION_STRATEGY_LIST: { ! List *elems = (List *) arg2; ! int nelems = list_length(elems); ! Assert(nelems >= 1); ! Assert(keynum == 0); ! if (nelems > 1 && ! !type_is_array(key->parttypid[keynum])) ! { ! ArrayExpr *arrexpr; ! ScalarArrayOpExpr *saopexpr; ! ! /* Construct an ArrayExpr for the right-hand inputs */ ! arrexpr = makeNode(ArrayExpr); ! arrexpr->array_typeid = ! get_array_type(key->parttypid[keynum]); ! arrexpr->array_collid = key->parttypcoll[keynum]; ! arrexpr->element_typeid = key->parttypid[keynum]; ! arrexpr->elements = elems; ! arrexpr->multidims = false; ! arrexpr->location = -1; ! ! /* Build leftop = ANY (rightop) */ ! saopexpr = makeNode(ScalarArrayOpExpr); ! saopexpr->opno = operoid; ! saopexpr->opfuncid = get_opcode(operoid); ! saopexpr->useOr = true; ! saopexpr->inputcollid = key->partcollation[keynum]; ! saopexpr->args = list_make2(arg1, arrexpr); ! saopexpr->location = -1; ! ! result = (Expr *) saopexpr; ! } ! else ! { ! List *elemops = NIL; ! ListCell *lc; ! ! foreach (lc, elems) ! { ! Expr *elem = lfirst(lc), ! *elemop; ! ! elemop = make_opclause(operoid, ! BOOLOID, ! false, ! arg1, elem, ! InvalidOid, ! key->partcollation[keynum]); ! elemops = lappend(elemops, elemop); ! } ! ! result = nelems > 1 ? makeBoolExpr(OR_EXPR, elemops, -1) : linitial(elemops); ! } break; } *************** *** 1758,1768 **** get_qual_for_list(Relation parent, PartitionBoundSpec *spec) PartitionKey key = RelationGetPartitionKey(parent); List *result; Expr *keyCol; - ArrayExpr *arr; Expr *opexpr; NullTest *nulltest; ListCell *cell; ! List *arrelems = NIL; bool list_has_null = false; /* --- 1800,1809 ---- PartitionKey key = RelationGetPartitionKey(parent); List *result; Expr *keyCol; Expr *opexpr; NullTest *nulltest; ListCell *cell; ! List *elems = NIL; bool list_has_null = false; /* *************** *** 1828,1834 **** get_qual_for_list(Relation parent, PartitionBoundSpec *spec) false, /* isnull */ key->parttypbyval[0]); ! arrelems = lappend(arrelems, val); } } else --- 1869,1875 ---- false, /* isnull */ key->parttypbyval[0]); ! elems = lappend(elems, val); } } else *************** *** 1843,1872 **** get_qual_for_list(Relation parent, PartitionBoundSpec *spec) if (val->constisnull) list_has_null = true; else ! arrelems = lappend(arrelems, copyObject(val)); } } ! if (arrelems) { ! /* Construct an ArrayExpr for the non-null partition values */ ! arr = makeNode(ArrayExpr); ! arr->array_typeid = !type_is_array(key->parttypid[0]) ! ? get_array_type(key->parttypid[0]) ! : key->parttypid[0]; ! arr->array_collid = key->parttypcoll[0]; ! arr->element_typeid = key->parttypid[0]; ! arr->elements = arrelems; ! arr->multidims = false; ! arr->location = -1; ! ! /* Generate the main expression, i.e., keyCol = ANY (arr) */ opexpr = make_partition_op_expr(key, 0, BTEqualStrategyNumber, ! keyCol, (Expr *) arr); } else { ! /* If there are no partition values, we don't need an = ANY expr */ opexpr = NULL; } --- 1884,1908 ---- if (val->constisnull) list_has_null = true; else ! elems = lappend(elems, copyObject(val)); } } ! if (elems) { ! /* ! * Generate the operator expression from the non-null partition ! * values. ! */ opexpr = make_partition_op_expr(key, 0, BTEqualStrategyNumber, ! keyCol, (Expr *) elems); } else { ! /* ! * If there are no partition values, we don't need an operator ! * expression. ! */ opexpr = NULL; } *** a/src/test/regress/expected/create_table.out --- b/src/test/regress/expected/create_table.out *************** *** 737,743 **** CREATE TABLE part_c_1_10 PARTITION OF part_c FOR VALUES FROM (1) TO (10); a | text | | | | extended | | b | integer | | not null | 1 | plain | | Partition of: parted FOR VALUES IN ('b') ! Partition constraint: ((a IS NOT NULL) AND (a = ANY (ARRAY['b'::text]))) Check constraints: "check_a" CHECK (length(a) > 0) "part_b_b_check" CHECK (b >= 0) --- 737,743 ---- a | text | | | | extended | | b | integer | | not null | 1 | plain | | Partition of: parted FOR VALUES IN ('b') ! Partition constraint: ((a IS NOT NULL) AND (a = 'b'::text)) Check constraints: "check_a" CHECK (length(a) > 0) "part_b_b_check" CHECK (b >= 0) *************** *** 750,756 **** Check constraints: a | text | | | | extended | | b | integer | | not null | 0 | plain | | Partition of: parted FOR VALUES IN ('c') ! Partition constraint: ((a IS NOT NULL) AND (a = ANY (ARRAY['c'::text]))) Partition key: RANGE (b) Check constraints: "check_a" CHECK (length(a) > 0) --- 750,756 ---- a | text | | | | extended | | b | integer | | not null | 0 | plain | | Partition of: parted FOR VALUES IN ('c') ! Partition constraint: ((a IS NOT NULL) AND (a = 'c'::text)) Partition key: RANGE (b) Check constraints: "check_a" CHECK (length(a) > 0) *************** *** 764,770 **** Partitions: part_c_1_10 FOR VALUES FROM (1) TO (10) a | text | | | | extended | | b | integer | | not null | 0 | plain | | Partition of: part_c FOR VALUES FROM (1) TO (10) ! Partition constraint: ((a IS NOT NULL) AND (a = ANY (ARRAY['c'::text])) AND (b IS NOT NULL) AND (b >= 1) AND (b < 10)) Check constraints: "check_a" CHECK (length(a) > 0) --- 764,770 ---- a | text | | | | extended | | b | integer | | not null | 0 | plain | | Partition of: part_c FOR VALUES FROM (1) TO (10) ! Partition constraint: ((a IS NOT NULL) AND (a = 'c'::text) AND (b IS NOT NULL) AND (b >= 1) AND (b < 10)) Check constraints: "check_a" CHECK (length(a) > 0) *************** *** 863,865 **** Partition key: LIST (a) --- 863,877 ---- Number of partitions: 0 DROP TABLE parted_col_comment; + -- list partitioning on array type column + CREATE TABLE arrlp (a int[]) PARTITION BY LIST (a); + CREATE TABLE arrlp12 PARTITION OF arrlp FOR VALUES IN ('{1}', '{2}'); + \d+ arrlp12 + Table "public.arrlp12" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description + --------+-----------+-----------+----------+---------+----------+--------------+------------- + 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[]))) + + DROP TABLE arrlp; *** a/src/test/regress/expected/foreign_data.out --- b/src/test/regress/expected/foreign_data.out *************** *** 1863,1869 **** Partitions: pt2_1 FOR VALUES IN (1) c2 | text | | | | | extended | | c3 | date | | | | | plain | | Partition of: pt2 FOR VALUES IN (1) ! Partition constraint: ((c1 IS NOT NULL) AND (c1 = ANY (ARRAY[1]))) Server: s0 FDW options: (delimiter ',', quote '"', "be quoted" 'value') --- 1863,1869 ---- c2 | text | | | | | extended | | c3 | date | | | | | plain | | Partition of: pt2 FOR VALUES IN (1) ! Partition constraint: ((c1 IS NOT NULL) AND (c1 = 1)) Server: s0 FDW options: (delimiter ',', quote '"', "be quoted" 'value') *************** *** 1935,1941 **** Partitions: pt2_1 FOR VALUES IN (1) c2 | text | | | | | extended | | c3 | date | | | | | plain | | Partition of: pt2 FOR VALUES IN (1) ! Partition constraint: ((c1 IS NOT NULL) AND (c1 = ANY (ARRAY[1]))) Server: s0 FDW options: (delimiter ',', quote '"', "be quoted" 'value') --- 1935,1941 ---- c2 | text | | | | | extended | | c3 | date | | | | | plain | | Partition of: pt2 FOR VALUES IN (1) ! Partition constraint: ((c1 IS NOT NULL) AND (c1 = 1)) Server: s0 FDW options: (delimiter ',', quote '"', "be quoted" 'value') *************** *** 1963,1969 **** Partitions: pt2_1 FOR VALUES IN (1) c2 | text | | | | | extended | | c3 | date | | not null | | | plain | | Partition of: pt2 FOR VALUES IN (1) ! Partition constraint: ((c1 IS NOT NULL) AND (c1 = ANY (ARRAY[1]))) Check constraints: "p21chk" CHECK (c2 <> ''::text) Server: s0 --- 1963,1969 ---- c2 | text | | | | | extended | | c3 | date | | not null | | | plain | | Partition of: pt2 FOR VALUES IN (1) ! Partition constraint: ((c1 IS NOT NULL) AND (c1 = 1)) Check constraints: "p21chk" CHECK (c2 <> ''::text) Server: s0 *** a/src/test/regress/expected/partition_prune.out --- b/src/test/regress/expected/partition_prune.out *************** *** 1014,1036 **** explain (costs off) select * from boolpart where a = false; Append -> Seq Scan on boolpart_f Filter: (NOT a) - -> Seq Scan on boolpart_t - Filter: (NOT a) -> Seq Scan on boolpart_default Filter: (NOT a) ! (7 rows) explain (costs off) select * from boolpart where not a = false; QUERY PLAN ------------------------------------ Append - -> Seq Scan on boolpart_f - Filter: a -> Seq Scan on boolpart_t Filter: a -> Seq Scan on boolpart_default Filter: a ! (7 rows) explain (costs off) select * from boolpart where a is true or a is not true; QUERY PLAN --- 1014,1032 ---- Append -> Seq Scan on boolpart_f Filter: (NOT a) -> Seq Scan on boolpart_default Filter: (NOT a) ! (5 rows) explain (costs off) select * from boolpart where not a = false; QUERY PLAN ------------------------------------ Append -> Seq Scan on boolpart_t Filter: a -> Seq Scan on boolpart_default Filter: a ! (5 rows) explain (costs off) select * from boolpart where a is true or a is not true; QUERY PLAN *** a/src/test/regress/sql/create_table.sql --- b/src/test/regress/sql/create_table.sql *************** *** 707,709 **** COMMENT ON COLUMN parted_col_comment.a IS 'Partition key'; --- 707,715 ---- SELECT obj_description('parted_col_comment'::regclass); \d+ parted_col_comment DROP TABLE parted_col_comment; + + -- list partitioning on array type column + CREATE TABLE arrlp (a int[]) PARTITION BY LIST (a); + CREATE TABLE arrlp12 PARTITION OF arrlp FOR VALUES IN ('{1}', '{2}'); + \d+ arrlp12 + DROP TABLE arrlp;