This is an automated email from the ASF dual-hosted git repository.

maxyang pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/cloudberry.git

commit ebccd1f8806d6bedd6e4f127505b1e62f4a8789f
Author: David Kimura <[email protected]>
AuthorDate: Mon Apr 24 12:10:00 2023 -0700

    [ORCA] Support boolean static partition pruning  (#15348)
    
    After Postgres 12 merge into GPDB, GPDB absorbed the underlying Postgres
    partition implementation. In the process, ORCA lost static partition
    pruning on boolean partitioned tables. In order to support that feature,
    ORCA constraint framework needs to support boolean types as interval
    constraints for constraint contradiction.
    
    In SQL standard, boolean type includes NULL and UNKNOWN. Some special
    care was needed to handle UNKNOWN type as it relates to an interval
    constraint. Since it is unknown, it can be anywhere on the spectrum
    (-inf, inf), hence that is the range we assign it.
    
    In the process of supporting this feature, a related issue was
    discovered in upstream Postgres [1].
    
    This commit also enables partition pruning with general boolean compare.
    It is important to note that general comparison handles NULL different
    than boolean test. For example, this evaluates to TRUE:
    
        SELECT true IS NOT null;
    
    However, this evaluates NULL:
    
        SELECT true<>null;
    
    This has vastly different effects on static partition pruning. First
    step to enabling this general boolean compare is to create interval
    constraints from boolean scalar idents (see PciIntervalFromScalarIdent).
    Second step is to update the interval range to support domain of boolean
    types (see CConstraintInterval::PciUnbounded). In order to illustrate
    that issue, consider the following table:
    
        CREATE TABLE booltab (a bool) partition by list(a) (
          partition part_t values(true),
          partition part_f values(false),
          partition default def);
    
    The default partition constraint is defined in the catalog. And in ORCA
    world is represented as an expression like:
    
        +--CScalarBoolOp (EboolopNot)
           +--CScalarBoolOp (EboolopAnd)
              |--CScalarBoolOp (EboolopNot)
              |  +--CScalarNullTest
              |     +--CScalarIdent "a" (0)
              +--CScalarArrayCmp Any (=)
                 |--CScalarIdent "a" (0)
                 +--CScalarArray: {(0) (1)}
    
    If we track the constraint derivation at each level without adjusting
    the constraint interval for boolean, then the derivation looks like:
    
        +--CScalarBoolOp (EboolopNot)           {"a" (0), ranges: (-inf, 0) (0, 
1) (1, inf) [NULL] }
           +--CScalarBoolOp (EboolopAnd)        {"a" (0), ranges: [0, 0] [1, 1] 
}
              |--CScalarBoolOp (EboolopNot)     {"a" (0), ranges: (-inf, inf) }
              |  +--CScalarNullTest             {"a" (0), ranges: [NULL] }
              |     +--CScalarIdent "a" (0)
              +--CScalarArrayCmp Any (=)        {"a" (0), ranges: [0, 0] [1, 1] 
}
                 |--CScalarIdent "a" (0)
                 +--CScalarArray: {(0) (1)}
    
    When the predicate is a=false, then the constraint is:
    
        +--CScalarBoolOp (EboolopNot)           {"a" (0), ranges: (-inf, 1) (1, 
inf) }
           +--CScalarIdent "a" (1)              {"a" (0), ranges: [1, 1] [NULL] 
}
    
    The conjunction of table constraint:
    
        {"a" (0), ranges: (-inf, 0) (0, 1) (1, inf) [NULL] }
    
    And predicate constraint:
    
        {"a" (0), ranges: (-inf, 1) (1, inf) }
    
    Produces result constraint:
    
        {"a" (0), ranges: (-inf, 0) (1, inf) }
    
    The problem with that result constraint is that it is not considered a
    contradiction because there is a range, albeit outside the range of
    boolean [0,1]. As a result, the default partition is incorrectly not
    pruned.
    
    There are 2 different ways to solve this:
       1) Fix up contradiction detection to special case boolean intervals
       2) Fix up boolean interval to map to the (-inf, inf) domain space
    
    One problem with the 2nd approach is that other systems (e.g. direct
    dispatch) use the constraint system and rely on finite values (i.e. 0,
    1). That would mean fixing up those areas in the code as well to handle
    the full spectrum (-inf, inf) correctly.
    
    Instead, this commit implements the 1st approach. It also requires
    updating the EboolopNot operator to keep the domain [0, 1]. In this case
    the above default partition and predicate constraint derivation looks
    like:
    
        +--CScalarBoolOp (EboolopNot)           {"a" (0), ranges: [NULL] }
           +--CScalarBoolOp (EboolopAnd)        {"a" (0), ranges: [0, 0] [1, 1] 
}
              |--CScalarBoolOp (EboolopNot)     {"a" (0), ranges: [0, 0] [1, 1] 
}
              |  +--CScalarNullTest             {"a" (0), ranges: [NULL] }
              |     +--CScalarIdent "a" (0)
              +--CScalarArrayCmp Any (=)        {"a" (0), ranges: [0, 0] [1, 1] 
}
                 |--CScalarIdent "a" (0)
                 +--CScalarArray: {(0) (1)}
    
        +--CScalarBoolOp (EboolopNot)           {"a" (0), ranges: [0, 0] }
           +--CScalarIdent "a" (1)              {"a" (0), ranges: [1, 1] [NULL] 
}
    
    Then the conjunction of the two produces:
    
        {"a" (0), ranges: }
    
    And the table is correctly pruned.
    
    [1] 
https://www.postgresql.org/message-id/flat/CAHnPFjQ5qxs6J_p+g8=ww7gqvfn71_je+tygj0s7rdrci1u...@mail.gmail.com
---
 .../dxl/minidump/CTEMisAlignedProducerConsumer.mdp |  24 ++
 .../data/dxl/minidump/PartTbl-SPE-Boolean1.mdp     | 365 ++++++++++++++++
 .../data/dxl/minidump/PartTbl-SPE-Boolean2.mdp     | 461 ++++++++++++++++++++
 .../include/gpopt/base/CConstraintInterval.h       |   9 +
 .../gporca/libgpopt/include/gpopt/base/CUtils.h    |   3 +
 .../libgpopt/src/base/CConstraintInterval.cpp      | 162 ++++++-
 .../libgpopt/src/base/CDefaultComparator.cpp       |   1 +
 src/backend/gporca/libgpopt/src/base/CUtils.cpp    |   8 +
 src/backend/gporca/server/CMakeLists.txt           |   3 +
 .../gpopt/translate/CTranslatorExprToDXLTest.cpp   |  10 +-
 .../regress/expected/partition_prune_optimizer.out |  14 +-
 src/test/regress/expected/partition_pruning.out    | 480 +++++++++++++++++++++
 .../expected/partition_pruning_optimizer.out       | 470 ++++++++++++++++++++
 .../expected/qp_targeted_dispatch_optimizer.out    |   2 +-
 src/test/regress/sql/partition_pruning.sql         | 102 +++++
 15 files changed, 2095 insertions(+), 19 deletions(-)

diff --git 
a/src/backend/gporca/data/dxl/minidump/CTEMisAlignedProducerConsumer.mdp 
b/src/backend/gporca/data/dxl/minidump/CTEMisAlignedProducerConsumer.mdp
index c9542903b5..56c2fa14a6 100644
--- a/src/backend/gporca/data/dxl/minidump/CTEMisAlignedProducerConsumer.mdp
+++ b/src/backend/gporca/data/dxl/minidump/CTEMisAlignedProducerConsumer.mdp
@@ -148,6 +148,30 @@ SELECT 1 FROM (SELECT * FROM foo) t2 FULL JOIN (SELECT 1) 
t1 ON true;
       <dxl:ColumnStatistics Mdid="1.16385.1.0.4" Name="xmax" Width="4.000000" 
NullFreq="0.000000" NdvRemain="0.000000" FreqRemain="0.000000" 
ColStatsMissing="true"/>
       <dxl:ColumnStatistics Mdid="1.16385.1.0.7" Name="gp_segment_id" 
Width="4.000000" NullFreq="0.000000" NdvRemain="0.000000" FreqRemain="0.000000" 
ColStatsMissing="true"/>
       <dxl:ColumnStatistics Mdid="1.16385.1.0.6" Name="tableoid" 
Width="4.000000" NullFreq="0.000000" NdvRemain="0.000000" FreqRemain="0.000000" 
ColStatsMissing="true"/>
+      <dxl:GPDBScalarOp Mdid="0.1695.1.0" Name="&gt;=" ComparisonType="GEq" 
ReturnsNullOnNullInput="true" IsNDVPreserving="false">
+        <dxl:LeftType Mdid="0.16.1.0"/>
+        <dxl:RightType Mdid="0.16.1.0"/>
+        <dxl:ResultType Mdid="0.16.1.0"/>
+        <dxl:OpFunc Mdid="0.1692.1.0"/>
+        <dxl:Commutator Mdid="0.1694.1.0"/>
+        <dxl:InverseOp Mdid="0.58.1.0"/>
+        <dxl:Opfamilies>
+          <dxl:Opfamily Mdid="0.424.1.0"/>
+          <dxl:Opfamily Mdid="0.10002.1.0"/>
+        </dxl:Opfamilies>
+      </dxl:GPDBScalarOp>
+      <dxl:GPDBScalarOp Mdid="0.1694.1.0" Name="&lt;=" ComparisonType="LEq" 
ReturnsNullOnNullInput="true" IsNDVPreserving="false">
+        <dxl:LeftType Mdid="0.16.1.0"/>
+        <dxl:RightType Mdid="0.16.1.0"/>
+        <dxl:ResultType Mdid="0.16.1.0"/>
+        <dxl:OpFunc Mdid="0.1691.1.0"/>
+        <dxl:Commutator Mdid="0.1695.1.0"/>
+        <dxl:InverseOp Mdid="0.59.1.0"/>
+        <dxl:Opfamilies>
+          <dxl:Opfamily Mdid="0.424.1.0"/>
+          <dxl:Opfamily Mdid="0.10002.1.0"/>
+        </dxl:Opfamilies>
+      </dxl:GPDBScalarOp>
     </dxl:Metadata>
     <dxl:Query>
       <dxl:OutputColumns>
diff --git a/src/backend/gporca/data/dxl/minidump/PartTbl-SPE-Boolean1.mdp 
b/src/backend/gporca/data/dxl/minidump/PartTbl-SPE-Boolean1.mdp
new file mode 100644
index 0000000000..e7f02e3cae
--- /dev/null
+++ b/src/backend/gporca/data/dxl/minidump/PartTbl-SPE-Boolean1.mdp
@@ -0,0 +1,365 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<dxl:DXLMessage xmlns:dxl="http://greenplum.com/dxl/2010/12/";>
+  <dxl:Comment><![CDATA[
+    Objective: Perform static partition elimination (SPE) on a table 
partitioned
+    by a boolean column. In below setup containing 2 leaf tables and predicate
+    IS TRUE, only 1 table should be scanned.
+
+    CREATE TABLE boolpart(a int, b bool) PARTITION BY LIST(b) (
+        PARTITION l1 values(true), PARTITION l2 values(false));
+    INSERT INTO boolpart values (1,true);
+    INSERT INTO boolpart values (2, false);
+
+    EXPLAIN SELECT * FROM boolpart WHERE b IS TRUE;
+  ]]>
+  </dxl:Comment>
+  <dxl:Thread Id="0">
+    <dxl:OptimizerConfig>
+      <dxl:EnumeratorConfig Id="0" PlanSamples="0" CostThreshold="0"/>
+      <dxl:StatisticsConfig DampingFactorFilter="0.750000" 
DampingFactorJoin="0.000000" DampingFactorGroupBy="0.750000" 
MaxStatsBuckets="100"/>
+      <dxl:CTEConfig CTEInliningCutoff="0"/>
+      <dxl:WindowOids RowNumber="3100" Rank="3101"/>
+      <dxl:CostModelConfig CostModelType="1" SegmentsForCosting="3">
+        <dxl:CostParams>
+          <dxl:CostParam Name="NLJFactor" Value="1024.000000" 
LowerBound="1023.500000" UpperBound="1024.500000"/>
+        </dxl:CostParams>
+      </dxl:CostModelConfig>
+      <dxl:Hint JoinArityForAssociativityCommutativity="18" 
ArrayExpansionThreshold="20" JoinOrderDynamicProgThreshold="10" 
BroadcastThreshold="100000" EnforceConstraintsOnDML="false" 
PushGroupByBelowSetopThreshold="10" XformBindThreshold="0" SkewFactor="0"/>
+      <dxl:TraceFlags 
Value="102001,102002,102003,102043,102074,102120,102144,103001,103014,103022,103026,103027,103029,103033,103038,103040,104002,104003,104004,104005,105000,106000"/>
+    </dxl:OptimizerConfig>
+    <dxl:Metadata SystemIds="0.GPDB">
+      <dxl:Type Mdid="0.16.1.0" Name="bool" IsRedistributable="true" 
IsHashable="true" IsMergeJoinable="true" IsComposite="false" 
IsTextRelated="false" IsFixedLength="true" Length="1" PassByValue="true">
+        <dxl:DistrOpfamily Mdid="0.2222.1.0"/>
+        <dxl:LegacyDistrOpfamily Mdid="0.7124.1.0"/>
+        <dxl:EqualityOp Mdid="0.91.1.0"/>
+        <dxl:InequalityOp Mdid="0.85.1.0"/>
+        <dxl:LessThanOp Mdid="0.58.1.0"/>
+        <dxl:LessThanEqualsOp Mdid="0.1694.1.0"/>
+        <dxl:GreaterThanOp Mdid="0.59.1.0"/>
+        <dxl:GreaterThanEqualsOp Mdid="0.1695.1.0"/>
+        <dxl:ComparisonOp Mdid="0.1693.1.0"/>
+        <dxl:ArrayType Mdid="0.1000.1.0"/>
+        <dxl:MinAgg Mdid="0.0.0.0"/>
+        <dxl:MaxAgg Mdid="0.0.0.0"/>
+        <dxl:AvgAgg Mdid="0.0.0.0"/>
+        <dxl:SumAgg Mdid="0.0.0.0"/>
+        <dxl:CountAgg Mdid="0.2147.1.0"/>
+      </dxl:Type>
+      <dxl:Type Mdid="0.23.1.0" Name="int4" IsRedistributable="true" 
IsHashable="true" IsMergeJoinable="true" IsComposite="false" 
IsTextRelated="false" IsFixedLength="true" Length="4" PassByValue="true">
+        <dxl:DistrOpfamily Mdid="0.1977.1.0"/>
+        <dxl:LegacyDistrOpfamily Mdid="0.7100.1.0"/>
+        <dxl:EqualityOp Mdid="0.96.1.0"/>
+        <dxl:InequalityOp Mdid="0.518.1.0"/>
+        <dxl:LessThanOp Mdid="0.97.1.0"/>
+        <dxl:LessThanEqualsOp Mdid="0.523.1.0"/>
+        <dxl:GreaterThanOp Mdid="0.521.1.0"/>
+        <dxl:GreaterThanEqualsOp Mdid="0.525.1.0"/>
+        <dxl:ComparisonOp Mdid="0.351.1.0"/>
+        <dxl:ArrayType Mdid="0.1007.1.0"/>
+        <dxl:MinAgg Mdid="0.2132.1.0"/>
+        <dxl:MaxAgg Mdid="0.2116.1.0"/>
+        <dxl:AvgAgg Mdid="0.2101.1.0"/>
+        <dxl:SumAgg Mdid="0.2108.1.0"/>
+        <dxl:CountAgg Mdid="0.2147.1.0"/>
+      </dxl:Type>
+      <dxl:Relation Mdid="6.112430.1.0" Name="boolpart_1_prt_l2" 
IsTemporary="false" StorageType="Heap" DistributionPolicy="Hash" 
DistributionColumns="0" Keys="8,2">
+        <dxl:Columns>
+          <dxl:Column Name="a" Attno="1" Mdid="0.23.1.0" Nullable="true" 
ColWidth="4">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+          <dxl:Column Name="b" Attno="2" Mdid="0.16.1.0" Nullable="true" 
ColWidth="1">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+          <dxl:Column Name="ctid" Attno="-1" Mdid="0.27.1.0" Nullable="false" 
ColWidth="6">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+          <dxl:Column Name="xmin" Attno="-2" Mdid="0.28.1.0" Nullable="false" 
ColWidth="4">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+          <dxl:Column Name="cmin" Attno="-3" Mdid="0.29.1.0" Nullable="false" 
ColWidth="4">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+          <dxl:Column Name="xmax" Attno="-4" Mdid="0.28.1.0" Nullable="false" 
ColWidth="4">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+          <dxl:Column Name="cmax" Attno="-5" Mdid="0.29.1.0" Nullable="false" 
ColWidth="4">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+          <dxl:Column Name="tableoid" Attno="-6" Mdid="0.26.1.0" 
Nullable="false" ColWidth="4">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+          <dxl:Column Name="gp_segment_id" Attno="-7" Mdid="0.23.1.0" 
Nullable="false" ColWidth="4">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+        </dxl:Columns>
+        <dxl:IndexInfoList/>
+        <dxl:CheckConstraints/>
+        <dxl:DistrOpfamilies>
+          <dxl:DistrOpfamily Mdid="0.1977.1.0"/>
+        </dxl:DistrOpfamilies>
+        <dxl:PartConstraint>
+          <dxl:And>
+            <dxl:IsNotNull>
+              <dxl:Ident ColId="2" ColName="b" TypeMdid="0.16.1.0"/>
+            </dxl:IsNotNull>
+            <dxl:Comparison ComparisonOperator="=" OperatorMdid="0.91.1.0">
+              <dxl:Ident ColId="2" ColName="b" TypeMdid="0.16.1.0"/>
+              <dxl:ConstValue TypeMdid="0.16.1.0" Value="false"/>
+            </dxl:Comparison>
+          </dxl:And>
+        </dxl:PartConstraint>
+      </dxl:Relation>
+      <dxl:Type Mdid="0.26.1.0" Name="oid" IsRedistributable="true" 
IsHashable="true" IsMergeJoinable="true" IsComposite="false" 
IsTextRelated="false" IsFixedLength="true" Length="4" PassByValue="true">
+        <dxl:DistrOpfamily Mdid="0.1990.1.0"/>
+        <dxl:LegacyDistrOpfamily Mdid="0.7109.1.0"/>
+        <dxl:EqualityOp Mdid="0.607.1.0"/>
+        <dxl:InequalityOp Mdid="0.608.1.0"/>
+        <dxl:LessThanOp Mdid="0.609.1.0"/>
+        <dxl:LessThanEqualsOp Mdid="0.611.1.0"/>
+        <dxl:GreaterThanOp Mdid="0.610.1.0"/>
+        <dxl:GreaterThanEqualsOp Mdid="0.612.1.0"/>
+        <dxl:ComparisonOp Mdid="0.356.1.0"/>
+        <dxl:ArrayType Mdid="0.1028.1.0"/>
+        <dxl:MinAgg Mdid="0.2134.1.0"/>
+        <dxl:MaxAgg Mdid="0.2118.1.0"/>
+        <dxl:AvgAgg Mdid="0.0.0.0"/>
+        <dxl:SumAgg Mdid="0.0.0.0"/>
+        <dxl:CountAgg Mdid="0.2147.1.0"/>
+      </dxl:Type>
+      <dxl:Type Mdid="0.27.1.0" Name="tid" IsRedistributable="true" 
IsHashable="true" IsMergeJoinable="true" IsComposite="false" 
IsTextRelated="false" IsFixedLength="true" Length="6" PassByValue="false">
+        <dxl:DistrOpfamily Mdid="0.2227.1.0"/>
+        <dxl:LegacyDistrOpfamily Mdid="0.7110.1.0"/>
+        <dxl:EqualityOp Mdid="0.387.1.0"/>
+        <dxl:InequalityOp Mdid="0.402.1.0"/>
+        <dxl:LessThanOp Mdid="0.2799.1.0"/>
+        <dxl:LessThanEqualsOp Mdid="0.2801.1.0"/>
+        <dxl:GreaterThanOp Mdid="0.2800.1.0"/>
+        <dxl:GreaterThanEqualsOp Mdid="0.2802.1.0"/>
+        <dxl:ComparisonOp Mdid="0.2794.1.0"/>
+        <dxl:ArrayType Mdid="0.1010.1.0"/>
+        <dxl:MinAgg Mdid="0.2798.1.0"/>
+        <dxl:MaxAgg Mdid="0.2797.1.0"/>
+        <dxl:AvgAgg Mdid="0.0.0.0"/>
+        <dxl:SumAgg Mdid="0.0.0.0"/>
+        <dxl:CountAgg Mdid="0.2147.1.0"/>
+      </dxl:Type>
+      <dxl:RelationStatistics Mdid="2.112424.1.0" Name="boolpart" 
Rows="0.000000" RelPages="0" RelAllVisible="0" EmptyRelation="true"/>
+      <dxl:Type Mdid="0.29.1.0" Name="cid" IsRedistributable="true" 
IsHashable="true" IsMergeJoinable="false" IsComposite="false" 
IsTextRelated="false" IsFixedLength="true" Length="4" PassByValue="true">
+        <dxl:DistrOpfamily Mdid="0.2226.1.0"/>
+        <dxl:EqualityOp Mdid="0.385.1.0"/>
+        <dxl:InequalityOp Mdid="0.0.0.0"/>
+        <dxl:LessThanOp Mdid="0.0.0.0"/>
+        <dxl:LessThanEqualsOp Mdid="0.0.0.0"/>
+        <dxl:GreaterThanOp Mdid="0.0.0.0"/>
+        <dxl:GreaterThanEqualsOp Mdid="0.0.0.0"/>
+        <dxl:ComparisonOp Mdid="0.0.0.0"/>
+        <dxl:ArrayType Mdid="0.1012.1.0"/>
+        <dxl:MinAgg Mdid="0.0.0.0"/>
+        <dxl:MaxAgg Mdid="0.0.0.0"/>
+        <dxl:AvgAgg Mdid="0.0.0.0"/>
+        <dxl:SumAgg Mdid="0.0.0.0"/>
+        <dxl:CountAgg Mdid="0.2147.1.0"/>
+      </dxl:Type>
+      <dxl:Type Mdid="0.28.1.0" Name="xid" IsRedistributable="true" 
IsHashable="true" IsMergeJoinable="false" IsComposite="false" 
IsTextRelated="false" IsFixedLength="true" Length="4" PassByValue="true">
+        <dxl:DistrOpfamily Mdid="0.2225.1.0"/>
+        <dxl:EqualityOp Mdid="0.352.1.0"/>
+        <dxl:InequalityOp Mdid="0.3315.1.0"/>
+        <dxl:LessThanOp Mdid="0.0.0.0"/>
+        <dxl:LessThanEqualsOp Mdid="0.0.0.0"/>
+        <dxl:GreaterThanOp Mdid="0.0.0.0"/>
+        <dxl:GreaterThanEqualsOp Mdid="0.0.0.0"/>
+        <dxl:ComparisonOp Mdid="0.0.0.0"/>
+        <dxl:ArrayType Mdid="0.1011.1.0"/>
+        <dxl:MinAgg Mdid="0.0.0.0"/>
+        <dxl:MaxAgg Mdid="0.0.0.0"/>
+        <dxl:AvgAgg Mdid="0.0.0.0"/>
+        <dxl:SumAgg Mdid="0.0.0.0"/>
+        <dxl:CountAgg Mdid="0.2147.1.0"/>
+      </dxl:Type>
+      <dxl:Relation Mdid="6.112424.1.0" Name="boolpart" IsTemporary="false" 
StorageType="Heap" DistributionPolicy="Hash" DistributionColumns="0" 
Keys="7,8,2" PartitionColumns="1" PartitionTypes="l">
+        <dxl:Columns>
+          <dxl:Column Name="a" Attno="1" Mdid="0.23.1.0" Nullable="true" 
ColWidth="4">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+          <dxl:Column Name="b" Attno="2" Mdid="0.16.1.0" Nullable="true" 
ColWidth="1">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+          <dxl:Column Name="ctid" Attno="-1" Mdid="0.27.1.0" Nullable="false" 
ColWidth="6">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+          <dxl:Column Name="xmin" Attno="-2" Mdid="0.28.1.0" Nullable="false" 
ColWidth="4">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+          <dxl:Column Name="cmin" Attno="-3" Mdid="0.29.1.0" Nullable="false" 
ColWidth="4">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+          <dxl:Column Name="xmax" Attno="-4" Mdid="0.28.1.0" Nullable="false" 
ColWidth="4">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+          <dxl:Column Name="cmax" Attno="-5" Mdid="0.29.1.0" Nullable="false" 
ColWidth="4">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+          <dxl:Column Name="tableoid" Attno="-6" Mdid="0.26.1.0" 
Nullable="false" ColWidth="4">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+          <dxl:Column Name="gp_segment_id" Attno="-7" Mdid="0.23.1.0" 
Nullable="false" ColWidth="4">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+        </dxl:Columns>
+        <dxl:IndexInfoList/>
+        <dxl:CheckConstraints/>
+        <dxl:DistrOpfamilies>
+          <dxl:DistrOpfamily Mdid="0.1977.1.0"/>
+        </dxl:DistrOpfamilies>
+        <dxl:Partitions>
+          <dxl:Partition Mdid="6.112430.1.0"/>
+          <dxl:Partition Mdid="6.112427.1.0"/>
+        </dxl:Partitions>
+      </dxl:Relation>
+      <dxl:Relation Mdid="6.112427.1.0" Name="boolpart_1_prt_l1" 
IsTemporary="false" StorageType="Heap" DistributionPolicy="Hash" 
DistributionColumns="0" Keys="8,2">
+        <dxl:Columns>
+          <dxl:Column Name="a" Attno="1" Mdid="0.23.1.0" Nullable="true" 
ColWidth="4">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+          <dxl:Column Name="b" Attno="2" Mdid="0.16.1.0" Nullable="true" 
ColWidth="1">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+          <dxl:Column Name="ctid" Attno="-1" Mdid="0.27.1.0" Nullable="false" 
ColWidth="6">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+          <dxl:Column Name="xmin" Attno="-2" Mdid="0.28.1.0" Nullable="false" 
ColWidth="4">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+          <dxl:Column Name="cmin" Attno="-3" Mdid="0.29.1.0" Nullable="false" 
ColWidth="4">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+          <dxl:Column Name="xmax" Attno="-4" Mdid="0.28.1.0" Nullable="false" 
ColWidth="4">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+          <dxl:Column Name="cmax" Attno="-5" Mdid="0.29.1.0" Nullable="false" 
ColWidth="4">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+          <dxl:Column Name="tableoid" Attno="-6" Mdid="0.26.1.0" 
Nullable="false" ColWidth="4">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+          <dxl:Column Name="gp_segment_id" Attno="-7" Mdid="0.23.1.0" 
Nullable="false" ColWidth="4">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+        </dxl:Columns>
+        <dxl:IndexInfoList/>
+        <dxl:CheckConstraints/>
+        <dxl:DistrOpfamilies>
+          <dxl:DistrOpfamily Mdid="0.1977.1.0"/>
+        </dxl:DistrOpfamilies>
+        <dxl:PartConstraint>
+          <dxl:And>
+            <dxl:IsNotNull>
+              <dxl:Ident ColId="2" ColName="b" TypeMdid="0.16.1.0"/>
+            </dxl:IsNotNull>
+            <dxl:Comparison ComparisonOperator="=" OperatorMdid="0.91.1.0">
+              <dxl:Ident ColId="2" ColName="b" TypeMdid="0.16.1.0"/>
+              <dxl:ConstValue TypeMdid="0.16.1.0" Value="true"/>
+            </dxl:Comparison>
+          </dxl:And>
+        </dxl:PartConstraint>
+      </dxl:Relation>
+      <dxl:ColumnStatistics Mdid="1.112424.1.0.1" Name="b" Width="1.000000" 
NullFreq="0.000000" NdvRemain="0.000000" FreqRemain="0.000000" 
ColStatsMissing="true"/>
+      <dxl:ColumnStatistics Mdid="1.112424.1.0.0" Name="a" Width="4.000000" 
NullFreq="0.000000" NdvRemain="0.000000" FreqRemain="0.000000" 
ColStatsMissing="true"/>
+      <dxl:GPDBScalarOp Mdid="0.91.1.0" Name="=" ComparisonType="Eq" 
ReturnsNullOnNullInput="true" IsNDVPreserving="false">
+        <dxl:LeftType Mdid="0.16.1.0"/>
+        <dxl:RightType Mdid="0.16.1.0"/>
+        <dxl:ResultType Mdid="0.16.1.0"/>
+        <dxl:OpFunc Mdid="0.60.1.0"/>
+        <dxl:Commutator Mdid="0.91.1.0"/>
+        <dxl:InverseOp Mdid="0.85.1.0"/>
+        <dxl:HashOpfamily Mdid="0.2222.1.0"/>
+        <dxl:LegacyHashOpfamily Mdid="0.7124.1.0"/>
+        <dxl:Opfamilies>
+          <dxl:Opfamily Mdid="0.424.1.0"/>
+          <dxl:Opfamily Mdid="0.2222.1.0"/>
+          <dxl:Opfamily Mdid="0.7124.1.0"/>
+          <dxl:Opfamily Mdid="0.10002.1.0"/>
+        </dxl:Opfamilies>
+      </dxl:GPDBScalarOp>
+      <dxl:RelationExtendedStatistics Mdid="10.112424.1.0" Name="boolpart"/>
+    </dxl:Metadata>
+    <dxl:Query>
+      <dxl:OutputColumns>
+        <dxl:Ident ColId="1" ColName="a" TypeMdid="0.23.1.0"/>
+        <dxl:Ident ColId="2" ColName="b" TypeMdid="0.16.1.0"/>
+      </dxl:OutputColumns>
+      <dxl:CTEList/>
+      <dxl:LogicalSelect>
+        <dxl:IsTrue>
+          <dxl:Ident ColId="2" ColName="b" TypeMdid="0.16.1.0"/>
+        </dxl:IsTrue>
+        <dxl:LogicalGet>
+          <dxl:TableDescriptor Mdid="6.112424.1.0" TableName="boolpart" 
LockMode="1">
+            <dxl:Columns>
+              <dxl:Column ColId="1" Attno="1" ColName="a" TypeMdid="0.23.1.0" 
ColWidth="4"/>
+              <dxl:Column ColId="2" Attno="2" ColName="b" TypeMdid="0.16.1.0" 
ColWidth="1"/>
+              <dxl:Column ColId="3" Attno="-1" ColName="ctid" 
TypeMdid="0.27.1.0" ColWidth="6"/>
+              <dxl:Column ColId="4" Attno="-2" ColName="xmin" 
TypeMdid="0.28.1.0" ColWidth="4"/>
+              <dxl:Column ColId="5" Attno="-3" ColName="cmin" 
TypeMdid="0.29.1.0" ColWidth="4"/>
+              <dxl:Column ColId="6" Attno="-4" ColName="xmax" 
TypeMdid="0.28.1.0" ColWidth="4"/>
+              <dxl:Column ColId="7" Attno="-5" ColName="cmax" 
TypeMdid="0.29.1.0" ColWidth="4"/>
+              <dxl:Column ColId="8" Attno="-6" ColName="tableoid" 
TypeMdid="0.26.1.0" ColWidth="4"/>
+              <dxl:Column ColId="9" Attno="-7" ColName="gp_segment_id" 
TypeMdid="0.23.1.0" ColWidth="4"/>
+            </dxl:Columns>
+          </dxl:TableDescriptor>
+        </dxl:LogicalGet>
+      </dxl:LogicalSelect>
+    </dxl:Query>
+    <dxl:Plan Id="0" SpaceSize="1">
+      <dxl:GatherMotion InputSegments="0,1,2" OutputSegments="-1">
+        <dxl:Properties>
+          <dxl:Cost StartupCost="0" TotalCost="431.000039" Rows="1.000000" 
Width="5"/>
+        </dxl:Properties>
+        <dxl:ProjList>
+          <dxl:ProjElem ColId="0" Alias="a">
+            <dxl:Ident ColId="0" ColName="a" TypeMdid="0.23.1.0"/>
+          </dxl:ProjElem>
+          <dxl:ProjElem ColId="1" Alias="b">
+            <dxl:Ident ColId="1" ColName="b" TypeMdid="0.16.1.0"/>
+          </dxl:ProjElem>
+        </dxl:ProjList>
+        <dxl:Filter/>
+        <dxl:SortingColumnList/>
+        <dxl:DynamicTableScan SelectorIds="">
+          <dxl:Properties>
+            <dxl:Cost StartupCost="0" TotalCost="431.000020" Rows="1.000000" 
Width="5"/>
+          </dxl:Properties>
+          <dxl:ProjList>
+            <dxl:ProjElem ColId="0" Alias="a">
+              <dxl:Ident ColId="0" ColName="a" TypeMdid="0.23.1.0"/>
+            </dxl:ProjElem>
+            <dxl:ProjElem ColId="1" Alias="b">
+              <dxl:Ident ColId="1" ColName="b" TypeMdid="0.16.1.0"/>
+            </dxl:ProjElem>
+          </dxl:ProjList>
+          <dxl:Filter>
+            <dxl:IsTrue>
+              <dxl:Ident ColId="1" ColName="b" TypeMdid="0.16.1.0"/>
+            </dxl:IsTrue>
+          </dxl:Filter>
+          <dxl:Partitions>
+            <dxl:Partition Mdid="6.112427.1.0"/>
+          </dxl:Partitions>
+          <dxl:TableDescriptor Mdid="6.112424.1.0" TableName="boolpart" 
LockMode="1">
+            <dxl:Columns>
+              <dxl:Column ColId="0" Attno="1" ColName="a" TypeMdid="0.23.1.0" 
ColWidth="4"/>
+              <dxl:Column ColId="1" Attno="2" ColName="b" TypeMdid="0.16.1.0" 
ColWidth="1"/>
+              <dxl:Column ColId="2" Attno="-1" ColName="ctid" 
TypeMdid="0.27.1.0" ColWidth="6"/>
+              <dxl:Column ColId="3" Attno="-2" ColName="xmin" 
TypeMdid="0.28.1.0" ColWidth="4"/>
+              <dxl:Column ColId="4" Attno="-3" ColName="cmin" 
TypeMdid="0.29.1.0" ColWidth="4"/>
+              <dxl:Column ColId="5" Attno="-4" ColName="xmax" 
TypeMdid="0.28.1.0" ColWidth="4"/>
+              <dxl:Column ColId="6" Attno="-5" ColName="cmax" 
TypeMdid="0.29.1.0" ColWidth="4"/>
+              <dxl:Column ColId="7" Attno="-6" ColName="tableoid" 
TypeMdid="0.26.1.0" ColWidth="4"/>
+              <dxl:Column ColId="8" Attno="-7" ColName="gp_segment_id" 
TypeMdid="0.23.1.0" ColWidth="4"/>
+            </dxl:Columns>
+          </dxl:TableDescriptor>
+        </dxl:DynamicTableScan>
+      </dxl:GatherMotion>
+    </dxl:Plan>
+  </dxl:Thread>
+</dxl:DXLMessage>
diff --git a/src/backend/gporca/data/dxl/minidump/PartTbl-SPE-Boolean2.mdp 
b/src/backend/gporca/data/dxl/minidump/PartTbl-SPE-Boolean2.mdp
new file mode 100644
index 0000000000..49c1f8c646
--- /dev/null
+++ b/src/backend/gporca/data/dxl/minidump/PartTbl-SPE-Boolean2.mdp
@@ -0,0 +1,461 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<dxl:DXLMessage xmlns:dxl="http://greenplum.com/dxl/2010/12/";>
+  <dxl:Comment><![CDATA[
+    Objective: Perform static partition elimination (SPE) on a table 
partitioned
+    by a boolean column. In below setup containing 3 leaf tables and predicate
+    IS TRUE OR IS FALSE, then 2 table should be scanned.
+
+    CREATE TABLE boolpart(a int, b bool) PARTITION BY LIST(b) (
+        PARTITION l1 values(true), PARTITION l2 values(false), DEFAULT 
PARTITION def);
+    INSERT INTO boolpart values (1,true);
+    INSERT INTO boolpart values (2, false);
+
+    EXPLAIN SELECT * FROM boolpart WHERE b IS true or b IS false;
+  ]]>
+  </dxl:Comment>
+  <dxl:Thread Id="0">
+    <dxl:OptimizerConfig>
+      <dxl:EnumeratorConfig Id="0" PlanSamples="0" CostThreshold="0"/>
+      <dxl:StatisticsConfig DampingFactorFilter="0.750000" 
DampingFactorJoin="0.000000" DampingFactorGroupBy="0.750000" 
MaxStatsBuckets="100"/>
+      <dxl:CTEConfig CTEInliningCutoff="0"/>
+      <dxl:WindowOids RowNumber="3100" Rank="3101"/>
+      <dxl:CostModelConfig CostModelType="1" SegmentsForCosting="3">
+        <dxl:CostParams>
+          <dxl:CostParam Name="NLJFactor" Value="1024.000000" 
LowerBound="1023.500000" UpperBound="1024.500000"/>
+        </dxl:CostParams>
+      </dxl:CostModelConfig>
+      <dxl:Hint JoinArityForAssociativityCommutativity="18" 
ArrayExpansionThreshold="20" JoinOrderDynamicProgThreshold="10" 
BroadcastThreshold="100000" EnforceConstraintsOnDML="false" 
PushGroupByBelowSetopThreshold="10" XformBindThreshold="0" SkewFactor="0"/>
+      <dxl:TraceFlags 
Value="102001,102002,102003,102043,102074,102120,102144,103001,103014,103022,103026,103027,103029,103033,103038,103040,104002,104003,104004,104005,105000,106000"/>
+    </dxl:OptimizerConfig>
+    <dxl:Metadata SystemIds="0.GPDB">
+      <dxl:Type Mdid="0.16.1.0" Name="bool" IsRedistributable="true" 
IsHashable="true" IsMergeJoinable="true" IsComposite="false" 
IsTextRelated="false" IsFixedLength="true" Length="1" PassByValue="true">
+        <dxl:DistrOpfamily Mdid="0.2222.1.0"/>
+        <dxl:LegacyDistrOpfamily Mdid="0.7124.1.0"/>
+        <dxl:EqualityOp Mdid="0.91.1.0"/>
+        <dxl:InequalityOp Mdid="0.85.1.0"/>
+        <dxl:LessThanOp Mdid="0.58.1.0"/>
+        <dxl:LessThanEqualsOp Mdid="0.1694.1.0"/>
+        <dxl:GreaterThanOp Mdid="0.59.1.0"/>
+        <dxl:GreaterThanEqualsOp Mdid="0.1695.1.0"/>
+        <dxl:ComparisonOp Mdid="0.1693.1.0"/>
+        <dxl:ArrayType Mdid="0.1000.1.0"/>
+        <dxl:MinAgg Mdid="0.0.0.0"/>
+        <dxl:MaxAgg Mdid="0.0.0.0"/>
+        <dxl:AvgAgg Mdid="0.0.0.0"/>
+        <dxl:SumAgg Mdid="0.0.0.0"/>
+        <dxl:CountAgg Mdid="0.2147.1.0"/>
+      </dxl:Type>
+      <dxl:Type Mdid="0.23.1.0" Name="int4" IsRedistributable="true" 
IsHashable="true" IsMergeJoinable="true" IsComposite="false" 
IsTextRelated="false" IsFixedLength="true" Length="4" PassByValue="true">
+        <dxl:DistrOpfamily Mdid="0.1977.1.0"/>
+        <dxl:LegacyDistrOpfamily Mdid="0.7100.1.0"/>
+        <dxl:EqualityOp Mdid="0.96.1.0"/>
+        <dxl:InequalityOp Mdid="0.518.1.0"/>
+        <dxl:LessThanOp Mdid="0.97.1.0"/>
+        <dxl:LessThanEqualsOp Mdid="0.523.1.0"/>
+        <dxl:GreaterThanOp Mdid="0.521.1.0"/>
+        <dxl:GreaterThanEqualsOp Mdid="0.525.1.0"/>
+        <dxl:ComparisonOp Mdid="0.351.1.0"/>
+        <dxl:ArrayType Mdid="0.1007.1.0"/>
+        <dxl:MinAgg Mdid="0.2132.1.0"/>
+        <dxl:MaxAgg Mdid="0.2116.1.0"/>
+        <dxl:AvgAgg Mdid="0.2101.1.0"/>
+        <dxl:SumAgg Mdid="0.2108.1.0"/>
+        <dxl:CountAgg Mdid="0.2147.1.0"/>
+      </dxl:Type>
+      <dxl:Type Mdid="0.26.1.0" Name="oid" IsRedistributable="true" 
IsHashable="true" IsMergeJoinable="true" IsComposite="false" 
IsTextRelated="false" IsFixedLength="true" Length="4" PassByValue="true">
+        <dxl:DistrOpfamily Mdid="0.1990.1.0"/>
+        <dxl:LegacyDistrOpfamily Mdid="0.7109.1.0"/>
+        <dxl:EqualityOp Mdid="0.607.1.0"/>
+        <dxl:InequalityOp Mdid="0.608.1.0"/>
+        <dxl:LessThanOp Mdid="0.609.1.0"/>
+        <dxl:LessThanEqualsOp Mdid="0.611.1.0"/>
+        <dxl:GreaterThanOp Mdid="0.610.1.0"/>
+        <dxl:GreaterThanEqualsOp Mdid="0.612.1.0"/>
+        <dxl:ComparisonOp Mdid="0.356.1.0"/>
+        <dxl:ArrayType Mdid="0.1028.1.0"/>
+        <dxl:MinAgg Mdid="0.2134.1.0"/>
+        <dxl:MaxAgg Mdid="0.2118.1.0"/>
+        <dxl:AvgAgg Mdid="0.0.0.0"/>
+        <dxl:SumAgg Mdid="0.0.0.0"/>
+        <dxl:CountAgg Mdid="0.2147.1.0"/>
+      </dxl:Type>
+      <dxl:Type Mdid="0.27.1.0" Name="tid" IsRedistributable="true" 
IsHashable="true" IsMergeJoinable="true" IsComposite="false" 
IsTextRelated="false" IsFixedLength="true" Length="6" PassByValue="false">
+        <dxl:DistrOpfamily Mdid="0.2227.1.0"/>
+        <dxl:LegacyDistrOpfamily Mdid="0.7110.1.0"/>
+        <dxl:EqualityOp Mdid="0.387.1.0"/>
+        <dxl:InequalityOp Mdid="0.402.1.0"/>
+        <dxl:LessThanOp Mdid="0.2799.1.0"/>
+        <dxl:LessThanEqualsOp Mdid="0.2801.1.0"/>
+        <dxl:GreaterThanOp Mdid="0.2800.1.0"/>
+        <dxl:GreaterThanEqualsOp Mdid="0.2802.1.0"/>
+        <dxl:ComparisonOp Mdid="0.2794.1.0"/>
+        <dxl:ArrayType Mdid="0.1010.1.0"/>
+        <dxl:MinAgg Mdid="0.2798.1.0"/>
+        <dxl:MaxAgg Mdid="0.2797.1.0"/>
+        <dxl:AvgAgg Mdid="0.0.0.0"/>
+        <dxl:SumAgg Mdid="0.0.0.0"/>
+        <dxl:CountAgg Mdid="0.2147.1.0"/>
+      </dxl:Type>
+      <dxl:Type Mdid="0.29.1.0" Name="cid" IsRedistributable="true" 
IsHashable="true" IsMergeJoinable="false" IsComposite="false" 
IsTextRelated="false" IsFixedLength="true" Length="4" PassByValue="true">
+        <dxl:DistrOpfamily Mdid="0.2226.1.0"/>
+        <dxl:EqualityOp Mdid="0.385.1.0"/>
+        <dxl:InequalityOp Mdid="0.0.0.0"/>
+        <dxl:LessThanOp Mdid="0.0.0.0"/>
+        <dxl:LessThanEqualsOp Mdid="0.0.0.0"/>
+        <dxl:GreaterThanOp Mdid="0.0.0.0"/>
+        <dxl:GreaterThanEqualsOp Mdid="0.0.0.0"/>
+        <dxl:ComparisonOp Mdid="0.0.0.0"/>
+        <dxl:ArrayType Mdid="0.1012.1.0"/>
+        <dxl:MinAgg Mdid="0.0.0.0"/>
+        <dxl:MaxAgg Mdid="0.0.0.0"/>
+        <dxl:AvgAgg Mdid="0.0.0.0"/>
+        <dxl:SumAgg Mdid="0.0.0.0"/>
+        <dxl:CountAgg Mdid="0.2147.1.0"/>
+      </dxl:Type>
+      <dxl:Type Mdid="0.28.1.0" Name="xid" IsRedistributable="true" 
IsHashable="true" IsMergeJoinable="false" IsComposite="false" 
IsTextRelated="false" IsFixedLength="true" Length="4" PassByValue="true">
+        <dxl:DistrOpfamily Mdid="0.2225.1.0"/>
+        <dxl:EqualityOp Mdid="0.352.1.0"/>
+        <dxl:InequalityOp Mdid="0.3315.1.0"/>
+        <dxl:LessThanOp Mdid="0.0.0.0"/>
+        <dxl:LessThanEqualsOp Mdid="0.0.0.0"/>
+        <dxl:GreaterThanOp Mdid="0.0.0.0"/>
+        <dxl:GreaterThanEqualsOp Mdid="0.0.0.0"/>
+        <dxl:ComparisonOp Mdid="0.0.0.0"/>
+        <dxl:ArrayType Mdid="0.1011.1.0"/>
+        <dxl:MinAgg Mdid="0.0.0.0"/>
+        <dxl:MaxAgg Mdid="0.0.0.0"/>
+        <dxl:AvgAgg Mdid="0.0.0.0"/>
+        <dxl:SumAgg Mdid="0.0.0.0"/>
+        <dxl:CountAgg Mdid="0.2147.1.0"/>
+      </dxl:Type>
+      <dxl:RelationExtendedStatistics Mdid="10.112486.1.0" Name="boolpart"/>
+      <dxl:ColumnStatistics Mdid="1.112486.1.0.1" Name="b" Width="1.000000" 
NullFreq="0.000000" NdvRemain="0.000000" FreqRemain="0.000000" 
ColStatsMissing="true"/>
+      <dxl:ColumnStatistics Mdid="1.112486.1.0.0" Name="a" Width="4.000000" 
NullFreq="0.000000" NdvRemain="0.000000" FreqRemain="0.000000" 
ColStatsMissing="true"/>
+      <dxl:RelationStatistics Mdid="2.112486.1.0" Name="boolpart" 
Rows="0.000000" RelPages="0" RelAllVisible="0" EmptyRelation="true"/>
+      <dxl:Relation Mdid="6.112486.1.0" Name="boolpart" IsTemporary="false" 
StorageType="Heap" DistributionPolicy="Hash" DistributionColumns="0" 
Keys="7,8,2" PartitionColumns="1" PartitionTypes="l">
+        <dxl:Columns>
+          <dxl:Column Name="a" Attno="1" Mdid="0.23.1.0" Nullable="true" 
ColWidth="4">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+          <dxl:Column Name="b" Attno="2" Mdid="0.16.1.0" Nullable="true" 
ColWidth="1">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+          <dxl:Column Name="ctid" Attno="-1" Mdid="0.27.1.0" Nullable="false" 
ColWidth="6">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+          <dxl:Column Name="xmin" Attno="-2" Mdid="0.28.1.0" Nullable="false" 
ColWidth="4">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+          <dxl:Column Name="cmin" Attno="-3" Mdid="0.29.1.0" Nullable="false" 
ColWidth="4">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+          <dxl:Column Name="xmax" Attno="-4" Mdid="0.28.1.0" Nullable="false" 
ColWidth="4">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+          <dxl:Column Name="cmax" Attno="-5" Mdid="0.29.1.0" Nullable="false" 
ColWidth="4">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+          <dxl:Column Name="tableoid" Attno="-6" Mdid="0.26.1.0" 
Nullable="false" ColWidth="4">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+          <dxl:Column Name="gp_segment_id" Attno="-7" Mdid="0.23.1.0" 
Nullable="false" ColWidth="4">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+        </dxl:Columns>
+        <dxl:IndexInfoList/>
+        <dxl:CheckConstraints/>
+        <dxl:DistrOpfamilies>
+          <dxl:DistrOpfamily Mdid="0.1977.1.0"/>
+        </dxl:DistrOpfamilies>
+        <dxl:Partitions>
+          <dxl:Partition Mdid="6.112495.1.0"/>
+          <dxl:Partition Mdid="6.112492.1.0"/>
+          <dxl:Partition Mdid="6.112489.1.0"/>
+        </dxl:Partitions>
+      </dxl:Relation>
+      <dxl:GPDBScalarOp Mdid="0.58.1.0" Name="&lt;" ComparisonType="LT" 
ReturnsNullOnNullInput="true" IsNDVPreserving="false">
+        <dxl:LeftType Mdid="0.16.1.0"/>
+        <dxl:RightType Mdid="0.16.1.0"/>
+        <dxl:ResultType Mdid="0.16.1.0"/>
+        <dxl:OpFunc Mdid="0.56.1.0"/>
+        <dxl:Commutator Mdid="0.59.1.0"/>
+        <dxl:InverseOp Mdid="0.1695.1.0"/>
+        <dxl:Opfamilies>
+          <dxl:Opfamily Mdid="0.424.1.0"/>
+          <dxl:Opfamily Mdid="0.10002.1.0"/>
+        </dxl:Opfamilies>
+      </dxl:GPDBScalarOp>
+      <dxl:GPDBScalarOp Mdid="0.59.1.0" Name="&gt;" ComparisonType="GT" 
ReturnsNullOnNullInput="true" IsNDVPreserving="false">
+        <dxl:LeftType Mdid="0.16.1.0"/>
+        <dxl:RightType Mdid="0.16.1.0"/>
+        <dxl:ResultType Mdid="0.16.1.0"/>
+        <dxl:OpFunc Mdid="0.57.1.0"/>
+        <dxl:Commutator Mdid="0.58.1.0"/>
+        <dxl:InverseOp Mdid="0.1694.1.0"/>
+        <dxl:Opfamilies>
+          <dxl:Opfamily Mdid="0.424.1.0"/>
+          <dxl:Opfamily Mdid="0.10002.1.0"/>
+        </dxl:Opfamilies>
+      </dxl:GPDBScalarOp>
+      <dxl:GPDBScalarOp Mdid="0.85.1.0" Name="&lt;&gt;" ComparisonType="NEq" 
ReturnsNullOnNullInput="true" IsNDVPreserving="false">
+        <dxl:LeftType Mdid="0.16.1.0"/>
+        <dxl:RightType Mdid="0.16.1.0"/>
+        <dxl:ResultType Mdid="0.16.1.0"/>
+        <dxl:OpFunc Mdid="0.84.1.0"/>
+        <dxl:Commutator Mdid="0.85.1.0"/>
+        <dxl:InverseOp Mdid="0.91.1.0"/>
+      </dxl:GPDBScalarOp>
+      <dxl:Relation Mdid="6.112492.1.0" Name="boolpart_1_prt_l1" 
IsTemporary="false" StorageType="Heap" DistributionPolicy="Hash" 
DistributionColumns="0" Keys="8,2">
+        <dxl:Columns>
+          <dxl:Column Name="a" Attno="1" Mdid="0.23.1.0" Nullable="true" 
ColWidth="4">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+          <dxl:Column Name="b" Attno="2" Mdid="0.16.1.0" Nullable="true" 
ColWidth="1">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+          <dxl:Column Name="ctid" Attno="-1" Mdid="0.27.1.0" Nullable="false" 
ColWidth="6">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+          <dxl:Column Name="xmin" Attno="-2" Mdid="0.28.1.0" Nullable="false" 
ColWidth="4">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+          <dxl:Column Name="cmin" Attno="-3" Mdid="0.29.1.0" Nullable="false" 
ColWidth="4">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+          <dxl:Column Name="xmax" Attno="-4" Mdid="0.28.1.0" Nullable="false" 
ColWidth="4">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+          <dxl:Column Name="cmax" Attno="-5" Mdid="0.29.1.0" Nullable="false" 
ColWidth="4">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+          <dxl:Column Name="tableoid" Attno="-6" Mdid="0.26.1.0" 
Nullable="false" ColWidth="4">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+          <dxl:Column Name="gp_segment_id" Attno="-7" Mdid="0.23.1.0" 
Nullable="false" ColWidth="4">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+        </dxl:Columns>
+        <dxl:IndexInfoList/>
+        <dxl:CheckConstraints/>
+        <dxl:DistrOpfamilies>
+          <dxl:DistrOpfamily Mdid="0.1977.1.0"/>
+        </dxl:DistrOpfamilies>
+        <dxl:PartConstraint>
+          <dxl:And>
+            <dxl:IsNotNull>
+              <dxl:Ident ColId="2" ColName="b" TypeMdid="0.16.1.0"/>
+            </dxl:IsNotNull>
+            <dxl:Comparison ComparisonOperator="=" OperatorMdid="0.91.1.0">
+              <dxl:Ident ColId="2" ColName="b" TypeMdid="0.16.1.0"/>
+              <dxl:ConstValue TypeMdid="0.16.1.0" Value="true"/>
+            </dxl:Comparison>
+          </dxl:And>
+        </dxl:PartConstraint>
+      </dxl:Relation>
+      <dxl:GPDBScalarOp Mdid="0.91.1.0" Name="=" ComparisonType="Eq" 
ReturnsNullOnNullInput="true" IsNDVPreserving="false">
+        <dxl:LeftType Mdid="0.16.1.0"/>
+        <dxl:RightType Mdid="0.16.1.0"/>
+        <dxl:ResultType Mdid="0.16.1.0"/>
+        <dxl:OpFunc Mdid="0.60.1.0"/>
+        <dxl:Commutator Mdid="0.91.1.0"/>
+        <dxl:InverseOp Mdid="0.85.1.0"/>
+        <dxl:HashOpfamily Mdid="0.2222.1.0"/>
+        <dxl:LegacyHashOpfamily Mdid="0.7124.1.0"/>
+        <dxl:Opfamilies>
+          <dxl:Opfamily Mdid="0.424.1.0"/>
+          <dxl:Opfamily Mdid="0.2222.1.0"/>
+          <dxl:Opfamily Mdid="0.7124.1.0"/>
+          <dxl:Opfamily Mdid="0.10002.1.0"/>
+        </dxl:Opfamilies>
+      </dxl:GPDBScalarOp>
+      <dxl:Relation Mdid="6.112495.1.0" Name="boolpart_1_prt_l2" 
IsTemporary="false" StorageType="Heap" DistributionPolicy="Hash" 
DistributionColumns="0" Keys="8,2">
+        <dxl:Columns>
+          <dxl:Column Name="a" Attno="1" Mdid="0.23.1.0" Nullable="true" 
ColWidth="4">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+          <dxl:Column Name="b" Attno="2" Mdid="0.16.1.0" Nullable="true" 
ColWidth="1">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+          <dxl:Column Name="ctid" Attno="-1" Mdid="0.27.1.0" Nullable="false" 
ColWidth="6">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+          <dxl:Column Name="xmin" Attno="-2" Mdid="0.28.1.0" Nullable="false" 
ColWidth="4">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+          <dxl:Column Name="cmin" Attno="-3" Mdid="0.29.1.0" Nullable="false" 
ColWidth="4">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+          <dxl:Column Name="xmax" Attno="-4" Mdid="0.28.1.0" Nullable="false" 
ColWidth="4">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+          <dxl:Column Name="cmax" Attno="-5" Mdid="0.29.1.0" Nullable="false" 
ColWidth="4">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+          <dxl:Column Name="tableoid" Attno="-6" Mdid="0.26.1.0" 
Nullable="false" ColWidth="4">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+          <dxl:Column Name="gp_segment_id" Attno="-7" Mdid="0.23.1.0" 
Nullable="false" ColWidth="4">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+        </dxl:Columns>
+        <dxl:IndexInfoList/>
+        <dxl:CheckConstraints/>
+        <dxl:DistrOpfamilies>
+          <dxl:DistrOpfamily Mdid="0.1977.1.0"/>
+        </dxl:DistrOpfamilies>
+        <dxl:PartConstraint>
+          <dxl:And>
+            <dxl:IsNotNull>
+              <dxl:Ident ColId="2" ColName="b" TypeMdid="0.16.1.0"/>
+            </dxl:IsNotNull>
+            <dxl:Comparison ComparisonOperator="=" OperatorMdid="0.91.1.0">
+              <dxl:Ident ColId="2" ColName="b" TypeMdid="0.16.1.0"/>
+              <dxl:ConstValue TypeMdid="0.16.1.0" Value="false"/>
+            </dxl:Comparison>
+          </dxl:And>
+        </dxl:PartConstraint>
+      </dxl:Relation>
+      <dxl:Relation Mdid="6.112489.1.0" Name="boolpart_1_prt_def" 
IsTemporary="false" StorageType="Heap" DistributionPolicy="Hash" 
DistributionColumns="0" Keys="8,2">
+        <dxl:Columns>
+          <dxl:Column Name="a" Attno="1" Mdid="0.23.1.0" Nullable="true" 
ColWidth="4">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+          <dxl:Column Name="b" Attno="2" Mdid="0.16.1.0" Nullable="true" 
ColWidth="1">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+          <dxl:Column Name="ctid" Attno="-1" Mdid="0.27.1.0" Nullable="false" 
ColWidth="6">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+          <dxl:Column Name="xmin" Attno="-2" Mdid="0.28.1.0" Nullable="false" 
ColWidth="4">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+          <dxl:Column Name="cmin" Attno="-3" Mdid="0.29.1.0" Nullable="false" 
ColWidth="4">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+          <dxl:Column Name="xmax" Attno="-4" Mdid="0.28.1.0" Nullable="false" 
ColWidth="4">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+          <dxl:Column Name="cmax" Attno="-5" Mdid="0.29.1.0" Nullable="false" 
ColWidth="4">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+          <dxl:Column Name="tableoid" Attno="-6" Mdid="0.26.1.0" 
Nullable="false" ColWidth="4">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+          <dxl:Column Name="gp_segment_id" Attno="-7" Mdid="0.23.1.0" 
Nullable="false" ColWidth="4">
+            <dxl:DefaultValue/>
+          </dxl:Column>
+        </dxl:Columns>
+        <dxl:IndexInfoList/>
+        <dxl:CheckConstraints/>
+        <dxl:DistrOpfamilies>
+          <dxl:DistrOpfamily Mdid="0.1977.1.0"/>
+        </dxl:DistrOpfamilies>
+        <dxl:PartConstraint>
+          <dxl:Not>
+            <dxl:And>
+              <dxl:IsNotNull>
+                <dxl:Ident ColId="2" ColName="b" TypeMdid="0.16.1.0"/>
+              </dxl:IsNotNull>
+              <dxl:ArrayComp OperatorName="=" OperatorMdid="0.91.1.0" 
OperatorType="Any">
+                <dxl:Ident ColId="2" ColName="b" TypeMdid="0.16.1.0"/>
+                <dxl:Array ArrayType="0.1000.1.0" ElementType="0.16.1.0" 
MultiDimensional="false">
+                  <dxl:ConstValue TypeMdid="0.16.1.0" Value="false"/>
+                  <dxl:ConstValue TypeMdid="0.16.1.0" Value="true"/>
+                </dxl:Array>
+              </dxl:ArrayComp>
+            </dxl:And>
+          </dxl:Not>
+        </dxl:PartConstraint>
+      </dxl:Relation>
+    </dxl:Metadata>
+    <dxl:Query>
+      <dxl:OutputColumns>
+        <dxl:Ident ColId="1" ColName="a" TypeMdid="0.23.1.0"/>
+        <dxl:Ident ColId="2" ColName="b" TypeMdid="0.16.1.0"/>
+      </dxl:OutputColumns>
+      <dxl:CTEList/>
+      <dxl:LogicalSelect>
+        <dxl:Or>
+          <dxl:IsTrue>
+            <dxl:Ident ColId="2" ColName="b" TypeMdid="0.16.1.0"/>
+          </dxl:IsTrue>
+          <dxl:IsFalse>
+            <dxl:Ident ColId="2" ColName="b" TypeMdid="0.16.1.0"/>
+          </dxl:IsFalse>
+        </dxl:Or>
+        <dxl:LogicalGet>
+          <dxl:TableDescriptor Mdid="6.112486.1.0" TableName="boolpart" 
LockMode="1">
+            <dxl:Columns>
+              <dxl:Column ColId="1" Attno="1" ColName="a" TypeMdid="0.23.1.0" 
ColWidth="4"/>
+              <dxl:Column ColId="2" Attno="2" ColName="b" TypeMdid="0.16.1.0" 
ColWidth="1"/>
+              <dxl:Column ColId="3" Attno="-1" ColName="ctid" 
TypeMdid="0.27.1.0" ColWidth="6"/>
+              <dxl:Column ColId="4" Attno="-2" ColName="xmin" 
TypeMdid="0.28.1.0" ColWidth="4"/>
+              <dxl:Column ColId="5" Attno="-3" ColName="cmin" 
TypeMdid="0.29.1.0" ColWidth="4"/>
+              <dxl:Column ColId="6" Attno="-4" ColName="xmax" 
TypeMdid="0.28.1.0" ColWidth="4"/>
+              <dxl:Column ColId="7" Attno="-5" ColName="cmax" 
TypeMdid="0.29.1.0" ColWidth="4"/>
+              <dxl:Column ColId="8" Attno="-6" ColName="tableoid" 
TypeMdid="0.26.1.0" ColWidth="4"/>
+              <dxl:Column ColId="9" Attno="-7" ColName="gp_segment_id" 
TypeMdid="0.23.1.0" ColWidth="4"/>
+            </dxl:Columns>
+          </dxl:TableDescriptor>
+        </dxl:LogicalGet>
+      </dxl:LogicalSelect>
+    </dxl:Query>
+    <dxl:Plan Id="0" SpaceSize="1">
+      <dxl:GatherMotion InputSegments="0,1,2" OutputSegments="-1">
+        <dxl:Properties>
+          <dxl:Cost StartupCost="0" TotalCost="431.000039" Rows="1.000000" 
Width="5"/>
+        </dxl:Properties>
+        <dxl:ProjList>
+          <dxl:ProjElem ColId="0" Alias="a">
+            <dxl:Ident ColId="0" ColName="a" TypeMdid="0.23.1.0"/>
+          </dxl:ProjElem>
+          <dxl:ProjElem ColId="1" Alias="b">
+            <dxl:Ident ColId="1" ColName="b" TypeMdid="0.16.1.0"/>
+          </dxl:ProjElem>
+        </dxl:ProjList>
+        <dxl:Filter/>
+        <dxl:SortingColumnList/>
+        <dxl:DynamicTableScan SelectorIds="">
+          <dxl:Properties>
+            <dxl:Cost StartupCost="0" TotalCost="431.000020" Rows="1.000000" 
Width="5"/>
+          </dxl:Properties>
+          <dxl:ProjList>
+            <dxl:ProjElem ColId="0" Alias="a">
+              <dxl:Ident ColId="0" ColName="a" TypeMdid="0.23.1.0"/>
+            </dxl:ProjElem>
+            <dxl:ProjElem ColId="1" Alias="b">
+              <dxl:Ident ColId="1" ColName="b" TypeMdid="0.16.1.0"/>
+            </dxl:ProjElem>
+          </dxl:ProjList>
+          <dxl:Filter>
+            <dxl:Or>
+              <dxl:IsTrue>
+                <dxl:Ident ColId="1" ColName="b" TypeMdid="0.16.1.0"/>
+              </dxl:IsTrue>
+              <dxl:IsFalse>
+                <dxl:Ident ColId="1" ColName="b" TypeMdid="0.16.1.0"/>
+              </dxl:IsFalse>
+            </dxl:Or>
+          </dxl:Filter>
+          <dxl:Partitions>
+            <dxl:Partition Mdid="6.112495.1.0"/>
+            <dxl:Partition Mdid="6.112492.1.0"/>
+          </dxl:Partitions>
+          <dxl:TableDescriptor Mdid="6.112486.1.0" TableName="boolpart" 
LockMode="1">
+            <dxl:Columns>
+              <dxl:Column ColId="0" Attno="1" ColName="a" TypeMdid="0.23.1.0" 
ColWidth="4"/>
+              <dxl:Column ColId="1" Attno="2" ColName="b" TypeMdid="0.16.1.0" 
ColWidth="1"/>
+              <dxl:Column ColId="2" Attno="-1" ColName="ctid" 
TypeMdid="0.27.1.0" ColWidth="6"/>
+              <dxl:Column ColId="3" Attno="-2" ColName="xmin" 
TypeMdid="0.28.1.0" ColWidth="4"/>
+              <dxl:Column ColId="4" Attno="-3" ColName="cmin" 
TypeMdid="0.29.1.0" ColWidth="4"/>
+              <dxl:Column ColId="5" Attno="-4" ColName="xmax" 
TypeMdid="0.28.1.0" ColWidth="4"/>
+              <dxl:Column ColId="6" Attno="-5" ColName="cmax" 
TypeMdid="0.29.1.0" ColWidth="4"/>
+              <dxl:Column ColId="7" Attno="-6" ColName="tableoid" 
TypeMdid="0.26.1.0" ColWidth="4"/>
+              <dxl:Column ColId="8" Attno="-7" ColName="gp_segment_id" 
TypeMdid="0.23.1.0" ColWidth="4"/>
+            </dxl:Columns>
+          </dxl:TableDescriptor>
+        </dxl:DynamicTableScan>
+      </dxl:GatherMotion>
+    </dxl:Plan>
+  </dxl:Thread>
+</dxl:DXLMessage>
diff --git 
a/src/backend/gporca/libgpopt/include/gpopt/base/CConstraintInterval.h 
b/src/backend/gporca/libgpopt/include/gpopt/base/CConstraintInterval.h
index 54c2595fce..e71f572a18 100644
--- a/src/backend/gporca/libgpopt/include/gpopt/base/CConstraintInterval.h
+++ b/src/backend/gporca/libgpopt/include/gpopt/base/CConstraintInterval.h
@@ -113,6 +113,15 @@ private:
        static CConstraintInterval *PciIntervalFromScalarNullTest(
                CMemoryPool *mp, CExpression *pexpr, CColRef *colref);
 
+       // create interval from scalar boolean test
+       static CConstraintInterval *PciIntervalFromScalarBooleanTest(
+               CMemoryPool *mp, CExpression *pexpr, CColRef *colref);
+
+       // create interval from bool scalar ident
+       static CConstraintInterval *PciIntervalFromScalarIdent(CMemoryPool *mp,
+                                                                               
                                   CColRef *colref,
+                                                                               
                                   BOOL infer_nulls_as);
+
        // creates a range like [x,x] where x is a constant
        static CRangeArray *PciRangeFromColConstCmp(CMemoryPool *mp,
                                                                                
                IMDType::ECmpType cmp_type,
diff --git a/src/backend/gporca/libgpopt/include/gpopt/base/CUtils.h 
b/src/backend/gporca/libgpopt/include/gpopt/base/CUtils.h
index 3d5ec8c1c1..3735b31079 100644
--- a/src/backend/gporca/libgpopt/include/gpopt/base/CUtils.h
+++ b/src/backend/gporca/libgpopt/include/gpopt/base/CUtils.h
@@ -655,6 +655,9 @@ public:
        static BOOL FScalarBoolOp(CExpression *pexpr,
                                                          
CScalarBoolOp::EBoolOperator eboolop);
 
+       // check if expression is scalar bool test op
+       static BOOL FScalarBooleanTest(CExpression *pexpr);
+
        // check if expression is scalar null test
        static BOOL FScalarNullTest(CExpression *pexpr);
 
diff --git a/src/backend/gporca/libgpopt/src/base/CConstraintInterval.cpp 
b/src/backend/gporca/libgpopt/src/base/CConstraintInterval.cpp
index 3c48dc405c..70a6ab5d1d 100644
--- a/src/backend/gporca/libgpopt/src/base/CConstraintInterval.cpp
+++ b/src/backend/gporca/libgpopt/src/base/CConstraintInterval.cpp
@@ -23,9 +23,12 @@
 #include "gpopt/base/CUtils.h"
 #include "gpopt/operators/CPredicateUtils.h"
 #include "gpopt/operators/CScalarArray.h"
+#include "gpopt/operators/CScalarBooleanTest.h"
 #include "gpopt/operators/CScalarIdent.h"
 #include "gpopt/operators/CScalarIsDistinctFrom.h"
+#include "naucrates/base/IDatumBool.h"
 #include "naucrates/md/IMDScalarOp.h"
+#include "naucrates/md/IMDTypeBool.h"
 
 using namespace gpopt;
 
@@ -75,7 +78,27 @@ CConstraintInterval::~CConstraintInterval()
 BOOL
 CConstraintInterval::FContradiction() const
 {
-       return (!m_fIncludesNull && 0 == m_pdrgprng->Size());
+       if (!m_fIncludesNull && 0 == m_pdrgprng->Size())
+       {
+               return true;
+       }
+
+       // Constraint on boolean column is special case because only 2 values 
exist
+       // in the domain space [0,1]. If both ends are exclude then the 
constraint
+       // is a contradiction.
+       if (m_pcr->RetrieveType()->GetDatumType() == IMDType::EtiBool &&
+               m_pdrgprng->Size() == 1 && !m_fIncludesNull)
+       {
+               if ((*m_pdrgprng)[0]->EriLeft() == CRange::EriExcluded &&
+                       (*m_pdrgprng)[0]->EriRight() == CRange::EriExcluded &&
+                       (*m_pdrgprng)[0]->PdatumLeft() != nullptr &&
+                       (*m_pdrgprng)[0]->PdatumRight() != nullptr)
+               {
+                       return true;
+               }
+       }
+
+       return false;
 }
 
 //---------------------------------------------------------------------------
@@ -174,10 +197,16 @@ CConstraintInterval::PciIntervalFromScalarExpr(
                case COperator::EopScalarNullTest:
                        pci = PciIntervalFromScalarNullTest(mp, pexpr, colref);
                        break;
+               case COperator::EopScalarBooleanTest:
+                       pci = PciIntervalFromScalarBooleanTest(mp, pexpr, 
colref);
+                       break;
                case COperator::EopScalarBoolOp:
                        pci = PciIntervalFromScalarBoolOp(mp, pexpr, colref, 
infer_nulls_as,
                                                                                
          access_method);
                        break;
+               case COperator::EopScalarIdent:
+                       pci = PciIntervalFromScalarIdent(mp, colref, 
infer_nulls_as);
+                       break;
                case COperator::EopScalarCmp:
                        pci = PciIntervalFromScalarCmp(mp, pexpr, colref, 
infer_nulls_as,
                                                                                
   access_method);
@@ -405,6 +434,84 @@ 
CConstraintInterval::PciIntervalFromScalarNullTest(CMemoryPool *mp,
        return nullptr;
 }
 
+//---------------------------------------------------------------------------
+//     @function:
+//             CConstraintInterval::PciIntervalFromScalarBooleanTest
+//
+//     @doc:
+//             Create interval from scalar null test
+//
+//---------------------------------------------------------------------------
+CConstraintInterval *
+CConstraintInterval::PciIntervalFromScalarBooleanTest(CMemoryPool *mp,
+                                                                               
                          CExpression *pexpr,
+                                                                               
                          CColRef *colref)
+{
+       GPOS_ASSERT(nullptr != pexpr);
+       GPOS_ASSERT(CUtils::FScalarBooleanTest(pexpr));
+
+       CScalarBooleanTest *pop = CScalarBooleanTest::PopConvert(pexpr->Pop());
+       GPOS_ASSERT(nullptr != pop);
+
+       CRangeArray *pdrngprng = GPOS_NEW(mp) CRangeArray(mp);
+       CMDAccessor *md_accessor = COptCtxt::PoctxtFromTLS()->Pmda();
+       const IMDTypeBool *pmdtypebool = md_accessor->PtMDType<IMDTypeBool>();
+       const IComparator *pcomp = COptCtxt::PoctxtFromTLS()->Pcomp();
+       bool fIncludesNull = false;
+       switch (pop->Ebt())
+       {
+               case CScalarBooleanTest::EbtIsTrue:
+               case CScalarBooleanTest::EbtIsNotFalse:
+               {
+                       if (pop->Ebt() == CScalarBooleanTest::EbtIsNotFalse)
+                       {
+                               fIncludesNull = true;
+                       }
+
+                       IDatumBool *datum =
+                               pmdtypebool->CreateBoolDatum(mp, true, false 
/*is_null*/);
+                       CRange *prange =
+                               GPOS_NEW(mp) CRange(pcomp, IMDType::EcmptEq, 
datum);
+                       pdrngprng->Append(prange);
+                       break;
+               }
+               case CScalarBooleanTest::EbtIsNotTrue:
+               case CScalarBooleanTest::EbtIsFalse:
+               {
+                       if (pop->Ebt() == CScalarBooleanTest::EbtIsNotTrue)
+                       {
+                               fIncludesNull = true;
+                       }
+
+                       IDatumBool *datum =
+                               pmdtypebool->CreateBoolDatum(mp, false, false 
/*is_null*/);
+                       CRange *prange =
+                               GPOS_NEW(mp) CRange(pcomp, IMDType::EcmptEq, 
datum);
+                       pdrngprng->Append(prange);
+                       break;
+               }
+               case CScalarBooleanTest::EbtIsUnknown:
+               case CScalarBooleanTest::EbtIsNotUnknown:
+               {
+                       IDatumBool *datum =
+                               pmdtypebool->CreateBoolDatum(mp, false, false 
/*is_null*/);
+                       CRange *prange =
+                               GPOS_NEW(mp) CRange(pcomp, IMDType::EcmptOther, 
datum);
+                       pdrngprng->Append(prange);
+                       fIncludesNull = true;
+                       break;
+               }
+               default:
+               {
+                       GPOS_ASSERT(false && "Unknown boolean test type");
+                       break;
+               }
+       }
+
+       return GPOS_NEW(mp)
+               CConstraintInterval(mp, colref, pdrngprng, fIncludesNull);
+}
+
 
 //---------------------------------------------------------------------------
 //     @function:
@@ -617,6 +724,33 @@ CConstraintInterval::PciIntervalFromScalarBoolOp(
        }
 }
 
+//---------------------------------------------------------------------------
+//     @function:
+//             CConstraintInterval::PciIntervalFromScalarIdent
+//
+//     @doc:
+//             Create interval from boolean scalar ident
+//
+//---------------------------------------------------------------------------
+CConstraintInterval *
+CConstraintInterval::PciIntervalFromScalarIdent(CMemoryPool *mp,
+                                                                               
                CColRef *colref,
+                                                                               
                BOOL infer_nulls_as)
+{
+       GPOS_ASSERT(colref->RetrieveType()->GetDatumType() == IMDType::EtiBool);
+
+       CRangeArray *pdrngprng = GPOS_NEW(mp) CRangeArray(mp);
+       CMDAccessor *md_accessor = COptCtxt::PoctxtFromTLS()->Pmda();
+       const IMDTypeBool *pmdtypebool = md_accessor->PtMDType<IMDTypeBool>();
+       IDatumBool *datum =
+               pmdtypebool->CreateBoolDatum(mp, true, false /*is_null*/);
+       pdrngprng->Append(GPOS_NEW(mp) 
CRange(COptCtxt::PoctxtFromTLS()->Pcomp(),
+                                                                               
  IMDType::EcmptEq, datum));
+
+       return GPOS_NEW(mp) CConstraintInterval(mp, colref, pdrngprng,
+                                                                               
        infer_nulls_as /*fIncludesNull*/);
+}
+
 //---------------------------------------------------------------------------
 //     @function:
 //             CConstraintInterval::PciIntervalFromScalarBoolOr
@@ -1282,12 +1416,30 @@ CConstraintInterval::PciUnbounded(CMemoryPool *mp, 
const CColRef *colref,
        }
 
        mdid->AddRef();
-       CRange *prange = GPOS_NEW(mp) CRange(
-               mdid, COptCtxt::PoctxtFromTLS()->Pcomp(), nullptr 
/*ppointLeft*/,
-               CRange::EriExcluded, nullptr /*ppointRight*/, 
CRange::EriExcluded);
 
        CRangeArray *pdrgprng = GPOS_NEW(mp) CRangeArray(mp);
-       pdrgprng->Append(prange);
+       if (colref->RetrieveType()->GetDatumType() == IMDType::EtiBool)
+       {
+               // valid boolean constraint values must map in the range [0, 1]
+               CMDAccessor *md_accessor = COptCtxt::PoctxtFromTLS()->Pmda();
+               const IMDTypeBool *pmdtypebool = 
md_accessor->PtMDType<IMDTypeBool>();
+               CRange *prange = GPOS_NEW(mp)
+                       CRange(mdid, COptCtxt::PoctxtFromTLS()->Pcomp(),
+                                  pmdtypebool->CreateBoolDatum(
+                                          mp, false, false /*is_null*/) 
/*ppointLeft*/,
+                                  CRange::EriIncluded,
+                                  pmdtypebool->CreateBoolDatum(
+                                          mp, true, false /*is_null*/) 
/*ppointRight*/,
+                                  CRange::EriIncluded);
+               pdrgprng->Append(prange);
+       }
+       else
+       {
+               CRange *prange = GPOS_NEW(mp) CRange(
+                       mdid, COptCtxt::PoctxtFromTLS()->Pcomp(), nullptr 
/*ppointLeft*/,
+                       CRange::EriExcluded, nullptr /*ppointRight*/, 
CRange::EriExcluded);
+               pdrgprng->Append(prange);
+       }
 
        return GPOS_NEW(mp)
                CConstraintInterval(mp, colref, pdrgprng, fIncludesNull);
diff --git a/src/backend/gporca/libgpopt/src/base/CDefaultComparator.cpp 
b/src/backend/gporca/libgpopt/src/base/CDefaultComparator.cpp
index fc33632dbd..285ac191a7 100644
--- a/src/backend/gporca/libgpopt/src/base/CDefaultComparator.cpp
+++ b/src/backend/gporca/libgpopt/src/base/CDefaultComparator.cpp
@@ -115,6 +115,7 @@ CDefaultComparator::FUseInternalEvaluator(const IDatum 
*datum1,
        // double value
        if (mdid1->Equals(datum2->MDId()) && datum1->StatsAreComparable(datum2) 
&&
                (CMDIdGPDB::m_mdid_date.Equals(mdid1) ||
+                CMDIdGPDB::m_mdid_bool.Equals(mdid1) ||
                 CMDIdGPDB::m_mdid_time.Equals(mdid1) ||
                 CMDIdGPDB::m_mdid_timestamp.Equals(mdid1) ||
                 CMDIdGPDB::m_mdid_float4.Equals(mdid1) ||
diff --git a/src/backend/gporca/libgpopt/src/base/CUtils.cpp 
b/src/backend/gporca/libgpopt/src/base/CUtils.cpp
index 6552a44940..e8735b3a3c 100644
--- a/src/backend/gporca/libgpopt/src/base/CUtils.cpp
+++ b/src/backend/gporca/libgpopt/src/base/CUtils.cpp
@@ -3027,6 +3027,13 @@ CUtils::FScalarBoolOp(CExpression *pexpr, 
CScalarBoolOp::EBoolOperator eboolop)
                   eboolop == CScalarBoolOp::PopConvert(pop)->Eboolop();
 }
 
+// check if given expression is a boolean test
+BOOL
+CUtils::FScalarBooleanTest(CExpression *pexpr)
+{
+       return (COperator::EopScalarBooleanTest == pexpr->Pop()->Eopid());
+}
+
 // check if given expression is a scalar null test
 BOOL
 CUtils::FScalarNullTest(CExpression *pexpr)
@@ -3168,6 +3175,7 @@ CUtils::FConstrainableType(IMDId *mdid_type)
        {
                // also allow date/time/timestamp/float4/float8
                return (CMDIdGPDB::m_mdid_date.Equals(mdid_type) ||
+                               CMDIdGPDB::m_mdid_bool.Equals(mdid_type) ||
                                CMDIdGPDB::m_mdid_time.Equals(mdid_type) ||
                                CMDIdGPDB::m_mdid_timestamp.Equals(mdid_type) ||
                                CMDIdGPDB::m_mdid_timeTz.Equals(mdid_type) ||
diff --git a/src/backend/gporca/server/CMakeLists.txt 
b/src/backend/gporca/server/CMakeLists.txt
index 2d78e2020d..244ae4fcd3 100644
--- a/src/backend/gporca/server/CMakeLists.txt
+++ b/src/backend/gporca/server/CMakeLists.txt
@@ -243,6 +243,9 @@ PartTbl-SPE-DynamicTableScan-Range-Cost5 
PartTbl-SPE-DynamicTableScan-List-Cost1
 PartTbl-SPE-DynamicTableScan-List-Cost2 PartTbl-SPE-DynamicTableScan-List-Cost3
 PartTbl-SPE-DynamicTableScan-List-Cost4 
PartTbl-SPE-DynamicTableScan-List-Cost5;
 
+CPartTblSPEBoolTest:
+PartTbl-SPE-Boolean1 PartTbl-SPE-Boolean2;
+
 CSetop1Test:
 ValueScanWithDuplicateAndSelfComparison PushGbBelowNaryUnionAll
 PushGbBelowNaryUnion-1 PushGbBelowNaryUnion-2 MS-UnionAll-1
diff --git 
a/src/backend/gporca/server/src/unittest/gpopt/translate/CTranslatorExprToDXLTest.cpp
 
b/src/backend/gporca/server/src/unittest/gpopt/translate/CTranslatorExprToDXLTest.cpp
index b44eede46b..190eaf65a8 100644
--- 
a/src/backend/gporca/server/src/unittest/gpopt/translate/CTranslatorExprToDXLTest.cpp
+++ 
b/src/backend/gporca/server/src/unittest/gpopt/translate/CTranslatorExprToDXLTest.cpp
@@ -167,12 +167,10 @@ const CTestUtils::STestCase rgtc[] = {
         "../data/dxl/expressiontests/DynamicGetNLJoinPartKeyPlan.xml"},
        {"../data/dxl/expressiontests/DynamicGetNLJoinOtherKeyQuery.xml",
         "../data/dxl/expressiontests/DynamicGetNLJoinOtherKeyPlan.xml"},
-       // GPDB_12_MERGE_FIXME: Re-enable once ORCA supports constraint 
derivation on
-       // bool columns
-       //      {"../data/dxl/expressiontests/DynamicGetBooleanQuery.xml",
-       //       "../data/dxl/expressiontests/DynamicGetBooleanPlan.xml"},
-       //      {"../data/dxl/expressiontests/DynamicGetBooleanNotQuery.xml",
-       //       "../data/dxl/expressiontests/DynamicGetBooleanNotPlan.xml"},
+       {"../data/dxl/expressiontests/DynamicGetBooleanQuery.xml",
+        "../data/dxl/expressiontests/DynamicGetBooleanPlan.xml"},
+       {"../data/dxl/expressiontests/DynamicGetBooleanNotQuery.xml",
+        "../data/dxl/expressiontests/DynamicGetBooleanNotPlan.xml"},
        {"../data/dxl/expressiontests/DynamicGetMultiJoinQuery.xml",
         "../data/dxl/expressiontests/DynamicGetMultiJoinPlan.xml"},
        {"../data/dxl/expressiontests/CoalesceQuery.xml",
diff --git a/src/test/regress/expected/partition_prune_optimizer.out 
b/src/test/regress/expected/partition_prune_optimizer.out
index f7d6a479f4..cc433eff42 100644
--- a/src/test/regress/expected/partition_prune_optimizer.out
+++ b/src/test/regress/expected/partition_prune_optimizer.out
@@ -1190,7 +1190,7 @@ explain (costs off) select * from boolpart where a = 
false;
 ------------------------------------------
  Gather Motion 3:1  (slice1; segments: 3)
    ->  Dynamic Seq Scan on boolpart
-         Number of partitions to scan: 3 (out of 3)
+         Number of partitions to scan: 1 (out of 3)
          Filter: (NOT a)
  Optimizer: Pivotal Optimizer (GPORCA)
 (5 rows)
@@ -1200,7 +1200,7 @@ explain (costs off) select * from boolpart where not a = 
false;
 ------------------------------------------
  Gather Motion 3:1  (slice1; segments: 3)
    ->  Dynamic Seq Scan on boolpart
-         Number of partitions to scan: 3 (out of 3)
+         Number of partitions to scan: 1 (out of 3)
          Filter: a
  Optimizer: Pivotal Optimizer (GPORCA)
 (5 rows)
@@ -1220,17 +1220,17 @@ explain (costs off) select * from boolpart where a is 
not true;
 ------------------------------------------
  Gather Motion 3:1  (slice1; segments: 3)
    ->  Dynamic Seq Scan on boolpart
-         Number of partitions to scan: 3 (out of 3)
+         Number of partitions to scan: 2 (out of 3)
          Filter: (a IS NOT TRUE)
  Optimizer: Pivotal Optimizer (GPORCA)
 (5 rows)
 
 explain (costs off) select * from boolpart where a is not true and a is not 
false;
-                          QUERY PLAN                          
---------------------------------------------------------
- Gather Motion 3:1  (slice1; segments: 3)
+              QUERY PLAN               
+---------------------------------------
+ Gather Motion 1:1  (slice1; segments: 1)
    ->  Dynamic Seq Scan on boolpart
-         Number of partitions to scan: 3 (out of 3)
+         Number of partitions to scan: 1 (out of 3)
          Filter: ((a IS NOT TRUE) AND (a IS NOT FALSE))
  Optimizer: Pivotal Optimizer (GPORCA)
 (5 rows)
diff --git a/src/test/regress/expected/partition_pruning.out 
b/src/test/regress/expected/partition_pruning.out
index 91cb2ea69c..b2c44dd8b1 100644
--- a/src/test/regress/expected/partition_pruning.out
+++ b/src/test/regress/expected/partition_pruning.out
@@ -3011,4 +3011,484 @@ select get_selected_parts('explain analyze select * 
from bar where j is distinct
  [0, 0]
 (1 row)
 
+-- Table partitioned by boolean column
+CREATE TABLE pt_bool_tab
+(
+  col1 int,
+  col2 bool
+)
+distributed by (col1)
+partition by list(col2)
+(
+  partition part1 values(true),
+  partition part2 values(false)
+);
+INSERT INTO pt_bool_tab SELECT i, true FROM generate_series(1,3)i;
+INSERT INTO pt_bool_tab SELECT i, false FROM generate_series(1,2)i;
+EXPLAIN SELECT * FROM pt_bool_tab WHERE col2 IS true;
+                                             QUERY PLAN                        
                      
+-----------------------------------------------------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)  
(cost=10000000000.00..10000000969.00 rows=46750 width=5)
+   ->  Seq Scan on pt_bool_tab_1_prt_part1  
(cost=10000000000.00..10000000345.67 rows=15583 width=5)
+         Filter: (col2 IS TRUE)
+ Optimizer: Postgres query optimizer
+(4 rows)
+
+SELECT * FROM pt_bool_tab WHERE col2 IS true;
+ col1 | col2 
+------+------
+    1 | t
+    2 | t
+    3 | t
+(3 rows)
+
+EXPLAIN SELECT * FROM pt_bool_tab WHERE col2 IS false;
+                                             QUERY PLAN                        
                      
+-----------------------------------------------------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)  
(cost=10000000000.00..10000000969.00 rows=46750 width=5)
+   ->  Seq Scan on pt_bool_tab_1_prt_part2  
(cost=10000000000.00..10000000345.67 rows=15583 width=5)
+         Filter: (col2 IS FALSE)
+ Optimizer: Postgres query optimizer
+(4 rows)
+
+SELECT * FROM pt_bool_tab WHERE col2 IS false;
+ col1 | col2 
+------+------
+    2 | f
+    1 | f
+(2 rows)
+
+EXPLAIN SELECT * FROM pt_bool_tab WHERE col2 IS NULL;
+                QUERY PLAN                
+------------------------------------------
+ Result  (cost=0.00..0.00 rows=0 width=0)
+   One-Time Filter: false
+ Optimizer: Postgres query optimizer
+(3 rows)
+
+SELECT * FROM pt_bool_tab WHERE col2 IS NULL;
+ col1 | col2 
+------+------
+(0 rows)
+
+EXPLAIN SELECT * FROM pt_bool_tab WHERE col2 IS unknown;
+                                               QUERY PLAN                      
                         
+--------------------------------------------------------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)  
(cost=10000000000.00..20000000694.14 rows=187 width=5)
+   ->  Append  (cost=10000000000.00..20000000691.65 rows=62 width=5)
+         ->  Seq Scan on pt_bool_tab_1_prt_part2  
(cost=10000000000.00..10000000345.67 rows=31 width=5)
+               Filter: (col2 IS UNKNOWN)
+         ->  Seq Scan on pt_bool_tab_1_prt_part1  
(cost=10000000000.00..10000000345.67 rows=31 width=5)
+               Filter: (col2 IS UNKNOWN)
+ Optimizer: Postgres query optimizer
+(7 rows)
+
+SELECT * FROM pt_bool_tab WHERE col2 IS unknown;
+ col1 | col2 
+------+------
+(0 rows)
+
+EXPLAIN SELECT * FROM pt_bool_tab WHERE col2 IS NOT true;
+                                             QUERY PLAN                        
                      
+-----------------------------------------------------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)  
(cost=10000000000.00..10000000969.00 rows=46750 width=5)
+   ->  Seq Scan on pt_bool_tab_1_prt_part2  
(cost=10000000000.00..10000000345.67 rows=15583 width=5)
+         Filter: (col2 IS NOT TRUE)
+ Optimizer: Postgres query optimizer
+(4 rows)
+
+SELECT * FROM pt_bool_tab WHERE col2 IS NOT true;
+ col1 | col2 
+------+------
+    2 | f
+    1 | f
+(2 rows)
+
+EXPLAIN SELECT * FROM pt_bool_tab WHERE col2 IS NOT false;
+                                             QUERY PLAN                        
                      
+-----------------------------------------------------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)  
(cost=10000000000.00..10000000969.00 rows=46750 width=5)
+   ->  Seq Scan on pt_bool_tab_1_prt_part1  
(cost=10000000000.00..10000000345.67 rows=15583 width=5)
+         Filter: (col2 IS NOT FALSE)
+ Optimizer: Postgres query optimizer
+(4 rows)
+
+SELECT * FROM pt_bool_tab WHERE col2 IS NOT false;
+ col1 | col2 
+------+------
+    2 | t
+    3 | t
+    1 | t
+(3 rows)
+
+EXPLAIN SELECT * FROM pt_bool_tab WHERE col2 IS NOT unknown;
+                                                QUERY PLAN                     
                            
+-----------------------------------------------------------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)  
(cost=10000000000.00..20000003493.53 rows=186813 width=5)
+   ->  Append  (cost=10000000000.00..20000001002.69 rows=62271 width=5)
+         ->  Seq Scan on pt_bool_tab_1_prt_part2  
(cost=10000000000.00..10000000345.67 rows=31136 width=5)
+               Filter: (col2 IS NOT UNKNOWN)
+         ->  Seq Scan on pt_bool_tab_1_prt_part1  
(cost=10000000000.00..10000000345.67 rows=31136 width=5)
+               Filter: (col2 IS NOT UNKNOWN)
+ Optimizer: Postgres query optimizer
+(7 rows)
+
+SELECT * FROM pt_bool_tab WHERE col2 IS NOT unknown;
+ col1 | col2 
+------+------
+    1 | f
+    1 | t
+    2 | f
+    2 | t
+    3 | t
+(5 rows)
+
+EXPLAIN SELECT * FROM pt_bool_tab WHERE col2 IS NOT NULL;
+                                                QUERY PLAN                     
                            
+-----------------------------------------------------------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)  
(cost=10000000000.00..20000003493.53 rows=186813 width=5)
+   ->  Append  (cost=10000000000.00..20000001002.69 rows=62271 width=5)
+         ->  Seq Scan on pt_bool_tab_1_prt_part2  
(cost=10000000000.00..10000000345.67 rows=31136 width=5)
+               Filter: (col2 IS NOT NULL)
+         ->  Seq Scan on pt_bool_tab_1_prt_part1  
(cost=10000000000.00..10000000345.67 rows=31136 width=5)
+               Filter: (col2 IS NOT NULL)
+ Optimizer: Postgres query optimizer
+(7 rows)
+
+SELECT * FROM pt_bool_tab WHERE col2 IS NOT NULL;
+ col1 | col2 
+------+------
+    1 | f
+    1 | t
+    2 | f
+    2 | t
+    3 | t
+(5 rows)
+
+CREATE TABLE pt_bool_tab_df
+(
+  col1 int,
+  col2 bool
+)
+distributed by (col1)
+partition by list(col2)
+(
+  partition part1 values(true),
+  partition part2 values(false),
+  default partition def
+);
+INSERT INTO pt_bool_tab_df SELECT i, true FROM generate_series(1,3)i;
+INSERT INTO pt_bool_tab_df SELECT i, false FROM generate_series(1,2)i;
+INSERT INTO pt_bool_tab_df SELECT i, NULL FROM generate_series(1,1)i;
+EXPLAIN SELECT * FROM pt_bool_tab_df WHERE col2 IS true;
+                                               QUERY PLAN                      
                         
+--------------------------------------------------------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)  
(cost=10000000000.00..10000000969.00 rows=46750 width=5)
+   ->  Seq Scan on pt_bool_tab_df_1_prt_part1  
(cost=10000000000.00..10000000345.67 rows=15583 width=5)
+         Filter: (col2 IS TRUE)
+ Optimizer: Postgres query optimizer
+(4 rows)
+
+SELECT * FROM pt_bool_tab_df WHERE col2 IS true;
+ col1 | col2 
+------+------
+    1 | t
+    2 | t
+    3 | t
+(3 rows)
+
+EXPLAIN SELECT * FROM pt_bool_tab_df WHERE col2 IS false;
+                                               QUERY PLAN                      
                         
+--------------------------------------------------------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)  
(cost=10000000000.00..10000000969.00 rows=46750 width=5)
+   ->  Seq Scan on pt_bool_tab_df_1_prt_part2  
(cost=10000000000.00..10000000345.67 rows=15583 width=5)
+         Filter: (col2 IS FALSE)
+ Optimizer: Postgres query optimizer
+(4 rows)
+
+SELECT * FROM pt_bool_tab_df WHERE col2 IS false;
+ col1 | col2 
+------+------
+    2 | f
+    1 | f
+(2 rows)
+
+EXPLAIN SELECT * FROM pt_bool_tab_df WHERE col2 IS NULL;
+                                            QUERY PLAN                         
                    
+---------------------------------------------------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)  
(cost=10000000000.00..10000000346.91 rows=94 width=5)
+   ->  Seq Scan on pt_bool_tab_df_1_prt_def  
(cost=10000000000.00..10000000345.67 rows=31 width=5)
+         Filter: (col2 IS NULL)
+ Optimizer: Postgres query optimizer
+(4 rows)
+
+SELECT * FROM pt_bool_tab_df WHERE col2 IS NULL;
+ col1 | col2 
+------+------
+    1 | 
+(1 row)
+
+EXPLAIN SELECT * FROM pt_bool_tab_df WHERE col2 IS unknown;
+                                                QUERY PLAN                     
                            
+-----------------------------------------------------------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)  
(cost=10000000000.00..30000001041.21 rows=280 width=5)
+   ->  Append  (cost=10000000000.00..30000001037.47 rows=94 width=5)
+         ->  Seq Scan on pt_bool_tab_df_1_prt_part2  
(cost=10000000000.00..10000000345.67 rows=31 width=5)
+               Filter: (col2 IS UNKNOWN)
+         ->  Seq Scan on pt_bool_tab_df_1_prt_part1  
(cost=10000000000.00..10000000345.67 rows=31 width=5)
+               Filter: (col2 IS UNKNOWN)
+         ->  Seq Scan on pt_bool_tab_df_1_prt_def  
(cost=10000000000.00..10000000345.67 rows=31 width=5)
+               Filter: (col2 IS UNKNOWN)
+ Optimizer: Postgres query optimizer
+(9 rows)
+
+SELECT * FROM pt_bool_tab_df WHERE col2 IS unknown;
+ col1 | col2 
+------+------
+    1 | 
+(1 row)
+
+EXPLAIN SELECT * FROM pt_bool_tab_df WHERE col2 IS NOT true;
+                                               QUERY PLAN                      
                         
+--------------------------------------------------------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)  
(cost=10000000000.00..10000000969.00 rows=46750 width=5)
+   ->  Seq Scan on pt_bool_tab_df_1_prt_part2  
(cost=10000000000.00..10000000345.67 rows=15583 width=5)
+         Filter: (col2 IS NOT TRUE)
+ Optimizer: Postgres query optimizer
+(4 rows)
+
+SELECT * FROM pt_bool_tab_df WHERE col2 IS NOT true;
+ col1 | col2 
+------+------
+    2 | f
+    1 | f
+(2 rows)
+
+EXPLAIN SELECT * FROM pt_bool_tab_df WHERE col2 IS NOT false;
+                                               QUERY PLAN                      
                         
+--------------------------------------------------------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)  
(cost=10000000000.00..10000000969.00 rows=46750 width=5)
+   ->  Seq Scan on pt_bool_tab_df_1_prt_part1  
(cost=10000000000.00..10000000345.67 rows=15583 width=5)
+         Filter: (col2 IS NOT FALSE)
+ Optimizer: Postgres query optimizer
+(4 rows)
+
+SELECT * FROM pt_bool_tab_df WHERE col2 IS NOT false;
+ col1 | col2 
+------+------
+    2 | t
+    3 | t
+    1 | t
+(3 rows)
+
+EXPLAIN SELECT * FROM pt_bool_tab_df WHERE col2 IS NOT unknown;
+                                                  QUERY PLAN                   
                               
+--------------------------------------------------------------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)  
(cost=10000000000.00..30000005240.29 rows=280220 width=5)
+   ->  Append  (cost=10000000000.00..30000001504.03 rows=93406 width=5)
+         ->  Seq Scan on pt_bool_tab_df_1_prt_part2  
(cost=10000000000.00..10000000345.67 rows=31136 width=5)
+               Filter: (col2 IS NOT UNKNOWN)
+         ->  Seq Scan on pt_bool_tab_df_1_prt_part1  
(cost=10000000000.00..10000000345.67 rows=31136 width=5)
+               Filter: (col2 IS NOT UNKNOWN)
+         ->  Seq Scan on pt_bool_tab_df_1_prt_def  
(cost=10000000000.00..10000000345.67 rows=31136 width=5)
+               Filter: (col2 IS NOT UNKNOWN)
+ Optimizer: Postgres query optimizer
+(9 rows)
+
+SELECT * FROM pt_bool_tab_df WHERE col2 IS NOT unknown;
+ col1 | col2 
+------+------
+    2 | f
+    2 | t
+    3 | t
+    1 | f
+    1 | t
+(5 rows)
+
+EXPLAIN SELECT * FROM pt_bool_tab_df WHERE col2 IS NOT NULL;
+                                                  QUERY PLAN                   
                               
+--------------------------------------------------------------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)  
(cost=10000000000.00..30000005240.29 rows=280220 width=5)
+   ->  Append  (cost=10000000000.00..30000001504.03 rows=93406 width=5)
+         ->  Seq Scan on pt_bool_tab_df_1_prt_part2  
(cost=10000000000.00..10000000345.67 rows=31136 width=5)
+               Filter: (col2 IS NOT NULL)
+         ->  Seq Scan on pt_bool_tab_df_1_prt_part1  
(cost=10000000000.00..10000000345.67 rows=31136 width=5)
+               Filter: (col2 IS NOT NULL)
+         ->  Seq Scan on pt_bool_tab_df_1_prt_def  
(cost=10000000000.00..10000000345.67 rows=31136 width=5)
+               Filter: (col2 IS NOT NULL)
+ Optimizer: Postgres query optimizer
+(9 rows)
+
+SELECT * FROM pt_bool_tab_df WHERE col2 IS NOT NULL;
+ col1 | col2 
+------+------
+    2 | f
+    2 | t
+    3 | t
+    1 | f
+    1 | t
+(5 rows)
+
+CREATE TABLE pt_bool_tab_null
+(
+  col1 int,
+  col2 bool
+)
+distributed by (col1)
+partition by list(col2)
+(
+  partition part1 values(true),
+  partition part2 values(false),
+  partition part3 values(null)
+);
+INSERT INTO pt_bool_tab_null SELECT i, true FROM generate_series(1,3)i;
+INSERT INTO pt_bool_tab_null SELECT i, false FROM generate_series(1,2)i;
+INSERT INTO pt_bool_tab_null SELECT i, NULL FROM generate_series(1,1)i;
+EXPLAIN SELECT * FROM pt_bool_tab_null WHERE col2 IS true;
+                                                QUERY PLAN                     
                           
+----------------------------------------------------------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)  
(cost=10000000000.00..10000000969.00 rows=46750 width=5)
+   ->  Seq Scan on pt_bool_tab_null_1_prt_part1  
(cost=10000000000.00..10000000345.67 rows=15583 width=5)
+         Filter: (col2 IS TRUE)
+ Optimizer: Postgres query optimizer
+(4 rows)
+
+SELECT * FROM pt_bool_tab_null WHERE col2 IS true;
+ col1 | col2 
+------+------
+    1 | t
+    2 | t
+    3 | t
+(3 rows)
+
+EXPLAIN SELECT * FROM pt_bool_tab_null WHERE col2 IS false;
+                                                QUERY PLAN                     
                           
+----------------------------------------------------------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)  
(cost=10000000000.00..10000000969.00 rows=46750 width=5)
+   ->  Seq Scan on pt_bool_tab_null_1_prt_part2  
(cost=10000000000.00..10000000345.67 rows=15583 width=5)
+         Filter: (col2 IS FALSE)
+ Optimizer: Postgres query optimizer
+(4 rows)
+
+SELECT * FROM pt_bool_tab_null WHERE col2 IS false;
+ col1 | col2 
+------+------
+    1 | f
+    2 | f
+(2 rows)
+
+EXPLAIN SELECT * FROM pt_bool_tab_null WHERE col2 IS NULL;
+                                              QUERY PLAN                       
                        
+-------------------------------------------------------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)  
(cost=10000000000.00..10000000346.91 rows=94 width=5)
+   ->  Seq Scan on pt_bool_tab_null_1_prt_part3  
(cost=10000000000.00..10000000345.67 rows=31 width=5)
+         Filter: (col2 IS NULL)
+ Optimizer: Postgres query optimizer
+(4 rows)
+
+SELECT * FROM pt_bool_tab_null WHERE col2 IS NULL;
+ col1 | col2 
+------+------
+    1 | 
+(1 row)
+
+EXPLAIN SELECT * FROM pt_bool_tab_null WHERE col2 IS unknown;
+                                                 QUERY PLAN                    
                              
+-------------------------------------------------------------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)  
(cost=10000000000.00..30000001041.21 rows=280 width=5)
+   ->  Append  (cost=10000000000.00..30000001037.47 rows=94 width=5)
+         ->  Seq Scan on pt_bool_tab_null_1_prt_part2  
(cost=10000000000.00..10000000345.67 rows=31 width=5)
+               Filter: (col2 IS UNKNOWN)
+         ->  Seq Scan on pt_bool_tab_null_1_prt_part1  
(cost=10000000000.00..10000000345.67 rows=31 width=5)
+               Filter: (col2 IS UNKNOWN)
+         ->  Seq Scan on pt_bool_tab_null_1_prt_part3  
(cost=10000000000.00..10000000345.67 rows=31 width=5)
+               Filter: (col2 IS UNKNOWN)
+ Optimizer: Postgres query optimizer
+(9 rows)
+
+SELECT * FROM pt_bool_tab_null WHERE col2 IS unknown;
+ col1 | col2 
+------+------
+    1 | 
+(1 row)
+
+EXPLAIN SELECT * FROM pt_bool_tab_null WHERE col2 IS NOT true;
+                                                QUERY PLAN                     
                           
+----------------------------------------------------------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)  
(cost=10000000000.00..10000000969.00 rows=46750 width=5)
+   ->  Seq Scan on pt_bool_tab_null_1_prt_part2  
(cost=10000000000.00..10000000345.67 rows=15583 width=5)
+         Filter: (col2 IS NOT TRUE)
+ Optimizer: Postgres query optimizer
+(4 rows)
+
+SELECT * FROM pt_bool_tab_null WHERE col2 IS NOT true;
+ col1 | col2 
+------+------
+    1 | f
+    2 | f
+(2 rows)
+
+EXPLAIN SELECT * FROM pt_bool_tab_null WHERE col2 IS NOT false;
+                                                QUERY PLAN                     
                           
+----------------------------------------------------------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)  
(cost=10000000000.00..10000000969.00 rows=46750 width=5)
+   ->  Seq Scan on pt_bool_tab_null_1_prt_part1  
(cost=10000000000.00..10000000345.67 rows=15583 width=5)
+         Filter: (col2 IS NOT FALSE)
+ Optimizer: Postgres query optimizer
+(4 rows)
+
+SELECT * FROM pt_bool_tab_null WHERE col2 IS NOT false;
+ col1 | col2 
+------+------
+    2 | t
+    3 | t
+    1 | t
+(3 rows)
+
+EXPLAIN SELECT * FROM pt_bool_tab_null WHERE col2 IS NOT unknown;
+                                                   QUERY PLAN                  
                                 
+----------------------------------------------------------------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)  
(cost=10000000000.00..30000005240.29 rows=280220 width=5)
+   ->  Append  (cost=10000000000.00..30000001504.03 rows=93406 width=5)
+         ->  Seq Scan on pt_bool_tab_null_1_prt_part2  
(cost=10000000000.00..10000000345.67 rows=31136 width=5)
+               Filter: (col2 IS NOT UNKNOWN)
+         ->  Seq Scan on pt_bool_tab_null_1_prt_part1  
(cost=10000000000.00..10000000345.67 rows=31136 width=5)
+               Filter: (col2 IS NOT UNKNOWN)
+         ->  Seq Scan on pt_bool_tab_null_1_prt_part3  
(cost=10000000000.00..10000000345.67 rows=31136 width=5)
+               Filter: (col2 IS NOT UNKNOWN)
+ Optimizer: Postgres query optimizer
+(9 rows)
+
+SELECT * FROM pt_bool_tab_null WHERE col2 IS NOT unknown;
+ col1 | col2 
+------+------
+    2 | f
+    2 | t
+    3 | t
+    1 | f
+    1 | t
+(5 rows)
+
+EXPLAIN SELECT * FROM pt_bool_tab_null WHERE col2 IS NOT NULL;
+                                                   QUERY PLAN                  
                                 
+----------------------------------------------------------------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)  
(cost=10000000000.00..20000003493.53 rows=186813 width=5)
+   ->  Append  (cost=10000000000.00..20000001002.69 rows=62271 width=5)
+         ->  Seq Scan on pt_bool_tab_null_1_prt_part2  
(cost=10000000000.00..10000000345.67 rows=31136 width=5)
+               Filter: (col2 IS NOT NULL)
+         ->  Seq Scan on pt_bool_tab_null_1_prt_part1  
(cost=10000000000.00..10000000345.67 rows=31136 width=5)
+               Filter: (col2 IS NOT NULL)
+ Optimizer: Postgres query optimizer
+(7 rows)
+
+SELECT * FROM pt_bool_tab_null WHERE col2 IS NOT NULL;
+ col1 | col2 
+------+------
+    2 | f
+    2 | t
+    3 | t
+    1 | f
+    1 | t
+(5 rows)
+
 RESET ALL;
diff --git a/src/test/regress/expected/partition_pruning_optimizer.out 
b/src/test/regress/expected/partition_pruning_optimizer.out
index af85d9c619..a0d6ece014 100644
--- a/src/test/regress/expected/partition_pruning_optimizer.out
+++ b/src/test/regress/expected/partition_pruning_optimizer.out
@@ -2507,4 +2507,474 @@ select get_selected_parts('explain analyze select * 
from bar where j is distinct
  [0, 0]
 (1 row)
 
+-- Table partitioned by boolean column
+CREATE TABLE pt_bool_tab
+(
+  col1 int,
+  col2 bool
+)
+distributed by (col1)
+partition by list(col2)
+(
+  partition part1 values(true),
+  partition part2 values(false)
+);
+INSERT INTO pt_bool_tab SELECT i, true FROM generate_series(1,3)i;
+INSERT INTO pt_bool_tab SELECT i, false FROM generate_series(1,2)i;
+EXPLAIN SELECT * FROM pt_bool_tab WHERE col2 IS true;
+                                  QUERY PLAN                                  
+------------------------------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)  (cost=0.00..431.00 rows=1 width=5)
+   ->  Dynamic Seq Scan on pt_bool_tab  (cost=0.00..431.00 rows=1 width=5)
+         Number of partitions to scan: 1 (out of 2)
+         Filter: (col2 IS TRUE)
+ Optimizer: Pivotal Optimizer (GPORCA)
+(5 rows)
+
+SELECT * FROM pt_bool_tab WHERE col2 IS true;
+ col1 | col2 
+------+------
+    1 | t
+    2 | t
+    3 | t
+(3 rows)
+
+EXPLAIN SELECT * FROM pt_bool_tab WHERE col2 IS false;
+                                  QUERY PLAN                                  
+------------------------------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)  (cost=0.00..431.00 rows=1 width=5)
+   ->  Dynamic Seq Scan on pt_bool_tab  (cost=0.00..431.00 rows=1 width=5)
+         Number of partitions to scan: 1 (out of 2)
+         Filter: (col2 IS FALSE)
+ Optimizer: Pivotal Optimizer (GPORCA)
+(5 rows)
+
+SELECT * FROM pt_bool_tab WHERE col2 IS false;
+ col1 | col2 
+------+------
+    2 | f
+    1 | f
+(2 rows)
+
+EXPLAIN SELECT * FROM pt_bool_tab WHERE col2 IS NULL;
+                QUERY PLAN                
+------------------------------------------
+ Result  (cost=0.00..0.00 rows=0 width=5)
+   One-Time Filter: false
+ Optimizer: Pivotal Optimizer (GPORCA)
+(3 rows)
+
+SELECT * FROM pt_bool_tab WHERE col2 IS NULL;
+ col1 | col2 
+------+------
+(0 rows)
+
+EXPLAIN SELECT * FROM pt_bool_tab WHERE col2 IS unknown;
+                                  QUERY PLAN                                  
+------------------------------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)  (cost=0.00..431.00 rows=1 width=5)
+   ->  Dynamic Seq Scan on pt_bool_tab  (cost=0.00..431.00 rows=1 width=5)
+         Number of partitions to scan: 2 (out of 2)
+         Filter: (col2 IS UNKNOWN)
+ Optimizer: Pivotal Optimizer (GPORCA)
+(5 rows)
+
+SELECT * FROM pt_bool_tab WHERE col2 IS unknown;
+ col1 | col2 
+------+------
+(0 rows)
+
+EXPLAIN SELECT * FROM pt_bool_tab WHERE col2 IS NOT true;
+                                  QUERY PLAN                                  
+------------------------------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)  (cost=0.00..431.00 rows=1 width=5)
+   ->  Dynamic Seq Scan on pt_bool_tab  (cost=0.00..431.00 rows=1 width=5)
+         Number of partitions to scan: 1 (out of 2)
+         Filter: (col2 IS NOT TRUE)
+ Optimizer: Pivotal Optimizer (GPORCA)
+(5 rows)
+
+SELECT * FROM pt_bool_tab WHERE col2 IS NOT true;
+ col1 | col2 
+------+------
+    2 | f
+    1 | f
+(2 rows)
+
+EXPLAIN SELECT * FROM pt_bool_tab WHERE col2 IS NOT false;
+                                  QUERY PLAN                                  
+------------------------------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)  (cost=0.00..431.00 rows=1 width=5)
+   ->  Dynamic Seq Scan on pt_bool_tab  (cost=0.00..431.00 rows=1 width=5)
+         Number of partitions to scan: 1 (out of 2)
+         Filter: (col2 IS NOT FALSE)
+ Optimizer: Pivotal Optimizer (GPORCA)
+(5 rows)
+
+SELECT * FROM pt_bool_tab WHERE col2 IS NOT false;
+ col1 | col2 
+------+------
+    2 | t
+    3 | t
+    1 | t
+(3 rows)
+
+EXPLAIN SELECT * FROM pt_bool_tab WHERE col2 IS NOT unknown;
+                                  QUERY PLAN                                  
+------------------------------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)  (cost=0.00..431.00 rows=1 width=5)
+   ->  Dynamic Seq Scan on pt_bool_tab  (cost=0.00..431.00 rows=1 width=5)
+         Number of partitions to scan: 2 (out of 2)
+         Filter: (col2 IS NOT UNKNOWN)
+ Optimizer: Pivotal Optimizer (GPORCA)
+(5 rows)
+
+SELECT * FROM pt_bool_tab WHERE col2 IS NOT unknown;
+ col1 | col2 
+------+------
+    1 | f
+    1 | t
+    2 | f
+    2 | t
+    3 | t
+(5 rows)
+
+EXPLAIN SELECT * FROM pt_bool_tab WHERE col2 IS NOT NULL;
+                                  QUERY PLAN                                  
+------------------------------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)  (cost=0.00..431.00 rows=1 width=5)
+   ->  Dynamic Seq Scan on pt_bool_tab  (cost=0.00..431.00 rows=1 width=5)
+         Number of partitions to scan: 2 (out of 2)
+         Filter: (NOT (col2 IS NULL))
+ Optimizer: Pivotal Optimizer (GPORCA)
+(5 rows)
+
+SELECT * FROM pt_bool_tab WHERE col2 IS NOT NULL;
+ col1 | col2 
+------+------
+    1 | f
+    1 | t
+    2 | f
+    2 | t
+    3 | t
+(5 rows)
+
+CREATE TABLE pt_bool_tab_df
+(
+  col1 int,
+  col2 bool
+)
+distributed by (col1)
+partition by list(col2)
+(
+  partition part1 values(true),
+  partition part2 values(false),
+  default partition def
+);
+INSERT INTO pt_bool_tab_df SELECT i, true FROM generate_series(1,3)i;
+INSERT INTO pt_bool_tab_df SELECT i, false FROM generate_series(1,2)i;
+INSERT INTO pt_bool_tab_df SELECT i, NULL FROM generate_series(1,1)i;
+EXPLAIN SELECT * FROM pt_bool_tab_df WHERE col2 IS true;
+                                  QUERY PLAN                                  
+------------------------------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)  (cost=0.00..431.00 rows=1 width=5)
+   ->  Dynamic Seq Scan on pt_bool_tab_df  (cost=0.00..431.00 rows=1 width=5)
+         Number of partitions to scan: 1 (out of 3)
+         Filter: (col2 IS TRUE)
+ Optimizer: Pivotal Optimizer (GPORCA)
+(5 rows)
+
+SELECT * FROM pt_bool_tab_df WHERE col2 IS true;
+ col1 | col2 
+------+------
+    1 | t
+    2 | t
+    3 | t
+(3 rows)
+
+EXPLAIN SELECT * FROM pt_bool_tab_df WHERE col2 IS false;
+                                  QUERY PLAN                                  
+------------------------------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)  (cost=0.00..431.00 rows=1 width=5)
+   ->  Dynamic Seq Scan on pt_bool_tab_df  (cost=0.00..431.00 rows=1 width=5)
+         Number of partitions to scan: 1 (out of 3)
+         Filter: (col2 IS FALSE)
+ Optimizer: Pivotal Optimizer (GPORCA)
+(5 rows)
+
+SELECT * FROM pt_bool_tab_df WHERE col2 IS false;
+ col1 | col2 
+------+------
+    2 | f
+    1 | f
+(2 rows)
+
+EXPLAIN SELECT * FROM pt_bool_tab_df WHERE col2 IS NULL;
+                                  QUERY PLAN                                  
+------------------------------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)  (cost=0.00..431.00 rows=1 width=5)
+   ->  Dynamic Seq Scan on pt_bool_tab_df  (cost=0.00..431.00 rows=1 width=5)
+         Number of partitions to scan: 1 (out of 3)
+         Filter: (col2 IS NULL)
+ Optimizer: Pivotal Optimizer (GPORCA)
+(5 rows)
+
+SELECT * FROM pt_bool_tab_df WHERE col2 IS NULL;
+ col1 | col2 
+------+------
+    1 | 
+(1 row)
+
+EXPLAIN SELECT * FROM pt_bool_tab_df WHERE col2 IS unknown;
+                                  QUERY PLAN                                  
+------------------------------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)  (cost=0.00..431.00 rows=1 width=5)
+   ->  Dynamic Seq Scan on pt_bool_tab_df  (cost=0.00..431.00 rows=1 width=5)
+         Number of partitions to scan: 3 (out of 3)
+         Filter: (col2 IS UNKNOWN)
+ Optimizer: Pivotal Optimizer (GPORCA)
+(5 rows)
+
+SELECT * FROM pt_bool_tab_df WHERE col2 IS unknown;
+ col1 | col2 
+------+------
+    1 | 
+(1 row)
+
+EXPLAIN SELECT * FROM pt_bool_tab_df WHERE col2 IS NOT true;
+                                  QUERY PLAN                                  
+------------------------------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)  (cost=0.00..431.00 rows=1 width=5)
+   ->  Dynamic Seq Scan on pt_bool_tab_df  (cost=0.00..431.00 rows=1 width=5)
+         Number of partitions to scan: 2 (out of 3)
+         Filter: (col2 IS NOT TRUE)
+ Optimizer: Pivotal Optimizer (GPORCA)
+(5 rows)
+
+SELECT * FROM pt_bool_tab_df WHERE col2 IS NOT true;
+ col1 | col2 
+------+------
+    2 | f
+    1 | f
+    1 | 
+(3 rows)
+
+EXPLAIN SELECT * FROM pt_bool_tab_df WHERE col2 IS NOT false;
+                                  QUERY PLAN                                  
+------------------------------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)  (cost=0.00..431.00 rows=1 width=5)
+   ->  Dynamic Seq Scan on pt_bool_tab_df  (cost=0.00..431.00 rows=1 width=5)
+         Number of partitions to scan: 2 (out of 3)
+         Filter: (col2 IS NOT FALSE)
+ Optimizer: Pivotal Optimizer (GPORCA)
+(5 rows)
+
+SELECT * FROM pt_bool_tab_df WHERE col2 IS NOT false;
+ col1 | col2 
+------+------
+    2 | t
+    3 | t
+    1 | t
+    1 | 
+(4 rows)
+
+EXPLAIN SELECT * FROM pt_bool_tab_df WHERE col2 IS NOT unknown;
+                                  QUERY PLAN                                  
+------------------------------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)  (cost=0.00..431.00 rows=1 width=5)
+   ->  Dynamic Seq Scan on pt_bool_tab_df  (cost=0.00..431.00 rows=1 width=5)
+         Number of partitions to scan: 3 (out of 3)
+         Filter: (col2 IS NOT UNKNOWN)
+ Optimizer: Pivotal Optimizer (GPORCA)
+(5 rows)
+
+SELECT * FROM pt_bool_tab_df WHERE col2 IS NOT unknown;
+ col1 | col2 
+------+------
+    2 | f
+    2 | t
+    3 | t
+    1 | f
+    1 | t
+(5 rows)
+
+EXPLAIN SELECT * FROM pt_bool_tab_df WHERE col2 IS NOT NULL;
+                                  QUERY PLAN                                  
+------------------------------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)  (cost=0.00..431.00 rows=1 width=5)
+   ->  Dynamic Seq Scan on pt_bool_tab_df  (cost=0.00..431.00 rows=1 width=5)
+         Number of partitions to scan: 3 (out of 3)
+         Filter: (NOT (col2 IS NULL))
+ Optimizer: Pivotal Optimizer (GPORCA)
+(5 rows)
+
+SELECT * FROM pt_bool_tab_df WHERE col2 IS NOT NULL;
+ col1 | col2 
+------+------
+    2 | f
+    2 | t
+    3 | t
+    1 | f
+    1 | t
+(5 rows)
+
+CREATE TABLE pt_bool_tab_null
+(
+  col1 int,
+  col2 bool
+)
+distributed by (col1)
+partition by list(col2)
+(
+  partition part1 values(true),
+  partition part2 values(false),
+  partition part3 values(null)
+);
+INSERT INTO pt_bool_tab_null SELECT i, true FROM generate_series(1,3)i;
+INSERT INTO pt_bool_tab_null SELECT i, false FROM generate_series(1,2)i;
+INSERT INTO pt_bool_tab_null SELECT i, NULL FROM generate_series(1,1)i;
+EXPLAIN SELECT * FROM pt_bool_tab_null WHERE col2 IS true;
+                                   QUERY PLAN                                  
 
+--------------------------------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)  (cost=0.00..431.00 rows=1 width=5)
+   ->  Dynamic Seq Scan on pt_bool_tab_null  (cost=0.00..431.00 rows=1 width=5)
+         Number of partitions to scan: 1 (out of 3)
+         Filter: (col2 IS TRUE)
+ Optimizer: Pivotal Optimizer (GPORCA)
+(5 rows)
+
+SELECT * FROM pt_bool_tab_null WHERE col2 IS true;
+ col1 | col2 
+------+------
+    1 | t
+    2 | t
+    3 | t
+(3 rows)
+
+EXPLAIN SELECT * FROM pt_bool_tab_null WHERE col2 IS false;
+                                   QUERY PLAN                                  
 
+--------------------------------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)  (cost=0.00..431.00 rows=1 width=5)
+   ->  Dynamic Seq Scan on pt_bool_tab_null  (cost=0.00..431.00 rows=1 width=5)
+         Number of partitions to scan: 1 (out of 3)
+         Filter: (col2 IS FALSE)
+ Optimizer: Pivotal Optimizer (GPORCA)
+(5 rows)
+
+SELECT * FROM pt_bool_tab_null WHERE col2 IS false;
+ col1 | col2 
+------+------
+    1 | f
+    2 | f
+(2 rows)
+
+EXPLAIN SELECT * FROM pt_bool_tab_null WHERE col2 IS NULL;
+                                   QUERY PLAN                                  
 
+--------------------------------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)  (cost=0.00..431.00 rows=1 width=5)
+   ->  Dynamic Seq Scan on pt_bool_tab_null  (cost=0.00..431.00 rows=1 width=5)
+         Number of partitions to scan: 1 (out of 3)
+         Filter: (col2 IS NULL)
+ Optimizer: Pivotal Optimizer (GPORCA)
+(5 rows)
+
+SELECT * FROM pt_bool_tab_null WHERE col2 IS NULL;
+ col1 | col2 
+------+------
+    1 | 
+(1 row)
+
+EXPLAIN SELECT * FROM pt_bool_tab_null WHERE col2 IS unknown;
+                                   QUERY PLAN                                  
 
+--------------------------------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)  (cost=0.00..431.00 rows=1 width=5)
+   ->  Dynamic Seq Scan on pt_bool_tab_null  (cost=0.00..431.00 rows=1 width=5)
+         Number of partitions to scan: 3 (out of 3)
+         Filter: (col2 IS UNKNOWN)
+ Optimizer: Pivotal Optimizer (GPORCA)
+(5 rows)
+
+SELECT * FROM pt_bool_tab_null WHERE col2 IS unknown;
+ col1 | col2 
+------+------
+    1 | 
+(1 row)
+
+EXPLAIN SELECT * FROM pt_bool_tab_null WHERE col2 IS NOT true;
+                                   QUERY PLAN                                  
 
+--------------------------------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)  (cost=0.00..431.00 rows=1 width=5)
+   ->  Dynamic Seq Scan on pt_bool_tab_null  (cost=0.00..431.00 rows=1 width=5)
+         Number of partitions to scan: 2 (out of 3)
+         Filter: (col2 IS NOT TRUE)
+ Optimizer: Pivotal Optimizer (GPORCA)
+(5 rows)
+
+SELECT * FROM pt_bool_tab_null WHERE col2 IS NOT true;
+ col1 | col2 
+------+------
+    1 | f
+    2 | f
+    1 | 
+(3 rows)
+
+EXPLAIN SELECT * FROM pt_bool_tab_null WHERE col2 IS NOT false;
+                                   QUERY PLAN                                  
 
+--------------------------------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)  (cost=0.00..431.00 rows=1 width=5)
+   ->  Dynamic Seq Scan on pt_bool_tab_null  (cost=0.00..431.00 rows=1 width=5)
+         Number of partitions to scan: 2 (out of 3)
+         Filter: (col2 IS NOT FALSE)
+ Optimizer: Pivotal Optimizer (GPORCA)
+(5 rows)
+
+SELECT * FROM pt_bool_tab_null WHERE col2 IS NOT false;
+ col1 | col2 
+------+------
+    2 | t
+    3 | t
+    1 | t
+    1 | 
+(4 rows)
+
+EXPLAIN SELECT * FROM pt_bool_tab_null WHERE col2 IS NOT unknown;
+                                   QUERY PLAN                                  
 
+--------------------------------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)  (cost=0.00..431.00 rows=1 width=5)
+   ->  Dynamic Seq Scan on pt_bool_tab_null  (cost=0.00..431.00 rows=1 width=5)
+         Number of partitions to scan: 3 (out of 3)
+         Filter: (col2 IS NOT UNKNOWN)
+ Optimizer: Pivotal Optimizer (GPORCA)
+(5 rows)
+
+SELECT * FROM pt_bool_tab_null WHERE col2 IS NOT unknown;
+ col1 | col2 
+------+------
+    2 | f
+    2 | t
+    3 | t
+    1 | f
+    1 | t
+(5 rows)
+
+EXPLAIN SELECT * FROM pt_bool_tab_null WHERE col2 IS NOT NULL;
+                                   QUERY PLAN                                  
 
+--------------------------------------------------------------------------------
+ Gather Motion 3:1  (slice1; segments: 3)  (cost=0.00..431.00 rows=1 width=5)
+   ->  Dynamic Seq Scan on pt_bool_tab_null  (cost=0.00..431.00 rows=1 width=5)
+         Number of partitions to scan: 2 (out of 3)
+         Filter: (NOT (col2 IS NULL))
+ Optimizer: Pivotal Optimizer (GPORCA)
+(5 rows)
+
+SELECT * FROM pt_bool_tab_null WHERE col2 IS NOT NULL;
+ col1 | col2 
+------+------
+    2 | f
+    2 | t
+    3 | t
+    1 | f
+    1 | t
+(5 rows)
+
 RESET ALL;
diff --git a/src/test/regress/expected/qp_targeted_dispatch_optimizer.out 
b/src/test/regress/expected/qp_targeted_dispatch_optimizer.out
index abf4565f51..330476105d 100644
--- a/src/test/regress/expected/qp_targeted_dispatch_optimizer.out
+++ b/src/test/regress/expected/qp_targeted_dispatch_optimizer.out
@@ -183,7 +183,7 @@ INFO:  (slice 0) Dispatch command to ALL contents: 0 1 2
 INFO:  Distributed transaction command 'Distributed Prepare' to ALL contents: 
0 1 2
 INFO:  Distributed transaction command 'Distributed Commit Prepared' to ALL 
contents: 0 1 2
 select * from boolean where boo='t' and b=2;
-INFO:  (slice 1) Dispatch command to ALL contents: 0 1 2
+INFO:  (slice 1) Dispatch command to SINGLE content
  boo | b 
 -----+---
  t   | 2
diff --git a/src/test/regress/sql/partition_pruning.sql 
b/src/test/regress/sql/partition_pruning.sql
index 8a5197c63b..51517b3c55 100644
--- a/src/test/regress/sql/partition_pruning.sql
+++ b/src/test/regress/sql/partition_pruning.sql
@@ -895,4 +895,106 @@ select get_selected_parts('explain analyze select * from 
bar where j is distinct
 -- 8 parts: NULL is shared with others on p1. So, all 8 parts.
 select get_selected_parts('explain analyze select * from bar where j is 
distinct from NULL;');
 
+
+-- Table partitioned by boolean column
+CREATE TABLE pt_bool_tab
+(
+  col1 int,
+  col2 bool
+)
+distributed by (col1)
+partition by list(col2)
+(
+  partition part1 values(true),
+  partition part2 values(false)
+);
+
+INSERT INTO pt_bool_tab SELECT i, true FROM generate_series(1,3)i;
+INSERT INTO pt_bool_tab SELECT i, false FROM generate_series(1,2)i;
+
+EXPLAIN SELECT * FROM pt_bool_tab WHERE col2 IS true;
+SELECT * FROM pt_bool_tab WHERE col2 IS true;
+EXPLAIN SELECT * FROM pt_bool_tab WHERE col2 IS false;
+SELECT * FROM pt_bool_tab WHERE col2 IS false;
+EXPLAIN SELECT * FROM pt_bool_tab WHERE col2 IS NULL;
+SELECT * FROM pt_bool_tab WHERE col2 IS NULL;
+EXPLAIN SELECT * FROM pt_bool_tab WHERE col2 IS unknown;
+SELECT * FROM pt_bool_tab WHERE col2 IS unknown;
+EXPLAIN SELECT * FROM pt_bool_tab WHERE col2 IS NOT true;
+SELECT * FROM pt_bool_tab WHERE col2 IS NOT true;
+EXPLAIN SELECT * FROM pt_bool_tab WHERE col2 IS NOT false;
+SELECT * FROM pt_bool_tab WHERE col2 IS NOT false;
+EXPLAIN SELECT * FROM pt_bool_tab WHERE col2 IS NOT unknown;
+SELECT * FROM pt_bool_tab WHERE col2 IS NOT unknown;
+EXPLAIN SELECT * FROM pt_bool_tab WHERE col2 IS NOT NULL;
+SELECT * FROM pt_bool_tab WHERE col2 IS NOT NULL;
+
+CREATE TABLE pt_bool_tab_df
+(
+  col1 int,
+  col2 bool
+)
+distributed by (col1)
+partition by list(col2)
+(
+  partition part1 values(true),
+  partition part2 values(false),
+  default partition def
+);
+
+INSERT INTO pt_bool_tab_df SELECT i, true FROM generate_series(1,3)i;
+INSERT INTO pt_bool_tab_df SELECT i, false FROM generate_series(1,2)i;
+INSERT INTO pt_bool_tab_df SELECT i, NULL FROM generate_series(1,1)i;
+
+EXPLAIN SELECT * FROM pt_bool_tab_df WHERE col2 IS true;
+SELECT * FROM pt_bool_tab_df WHERE col2 IS true;
+EXPLAIN SELECT * FROM pt_bool_tab_df WHERE col2 IS false;
+SELECT * FROM pt_bool_tab_df WHERE col2 IS false;
+EXPLAIN SELECT * FROM pt_bool_tab_df WHERE col2 IS NULL;
+SELECT * FROM pt_bool_tab_df WHERE col2 IS NULL;
+EXPLAIN SELECT * FROM pt_bool_tab_df WHERE col2 IS unknown;
+SELECT * FROM pt_bool_tab_df WHERE col2 IS unknown;
+EXPLAIN SELECT * FROM pt_bool_tab_df WHERE col2 IS NOT true;
+SELECT * FROM pt_bool_tab_df WHERE col2 IS NOT true;
+EXPLAIN SELECT * FROM pt_bool_tab_df WHERE col2 IS NOT false;
+SELECT * FROM pt_bool_tab_df WHERE col2 IS NOT false;
+EXPLAIN SELECT * FROM pt_bool_tab_df WHERE col2 IS NOT unknown;
+SELECT * FROM pt_bool_tab_df WHERE col2 IS NOT unknown;
+EXPLAIN SELECT * FROM pt_bool_tab_df WHERE col2 IS NOT NULL;
+SELECT * FROM pt_bool_tab_df WHERE col2 IS NOT NULL;
+
+
+CREATE TABLE pt_bool_tab_null
+(
+  col1 int,
+  col2 bool
+)
+distributed by (col1)
+partition by list(col2)
+(
+  partition part1 values(true),
+  partition part2 values(false),
+  partition part3 values(null)
+);
+INSERT INTO pt_bool_tab_null SELECT i, true FROM generate_series(1,3)i;
+INSERT INTO pt_bool_tab_null SELECT i, false FROM generate_series(1,2)i;
+INSERT INTO pt_bool_tab_null SELECT i, NULL FROM generate_series(1,1)i;
+
+EXPLAIN SELECT * FROM pt_bool_tab_null WHERE col2 IS true;
+SELECT * FROM pt_bool_tab_null WHERE col2 IS true;
+EXPLAIN SELECT * FROM pt_bool_tab_null WHERE col2 IS false;
+SELECT * FROM pt_bool_tab_null WHERE col2 IS false;
+EXPLAIN SELECT * FROM pt_bool_tab_null WHERE col2 IS NULL;
+SELECT * FROM pt_bool_tab_null WHERE col2 IS NULL;
+EXPLAIN SELECT * FROM pt_bool_tab_null WHERE col2 IS unknown;
+SELECT * FROM pt_bool_tab_null WHERE col2 IS unknown;
+EXPLAIN SELECT * FROM pt_bool_tab_null WHERE col2 IS NOT true;
+SELECT * FROM pt_bool_tab_null WHERE col2 IS NOT true;
+EXPLAIN SELECT * FROM pt_bool_tab_null WHERE col2 IS NOT false;
+SELECT * FROM pt_bool_tab_null WHERE col2 IS NOT false;
+EXPLAIN SELECT * FROM pt_bool_tab_null WHERE col2 IS NOT unknown;
+SELECT * FROM pt_bool_tab_null WHERE col2 IS NOT unknown;
+EXPLAIN SELECT * FROM pt_bool_tab_null WHERE col2 IS NOT NULL;
+SELECT * FROM pt_bool_tab_null WHERE col2 IS NOT NULL;
+
 RESET ALL;


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to