(2018/01/29 9:50), Amit Langote wrote:
On 2018/01/26 21:31, Etsuro Fujita wrote:
Attached is a modified
version of the patch.  What do you think about that?  Please let me know.
If that is okay, I'll mark this as Ready for Committer.

That looks good, thanks.

Cool! One thing I noticed to revise the patch a bit further is to add an assertion to make_partition_op_expr that the number of the right-hand inputs to generate an operator expression from for list-partitioning should be >=1; in that case we call that function if there is at least one non-null partition value as the right-hand input, so that should be asserted successfully there. I think the assertion is a good thing, so I modified the patch. Updated patch attached. Because I made no changes other than that, I'll make this as Ready for Committer.

Best regards,
Etsuro Fujita
*** 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;

Reply via email to