Hi Stephen.

On 2018/01/26 10:16, Stephen Frost wrote:
> * Amit Langote (langote_amit...@lab.ntt.co.jp) wrote:
> Still compiles and passes regression tests, which is good.

Thanks for looking at this.

>>> I extended your test a bit to check whether partitions over booleans are 
>>> useful.
>>> Note specifically the 'explain' output, which does not seem to restrict the 
>>> scan
>>> to just the relevant partitions.  You could easily argue that this is 
>>> beyond the scope
>>> of your patch (and therefore not your problem), but I doubt it makes much 
>>> sense
>>> to have boolean partitions without planner support for skipping partitions 
>>> like is
>>> done for tables partitioned over other data types.
>>
>> Yeah.  Actually, I'm aware that the planner doesn't work this.  While
>> constraint exclusion (planner's current method of skipping partitions)
>> does not work with IS TRUE/FALSE/UNKNOWN clauses, the new partition
>> pruning patch [1] addresses that.  In fact, I started this thread prompted
>> by some discussion about Boolean partitions on that thread [2].
>>
>> That said, someone might argue that we should also fix constraint
>> exclusion (the current method of partition pruning) so that partition
>> skipping works correctly for Boolean partitions.
> 
> For my 2c, at least, I don't think we need to fix constraint exclusion
> to work for this case and hopefully we'll get the partition pruning
> patch in but I'm not sure that we really need to wait for that either.
> Worst case, we can simply document that the planner won't actually
> exclude boolean-based partitions in this release and then fix it in the
> future.

Yeah, I meant this just as a tiny syntax extension patch.

> Looking over this patch, it seems to be in pretty good shape to me
> except that I'm not sure why you went with the approach of naming the
> function 'NoCast'.  There's a number of other functions just above
> makeBoolAConst() that don't include a TypeCast and it seems like having
> makeBoolConst() and makeBoolConstCast() would be more in-line with the
> existing code (see makeStringConst() and makeStringConstCast() for
> example, but also makeIntConst(), makeFloatConst(), et al).  That would
> require updating the existing callers that really want a TypeCast result
> even though they're calling makeBoolAConst(), but that seems like a good
> improvement to be making.

Agreed, done.

> I could see an argument that we should have two patches (one to rename
> the existing function, another to add support for boolean) but that's
> really up to whatever committer picks this up.  For my 2c, I don't think
> it's really necessary to split it into two patches.

OK, I kept the function name change part with the main patch.

Attached updated patch.

Thanks,
Amit
>From 3ebd9387c4515cc5272e12e0138cd8035fedaaea Mon Sep 17 00:00:00 2001
From: amit <amitlangot...@gmail.com>
Date: Tue, 12 Dec 2017 10:33:11 +0900
Subject: [PATCH v3] Allow Boolean values in partition FOR VALUES clause

---
 doc/src/sgml/ref/create_table.sgml         |  6 +++---
 src/backend/parser/gram.y                  | 24 +++++++++++++++++++-----
 src/test/regress/expected/create_table.out | 14 ++++++++++++++
 src/test/regress/sql/create_table.sql      |  7 +++++++
 4 files changed, 43 insertions(+), 8 deletions(-)

diff --git a/doc/src/sgml/ref/create_table.sgml 
b/doc/src/sgml/ref/create_table.sgml
index a0c9a6d257..eaa79ae333 100644
--- a/doc/src/sgml/ref/create_table.sgml
+++ b/doc/src/sgml/ref/create_table.sgml
@@ -86,9 +86,9 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] 
TABLE [ IF NOT EXI
 
 <phrase>and <replaceable class="parameter">partition_bound_spec</replaceable> 
is:</phrase>
 
-IN ( { <replaceable class="parameter">numeric_literal</replaceable> | 
<replaceable class="parameter">string_literal</replaceable> | NULL } [, ...] ) |
-FROM ( { <replaceable class="parameter">numeric_literal</replaceable> | 
<replaceable class="parameter">string_literal</replaceable> | MINVALUE | 
MAXVALUE } [, ...] )
-  TO ( { <replaceable class="parameter">numeric_literal</replaceable> | 
<replaceable class="parameter">string_literal</replaceable> | MINVALUE | 
MAXVALUE } [, ...] ) |
+IN ( { <replaceable class="parameter">numeric_literal</replaceable> | 
<replaceable class="parameter">string_literal</replaceable> | TRUE | FALSE | 
NULL } [, ...] ) |
+FROM ( { <replaceable class="parameter">numeric_literal</replaceable> | 
<replaceable class="parameter">string_literal</replaceable> | TRUE | FALSE | 
MINVALUE | MAXVALUE } [, ...] )
+  TO ( { <replaceable class="parameter">numeric_literal</replaceable> | 
<replaceable class="parameter">string_literal</replaceable> | TRUE | FALSE | 
MINVALUE | MAXVALUE } [, ...] ) |
 WITH ( MODULUS <replaceable class="parameter">numeric_literal</replaceable>, 
REMAINDER <replaceable class="parameter">numeric_literal</replaceable> )
 
 <phrase><replaceable class="parameter">index_parameters</replaceable> in 
<literal>UNIQUE</literal>, <literal>PRIMARY KEY</literal>, and 
<literal>EXCLUDE</literal> constraints are:</phrase>
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 459a227e57..15b5c85a6e 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -152,6 +152,7 @@ static Node *makeFloatConst(char *str, int location);
 static Node *makeBitStringConst(char *str, int location);
 static Node *makeNullAConst(int location);
 static Node *makeAConst(Value *v, int location);
+static Node *makeBoolAConstCast(bool state, int location);
 static Node *makeBoolAConst(bool state, int location);
 static RoleSpec *makeRoleSpec(RoleSpecType type, int location);
 static void check_qualified_name(List *names, core_yyscan_t yyscanner);
@@ -2793,6 +2794,8 @@ partbound_datum:
                        Sconst                  { $$ = makeStringConst($1, @1); 
}
                        | NumericOnly   { $$ = makeAConst($1, @1); }
                        | NULL_P                { $$ = makeNullAConst(@1); }
+                       | TRUE_P                { $$ = makeBoolAConst(true, 
@1); }
+                       | FALSE_P               { $$ = makeBoolAConst(false, 
@1); }
                ;
 
 partbound_datum_list:
@@ -13826,7 +13829,7 @@ func_expr_common_subexpr:
                                {
                                        XmlExpr *x = (XmlExpr *)
                                                makeXmlExpr(IS_XMLPARSE, NULL, 
NIL,
-                                                                       
list_make2($4, makeBoolAConst($5, -1)),
+                                                                       
list_make2($4, makeBoolAConstCast($5, -1)),
                                                                        @1);
                                        x->xmloption = $3;
                                        $$ = (Node *)x;
@@ -14777,11 +14780,11 @@ AexprConst: Iconst
                                }
                        | TRUE_P
                                {
-                                       $$ = makeBoolAConst(true, @1);
+                                       $$ = makeBoolAConstCast(true, @1);
                                }
                        | FALSE_P
                                {
-                                       $$ = makeBoolAConst(false, @1);
+                                       $$ = makeBoolAConstCast(false, @1);
                                }
                        | NULL_P
                                {
@@ -15597,10 +15600,21 @@ makeAConst(Value *v, int location)
        return n;
 }
 
-/* makeBoolAConst()
+/* makeBoolAConstCast()
  * Create an A_Const string node and put it inside a boolean cast.
  */
 static Node *
+makeBoolAConstCast(bool state, int location)
+{
+       A_Const *n = (A_Const *) makeBoolAConst(state, location);
+
+       return makeTypeCast((Node *)n, SystemTypeName("bool"), -1);
+}
+
+/* makeBoolAConst()
+ * Create an A_Const string node containing valid bool type values.
+ */
+static Node *
 makeBoolAConst(bool state, int location)
 {
        A_Const *n = makeNode(A_Const);
@@ -15609,7 +15623,7 @@ makeBoolAConst(bool state, int location)
        n->val.val.str = (state ? "t" : "f");
        n->location = location;
 
-       return makeTypeCast((Node *)n, SystemTypeName("bool"), -1);
+       return (Node *) n;
 }
 
 /* makeRoleSpec
diff --git a/src/test/regress/expected/create_table.out 
b/src/test/regress/expected/create_table.out
index 8e745402ae..c541a652c4 100644
--- a/src/test/regress/expected/create_table.out
+++ b/src/test/regress/expected/create_table.out
@@ -863,3 +863,17 @@ Partition key: LIST (a)
 Number of partitions: 0
 
 DROP TABLE parted_col_comment;
+-- boolean partitions
+create table boolspart (a bool) partition by list (a);
+create table boolspart_t partition of boolspart for values in (true);
+create table boolspart_f partition of boolspart for values in (false);
+\d+ boolspart
+                                 Table "public.boolspart"
+ Column |  Type   | Collation | Nullable | Default | Storage | Stats target | 
Description 
+--------+---------+-----------+----------+---------+---------+--------------+-------------
+ a      | boolean |           |          |         | plain   |              | 
+Partition key: LIST (a)
+Partitions: boolspart_f FOR VALUES IN (false),
+            boolspart_t FOR VALUES IN (true)
+
+drop table boolspart;
diff --git a/src/test/regress/sql/create_table.sql 
b/src/test/regress/sql/create_table.sql
index 8f9991ef18..c71e9f938e 100644
--- a/src/test/regress/sql/create_table.sql
+++ b/src/test/regress/sql/create_table.sql
@@ -707,3 +707,10 @@ 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;
+
+-- boolean partitions
+create table boolspart (a bool) partition by list (a);
+create table boolspart_t partition of boolspart for values in (true);
+create table boolspart_f partition of boolspart for values in (false);
+\d+ boolspart
+drop table boolspart;
-- 
2.11.0

Reply via email to