Fujita-san,

Thanks for the review.

On 2018/01/25 21:17, Etsuro Fujita wrote:
> Thanks for the updated patch!  Some minor comments:
> 
> +                   /*
> +                    * Construct an ArrayExpr for the non-null partition
> +                    * values
> +                    */
> +                   arrexpr = makeNode(ArrayExpr);
> +                   arrexpr->array_typeid =
> +                                   !type_is_array(key->parttypid[0])
> +                                       ? get_array_type(key->parttypid[0])
> +                                       : key->parttypid[0];
> 
> We test the type_is_array() above in this bit, so I don't think we need to
> test that again here.

Ah, you're right.  Fixed.

> +                   arrexpr->array_collid = key->parttypcoll[0];
> +                   arrexpr->element_typeid = key->parttypid[0];
> 
> We can assume that keynum=0 here, so it would be okay to specify zero as
> the offset.  But ISTM that that makes code a bit less readable, so I'd
> vote for using keynum as the offset and maybe adding an assertion that
> keynum should be zero, somewhere in the PARTITION_STRATEGY_LIST block.

Agreed, done.

> 
> * Both comments in the following in get_qual_for_list needs to be updated,
> because the expression made there isn't necessarily = ANY anymore.
> 
>     if (elems)
>     {
>         /* Generate the main expression, i.e., keyCol = ANY (arr) */
>         opexpr = make_partition_op_expr(key, 0, BTEqualStrategyNumber,
>                                         keyCol, (Expr *) elems);
>     }
>     else
>     {
>         /* If there are no partition values, we don't need an = ANY expr */
>         opexpr = NULL;
>     }

Fixed those.

Attached updated patch.  Thanks again.

Regards,
Amit
From 358b7c0fbbc646939b43b94405aeca96e56ccb9b Mon Sep 17 00:00:00 2001
From: amit <amitlangot...@gmail.com>
Date: Fri, 8 Dec 2017 19:00:46 +0900
Subject: [PATCH v3] Change how list partition constraint is emitted

In its current form (key = ANY (<array-of-values>)), a list partition
constraint expression is not always accepted by the backend's parser.
---
 src/backend/catalog/partition.c               | 102 ++++++++++++++++++--------
 src/test/regress/expected/create_table.out    |  18 ++++-
 src/test/regress/expected/foreign_data.out    |   6 +-
 src/test/regress/expected/partition_prune.out |   8 +-
 src/test/regress/sql/create_table.sql         |   6 ++
 5 files changed, 97 insertions(+), 43 deletions(-)

diff --git a/src/backend/catalog/partition.c b/src/backend/catalog/partition.c
index 8adc4ee977..c82a52fc1b 100644
--- a/src/backend/catalog/partition.c
+++ b/src/backend/catalog/partition.c
@@ -1625,18 +1625,67 @@ 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;
+                               ListCell   *lc;
+                               List   *elems = (List *) arg2,
+                                          *elemops = NIL;
+
+                               Assert(keynum == 0);
+                               if (type_is_array(key->parttypid[keynum]))
+                               {
+                                       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 = list_length(elemops) > 1
+                                                               ? 
makeBoolExpr(OR_EXPR, elemops, -1)
+                                                               : 
linitial(elemops);
+                               }
+                               else if (list_length(elems) > 1)
+                               {
+                                       ArrayExpr  *arrexpr;
+                                       ScalarArrayOpExpr *saopexpr;
+
+                                       /*
+                                        * Construct an ArrayExpr for the 
non-null partition
+                                        * values
+                                        */
+                                       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
+                                       result = make_opclause(operoid,
+                                                                               
   BOOLOID,
+                                                                               
   false,
+                                                                               
   arg1, linitial(elems),
+                                                                               
   InvalidOid,
+                                                                               
   key->partcollation[keynum]);
                                break;
                        }
 
@@ -1758,11 +1807,10 @@ 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;
+       List       *elems = NIL;
        bool            list_has_null = false;
 
        /*
@@ -1828,7 +1876,7 @@ get_qual_for_list(Relation parent, PartitionBoundSpec 
*spec)
                                                        false,  /* isnull */
                                                        key->parttypbyval[0]);
 
-                       arrelems = lappend(arrelems, val);
+                       elems = lappend(elems, val);
                }
        }
        else
@@ -1843,30 +1891,22 @@ get_qual_for_list(Relation parent, PartitionBoundSpec 
*spec)
                        if (val->constisnull)
                                list_has_null = true;
                        else
-                               arrelems = lappend(arrelems, copyObject(val));
+                               elems = lappend(elems, copyObject(val));
                }
        }
 
-       if (arrelems)
+       if (elems)
        {
-               /* 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) */
+               /* Generate the operator expression. */
                opexpr = make_partition_op_expr(key, 0, BTEqualStrategyNumber,
-                                                                               
keyCol, (Expr *) arr);
+                                                                               
keyCol, (Expr *) elems);
        }
        else
        {
-               /* If there are no partition values, we don't need an = ANY 
expr */
+               /*
+                * If there are no partition values, we don't need an operator
+                * expression.
+                */
                opexpr = NULL;
        }
 
diff --git a/src/test/regress/expected/create_table.out 
b/src/test/regress/expected/create_table.out
index 8e745402ae..14bcf7eaf3 100644
--- a/src/test/regress/expected/create_table.out
+++ b/src/test/regress/expected/create_table.out
@@ -737,7 +737,7 @@ 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])))
+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,7 +750,7 @@ 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 constraint: ((a IS NOT NULL) AND (a = 'c'::text))
 Partition key: RANGE (b)
 Check constraints:
     "check_a" CHECK (length(a) > 0)
@@ -764,7 +764,7 @@ 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))
+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,3 +863,15 @@ Partition key: LIST (a)
 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;
diff --git a/src/test/regress/expected/foreign_data.out 
b/src/test/regress/expected/foreign_data.out
index d2c184f2cf..6a1b278e5a 100644
--- a/src/test/regress/expected/foreign_data.out
+++ b/src/test/regress/expected/foreign_data.out
@@ -1863,7 +1863,7 @@ 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])))
+Partition constraint: ((c1 IS NOT NULL) AND (c1 = 1))
 Server: s0
 FDW options: (delimiter ',', quote '"', "be quoted" 'value')
 
@@ -1935,7 +1935,7 @@ 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])))
+Partition constraint: ((c1 IS NOT NULL) AND (c1 = 1))
 Server: s0
 FDW options: (delimiter ',', quote '"', "be quoted" 'value')
 
@@ -1963,7 +1963,7 @@ 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])))
+Partition constraint: ((c1 IS NOT NULL) AND (c1 = 1))
 Check constraints:
     "p21chk" CHECK (c2 <> ''::text)
 Server: s0
diff --git a/src/test/regress/expected/partition_prune.out 
b/src/test/regress/expected/partition_prune.out
index aabb0240a9..348719bd62 100644
--- a/src/test/regress/expected/partition_prune.out
+++ b/src/test/regress/expected/partition_prune.out
@@ -1014,23 +1014,19 @@ 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)
+(5 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)
+(5 rows)
 
 explain (costs off) select * from boolpart where a is true or a is not true;
                     QUERY PLAN                    
diff --git a/src/test/regress/sql/create_table.sql 
b/src/test/regress/sql/create_table.sql
index 8f9991ef18..f04d6c6114 100644
--- a/src/test/regress/sql/create_table.sql
+++ b/src/test/regress/sql/create_table.sql
@@ -707,3 +707,9 @@ COMMENT ON COLUMN parted_col_comment.a IS 'Partition key';
 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;
-- 
2.11.0

Reply via email to