public inbox for [email protected]
help / color / mirror / Atom feedFrom: ro b <[email protected]>
To: pgsql-hackers <[email protected]>
Subject: Self contradictory examining on rel's baserestrictinfo
Date: Mon, 25 Nov 2024 08:58:04 +0000
Message-ID: <TYCPR01MB6093E2A06F3F8CF8DF17B5CE852E2@TYCPR01MB6093.jpnprd01.prod.outlook.com> (raw)
Hi,
I committed the major features of self-contradictory examining patches.
I'd like to explain it in the following aspects.
1. Background
A few months ago, when i read source codes of B-tree in routine
_bt_preprocess_keys, i found that there are more contradictory
checking case we can add. I sent email to pgsql-hackers and
then community contributor replied me and told me someone had
already proposed this question. Thanks for taking the time
to address my question. After serveral conversations, i found
that we can do something more. We can place these jobs at planning time.
2. Under the frame
In practice, B-tree index is used widely; Binary operation expression
that Var op Const is often written; Also without data type coercion
and collation. So features above are supported.
There are several considerations 1) self-contradictory situation
is seldom appeared. 2) It's much expensive if spend too much effort
on it and find that rel is not self-contradictory. 3) The expression
evaluation mechanism will do the right things finally. So this is
a compromise.
3. Detailes
We will get the base restrictinfo list after deconstructed jointree.
1) The baserestrictinfo is a AND-implict list, that mean if one element
of the list is contradictory to others or self-contradictory the whole
rel is self-contradictory, then we can mark the rel is dummy.
2) The stragegy operators(>,>=,=,<,<=) of B-tree, some of them may be
contradictory to others. Another operator need to be considered is <>
the negator of =.
2.1) = against >, >=, =, <, <=, <>
2.2) >, >= against <, <=
3) We can eliminate the weaker restrictive operator if there is a more
restrictive operator (eg. x > 4 and x >=5, the sub-expression x > 4 will
be abandoned). This will simplify the subsequent examining.
A special situation we need to care about is if we encounter operator '='
and there is not contradictory, the operator '=' will dominate the others
operators.
4) We need to record down the details when we encounter the operator '<>'
and then check them oen by one if then operator '=' appear.
I use linear searching when the number of elements is less than or equal 4
or we can't find a support function to sort these elements.
If we find a support function and the number of elements is greater than 4,
sort these elements and use binary searching.
I choose number 4 here for two considerations. 1) the type size of storing
the const value multiply 4 match a cpu cache line usually. 2) In practice
we will not write down much not equal expressions generally.
5) NULL test
When IS NULL is set, it's contradictory to IS NOT NULL obviously.
And it's contradictory to operator that imply IS NOT NULL implictly.
If we find one of these operators ( >,>=,=,<,<=,<> ) and the expression with
the operator make sense (eg. NULL is not in expression) then we can recognize
this situation is contradictory to IS NULL test.
6) Boolean type
Boolean type is a little tricky, because it can evaluate with both of
test and opreator.
When we encounter the operator one of =, <> or expression is a single
Var or NOT Boolexpr with a single Var. We need to extract details to
make a test format (eg. x = true to x is true; x <> not false to x is false.)
When Var is set with IS_TRUE, this is contradictory to IS_NOT_TRUE,
IS_FALSE and IS_UNKNOWN.
When Var is set with IS_FALSE, this is contradictory to IS_TRUE,
IS_NOT_FALSE and IS_UNKNOWN.
When Var is set with IS_UNKNOWN, this is contradictory to IS_NOT_UNKNOWN,
IS_TRUE and IS_FALSE.
When the NULL test and self test of of boolean type are both appeared.
If IS NULL is set it's contradictory to IS TRUE, IS FALSE, IS NOT
UNKNOWN; If IS NOT NULL is set it's contradictory to IS UNKNOWN.
Finally we need check them carefully when strategy operator appear.
If we found boolean expression is written like x > true or x < false,
it's beyond the scope of the defined values of boolean type, the expression
does not make sense obviously.
If IS_UNKNOWN is set and it's contradictory to stragegy operator.
If IS_NOT_FALSE is set, that means the equivalent expression is (eg. x IS
NULL OR x IS TRUE). The NULL test will always fail with the strategy operator,
so we only need to test whether the sub-expression (x IS TRUE) is
contradictory with the strategy operator. If IS_NOT_TRUE is set, it's
similar to IS_NOT_FALSE.
7) Scalar array comparison expression
First we need to deconstruct the const array, figure out the null and non-null
elements.
If ALL flag is set and the Const contain NULL. we will get nothing (eg. x <=
ALL(array[56, null])), it's contradictory.
Then sort the non-null elements and eliminate any duplicates. We will give up
if we can't get the sorting support function.
1. Expression with operator <>
We can examine them one by one if ALL flag is set, it's similar to the common
expression (eg. x <> 2 and x <> 3);
If ANY flag is set and the number of sorted elements is only one, we can convert
the scalar array expression to a binary operator expression, but we can't do
anything else if there are more than one elements.
2. Expression with one of these operators >,>=,<,<=
We just need check the boundary element (eg. x > ALL(array[1,2,3]) it's equal
to x > 3) and convert expression to the equivalent binary operator expression.
3. Expression with operator =
We treat it as a binary operator expression if the number of sorted elements
is only one;
When the number of sorted elements is more than one.
It is contradictory if ALL flag is set.
If ANY flag is set, we need to postpone them before the collection of same type
expression is completed (eg. x in(1,3) and x in(1,5) we can extract the same
value 1 when we collected all of these expression over). Then we check
the intersection elements.
8) Row comparison expression
We need convert row comparison to nonconstructor.
The operator <> and = have already done in analysis phase. So we just need
to take care of one of operators <, <=, > and >=.
The basic rules for evaluating a row comparison expression is the row elements
are compared left-to-right, stopping as soon as an unequal or null pair
of elements is found.
Let us ignore the NULL that may appear in the row comparison expression
temporarily, the logic of deconstructing row comparison expression is like:
ROW(a1, a2, ..., an) >= ROW(b1, b2, ..., bn)
Normal format:
(a1 > b1)
OR (a1 = b1 AND a2 > b2)
OR (a1 = b1 AND a2 = b2 AND a3 > b3)
...
OR (a1 = b1 AND a2 = b2 AND ... AND an >= bn)
The difference between operators in row comparison expression is the more
restrictive operator is used in last sub-condition of every sub-OR expression
(eg. a3 > b3 the more restrictive > is used), but the operator of last
sub-condition (an >= bn) of the last sub-OR expression is according to the
operator of row comparison expression.
We get two regulations:
1. operator '=' is used in every sub-condition except the last one in
every sub-OR expression or the sub-OR expression had no equal sub-condition.
So we can record down the equal sub-condition with a list(i called it
sub-condition-list) and then we will iterate the list to generating
sub-conditions for subsequent sub-OR expression when we meet a new pair
of elements.
2. The more restrictive operator is used in last sub-condition of
every sub-OR expression except the last sub-OR expression. row expression's
operator weill be used int he last sub-condition of last sub-OR expression.
It's time to face the special cases now.
1. NULL value.
If either of this pair of elements is null, we can skip the evaluation of
subsequent elements, but if the NULL come out at first position then the
whole expression will supply nothing.
For example ROW(a,NULL,c) > (1,2,3)
normal format:
a > 1
or a = 1 and NULL > 2
or a = 1 and NULL = 2 and c > 3
The sub-OR expression doesn't make sense if NULL in sub-condition. So the
final converted expression is a > 1.
2. Pairs of elements are equal.
When they contain volatile functions, we will give up and just return back.
If they are not Const that mean element IS NOT NULL. We need add the NULL
test to the sub-condition-list for generating subsequent sub-OR expression.
It's need to ignore them if they are Const, so we don't add it to the
sub-condition-list.
We skip the current sub-OR expression generating, but if the pair of elements
come out at the last position we need be carefull.
If the operator of row comparison expression is a more restrictive operator,
we skip the last sub-OR expression generating, but if the operator is weaker
we need to generate the last sub-OR expression.
For examples:
ROW(a,b,c) > (1,b,3) ROW(a,2,c) > (1,2,3)
normal format: normal format:
a > 1 a > 1
or a = 1 and b > b or a = 1 and 2 > 2
or a = 1 and b = b and c > 3 or a = 1 and 2 = 2 and c > 3
The final expression is The final expression is
a > 1 a > 1
or a = 1 and b IS NOT NULL and c > 3 or a = 1 and c > 3
ROW(a,b,c) > (1,2,c) ROW(a,b,c) >= (1,2,c)
normal format: normal format:
a > 1 a > 1
or a = 1 and b > 2 or a = 1 and b > 2
or a = 1 and b = 2 and c > c or a = 1 and b = 2 and c >= c
The final expression is The final expression is
a > 1 a > 1
or a = 1 and b > 2 or a = 1 and b > 2
or a = 1 and b = 2 and c is not null
If case 1 and 2 are both appeared in row expression.
We will skip the subsequent pairs of elements when we meet the NULL.
So it just needs to be considered case 2 is in front of 1.
A special situation is all of pairs of elements are equal before we
meet NULL, according to the rule of case 2 we don't generate current
sub-OR expression if meet a pairs of elements these are equal.
So the nonconstructor is empty and we need a flag to know the result of
evaluation of the last pair of elements, then the result of row expression
is according to the flag.
3. Pairs of elements are Const but not equal.
Seeing the above normal format, there is no need to generate sub-OR
expression for the subsequent pairs of elements if we meet the pair of
elements they are Const but not equal.
But whether it's need to generate the current sub-OR expression or not is
according to the reulst of evaluation of current pair of elements.
If the reulst is positive we need to generate the sub-OR expression or
do nothing.
If the pair of elements come out at the first position, then the result
of row comparison expression is according to result of the pair of elements.
If the result is positive, the reuslt of row comparison expression is
positive.
Another situation is all of pairs of elements are equal before we meet
the not equal pair of elements, it's similar to what we discussed in case 2.
We will get a OR-expression finally. Then we can do the examining jobs and
prune the OR-expression, we only keep the output expression that is a simple
expression. The OR-format is not better than row expression for subsequent
processing. If we need watch the output OR-expression we should add macro
DEBUG_ROW_DECODE when configure our environment.
9) OR-expression
We need postpone OR-expression if we meet it. Because we can push other
expressions these have the same semantic level with OR-expression down into
the OR-expression. Then we can check every sub-expression with the pushed
down details.
we will abandon the sub-expression if we find the sub-expression is
contradictory.
when all of the sub-expressions are contradictory that mean the OR-expression
is contradictory.
A special situation is once we find a sub-expression is const true and then
the OR-expression is const true.
For example: x > 10 and (x < 9 or y > 10) in the expression we push x > 10
down into the OR-expression, then we will find the sub-expression x < 9 is
contradictory to x > 10 and x < 9 will be abandoned, so the final expression
is x > 10 AND y > 10.
10) EC situation
We may get a clause match the EC mechanism after we finished the all jobs.
For example: x > 10 and (x < 9 or y = 10) we will get the expression y = 10
match the EC, so we need add it into the EC.
11) The phase 2 examining
As we know in the case 10, if we add a ec and we may get a contradictory case
after the generate_base_implied_equalities invoked. So we need to recheck the
rel when rel's baserestrictinfo added clauses.
For example: select * from self_a x join self_a y on x.a= y.a where x.a in
(2,3,45) and x.a in (45, 78) and y.a <> 45
we will get the intersection element 45 and convert
(x.a in (2,3,45) and x.a in (45, 78)) to x.a = 45, then add it into EC.
We will get the generated clause y.a = 45 after
generate_base_implied_equalities invoked, it's contradictory to y.a <>45,
so alias y is self-contradictory finally.
Best regards
Attachments:
[application/octet-stream] patch.diff (78.6K, ../TYCPR01MB6093E2A06F3F8CF8DF17B5CE852E2@TYCPR01MB6093.jpnprd01.prod.outlook.com/3-patch.diff)
download | inline diff:
From e94d26d35ea8e6ff9c69576bb31e10248eb29805 Mon Sep 17 00:00:00 2001
From: wq <[email protected]>
Date: Mon, 25 Nov 2024 16:27:34 +0800
Subject: [PATCH] Self contradictory examining on rel's baserestrictinfo
---
src/backend/optimizer/plan/Makefile | 3 +-
src/backend/optimizer/plan/contradictory.c | 2640 ++++++++++++++++++++
src/backend/optimizer/plan/initsplan.c | 16 +-
src/backend/optimizer/plan/meson.build | 1 +
src/backend/optimizer/plan/planmain.c | 4 +
src/backend/utils/cache/lsyscache.c | 39 +
src/include/nodes/pathnodes.h | 7 +
src/include/optimizer/planmain.h | 2 +
src/include/utils/lsyscache.h | 3 +
9 files changed, 2711 insertions(+), 4 deletions(-)
create mode 100644 src/backend/optimizer/plan/contradictory.c
diff --git a/src/backend/optimizer/plan/Makefile b/src/backend/optimizer/plan/Makefile
index 80ef162e48..36ba23664a 100644
--- a/src/backend/optimizer/plan/Makefile
+++ b/src/backend/optimizer/plan/Makefile
@@ -20,6 +20,7 @@ OBJS = \
planmain.o \
planner.o \
setrefs.o \
- subselect.o
+ subselect.o \
+ contradictory.o
include $(top_srcdir)/src/backend/common.mk
diff --git a/src/backend/optimizer/plan/contradictory.c b/src/backend/optimizer/plan/contradictory.c
new file mode 100644
index 0000000000..a58a825b32
--- /dev/null
+++ b/src/backend/optimizer/plan/contradictory.c
@@ -0,0 +1,2640 @@
+/*-------------------------------------------------------------------------
+ *
+ * initsplan.c
+ * Target list, qualification, joininfo initialization routines
+ *
+ * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * src/backend/optimizer/plan/contradictory.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "nodes/nodeFuncs.h"
+#include "nodes/makefuncs.h"
+#include "utils/lsyscache.h"
+#include "utils/rel.h"
+#include "utils/typcache.h"
+#include "utils/array.h"
+#include "access/nbtree.h"
+#include "lib/qunique.h"
+#include "common/int.h"
+#include "optimizer/restrictinfo.h"
+#include "optimizer/paths.h"
+
+/*
+ * Self-contradictory definations
+ *
+ */
+#define DEFAULT_ELEMS_NUM 4
+#define STRATEGY_NOT_EQUAL (BTMaxStrategyNumber + 1) /* operator '<>' */
+
+typedef enum ClauseCxtType
+{
+ CCT_DEL,
+ CCT_CONSTT, /* Evaluated expr is const and true. */
+ CCT_CONSTF, /* Evaluated expr is const and false. */
+ CCT_REPLACE
+}ClauseCxtType;
+
+#define NT_MARK (1<<7)
+#define NT_IS_NULL (1<<IS_NULL)
+#define NT_IS_NOT_NULL (1<<IS_NOT_NULL)
+
+/* Boolean test definations. */
+#define BT_MARK (1<<7)
+#define BT_IS_TRUE (1<<IS_TRUE)
+#define BT_IS_NOT_TRUE (1<<IS_NOT_TRUE)
+#define BT_IS_FALSE (1<<IS_FALSE)
+#define BT_IS_NOT_FALSE (1<<IS_NOT_FALSE)
+#define BT_IS_UNKNOWN (1<<IS_UNKNOWN)
+#define BT_IS_NOT_UNKNOWN (1<<IS_NOT_UNKNOWN)
+
+typedef struct ConstVal
+{
+ bool push_down;
+ uint16 strategy;
+ uint32 idx;
+ Expr *expr;
+ Datum *value;
+ FmgrInfo op_func;
+}ConstVal;
+
+typedef struct SAEqualDatElem
+{
+ uint32 idx;
+ int elem_nums;
+ Expr *expr;
+ Datum *elem_values;
+}SAEqualDatElem;
+
+typedef struct SortArrayContext
+{
+ FmgrInfo sortproc;
+ Oid collation;
+ Oid elmtype;
+ int16 elmlen;
+ bool elmbyval;
+ char elmalign;
+ bool reverse;
+} SortArrayContext;
+
+typedef struct SortNeConstCxt
+{
+ FmgrInfo cmp_proc;
+ Oid collation;
+ bool reverse;
+} SortNeConstCxt;
+
+typedef struct SAEqualDat
+{
+ RegProcedure opfuncid;
+ SortArrayContext sortcxt;
+ List *upper_elems;
+ List *elemnents; /* Type of SAEqualDatElem. */
+}SAEqualDat;
+
+typedef struct NeConstDat
+{
+ uint32 idx;
+ Datum *val;
+}NeConstDat;
+
+typedef struct NeConstVal
+{
+ SortNeConstCxt sncc;
+ bool can_sort;
+ bool sorted;
+ FmgrInfo op_func;
+ int size;
+ int capacity;
+ NeConstDat *ncds;
+ struct NeConstVal *upper_ncv;
+}NeConstVal;
+
+typedef struct VarattInfo
+{
+ uint8 stratcount;
+ uint8 null_test;
+ uint8 bool_test;
+ uint16 atidx;
+ Oid collid;
+ Oid type;
+ NeConstVal ne_const;
+ SAEqualDat saop;
+ ConstVal st_table[BTMaxStrategyNumber];
+ struct VarattInfo *next;
+}VarattInfo;
+
+typedef struct RowCompElem
+{
+ Oid opid;
+ Oid stricter_opid;
+ Expr *contact;
+}RowCompElem;
+
+typedef struct ExtractedAttris
+{
+ bool addOp;
+ AttrNumber min_attr;
+ VarattInfo **array_vi;
+ VarattInfo *att_lst;
+ VarattInfo *last;
+ struct ExtractedAttris *upper_ea;
+}ExtractedAttris;
+
+typedef struct ClauseContext
+{
+ ClauseCxtType cct;
+ uint32 idx;
+ Expr *origin;
+ void *cxt;
+}ClauseContext;
+
+typedef struct ClauseCxtWapper
+{
+ List *clausecxt; /* Type of ClauseContext. */
+}ClauseCxtWapper;
+
+typedef struct AttrOpFamily
+{
+ Oid negator;
+ Oid opfamily;
+}AttrOpFamily;
+
+typedef struct AttrOpFamilySet
+{
+ AttrOpFamily elems[DEFAULT_ELEMS_NUM];
+ struct AttrOpFamilySet *next;
+}AttrOpFamilySet;
+
+
+typedef struct AttrsDetailsCache
+{
+ AttrNumber min_attr;
+ AttrNumber max_attr;
+ int len_set; /* The number of current AttrOpFamilySet elements used. */
+ AttrOpFamily **atop_array;
+ AttrOpFamilySet *atop_set;
+}AttrsDetailsCache;
+
+typedef struct OpcInfoElement
+{
+ Oid opcid;
+ Oid opcfamily;
+ Oid opcintype;
+}OpcInfoElement;
+
+typedef struct SortedOpclassInfo
+{
+ int n_members;
+ OpcInfoElement **opcies;
+}SortedOpclassInfo;
+
+typedef struct SelfExamContext
+{
+ SortedOpclassInfo sopcinfo;
+ AttrsDetailsCache attrsdc;
+ ClauseContext *ccfree;
+ VarattInfo *vifree;
+}SelfExamContext;
+
+#define EXAMINE_ABORT(x) \
+do{ \
+ ret = x; \
+ goto finished; \
+}while(0)
+
+extern void check_mergejoinable(RestrictInfo *restrictinfo);
+extern bool contain_volatile_functions(Node *clause);
+void examine_self_contradictory_rels_phase1(PlannerInfo *root);
+void examine_self_contradictory_rels_phase2(PlannerInfo *root);
+
+static inline ClauseContext* get_clause_cxt_internal(SelfExamContext *sec)
+{
+ ClauseContext *ccxt;
+ if (sec->ccfree)
+ {
+ ccxt = sec->ccfree;
+ sec->ccfree = (ClauseContext*) ccxt->cxt;
+ ccxt->cxt = NULL;
+ ccxt->origin = NULL;
+ }
+ else
+ ccxt = palloc0(sizeof(ClauseContext));
+
+ return ccxt;
+}
+
+static inline void free_clause_cxt_internal(SelfExamContext *sec, ClauseContext *cc)
+{
+ if (sec->ccfree)
+ {
+ cc->cxt = sec->ccfree;
+ sec->ccfree = cc;
+ }
+ else
+ {
+ cc->cxt = NULL;
+ sec->ccfree = cc;
+ }
+}
+
+static inline VarattInfo* get_attinfo_cxt_internal(SelfExamContext *sec)
+{
+ VarattInfo *varatt;
+ if (sec->vifree)
+ {
+ varatt = sec->vifree;
+ sec->vifree = varatt->next;
+ varatt->next = NULL;
+ }
+ else
+ varatt = palloc0(sizeof(VarattInfo));
+
+ return varatt;
+}
+
+static inline void free_attinfo_cxt_internal(SelfExamContext *sec, VarattInfo *atinfo)
+{
+ if (sec->vifree)
+ {
+ atinfo->next = sec->vifree;
+ sec->vifree = atinfo;
+ }
+ else
+ {
+ atinfo->next = NULL;
+ sec->vifree = atinfo;
+ }
+}
+
+
+static inline AttrOpFamily* get_atop_element_internal(AttrsDetailsCache *attrsdc)
+{
+ AttrOpFamilySet *atops;
+ if (attrsdc->len_set == DEFAULT_ELEMS_NUM)
+ {
+ atops = palloc0(sizeof(AttrOpFamilySet));
+ atops->next = attrsdc->atop_set;
+ attrsdc->atop_set = atops;
+ attrsdc->len_set = 0;
+ }
+ else
+ attrsdc->atop_set->elems[attrsdc->len_set].negator = InvalidOid;
+ return attrsdc->atop_set->elems + attrsdc->len_set++;
+}
+
+static int compare_scalararray_elements(const void *a, const void *b, void *arg)
+{
+ Datum da = *((const Datum *) a);
+ Datum db = *((const Datum *) b);
+ SortArrayContext *cxt = (SortArrayContext *) arg;
+ int32 compare;
+
+ compare = DatumGetInt32(FunctionCall2Coll(&cxt->sortproc,
+ cxt->collation,
+ da, db));
+ if (cxt->reverse)
+ INVERT_COMPARE_RESULT(compare);
+ return compare;
+}
+
+static int sort_scalararray_elements(SortArrayContext *cxt,
+ Oid intype,
+ Oid opfamily,
+ Oid collid,
+ bool reverse,
+ Datum *elems,
+ int nelems)
+{
+ RegProcedure cmp_proc;
+
+ if (nelems <= 1)
+ return nelems; /* No work to do */
+ /*
+ * Look up the appropriate comparison function in the opfamily.
+ *
+ * Note: it's possible that this would fail, if the opfamily is
+ * incomplete, but it seems quite unlikely that an opfamily would omit
+ * non-cross-type support functions for any datatype that it supports at
+ * all.
+ */
+ cmp_proc = get_opfamily_proc(opfamily,
+ intype,
+ intype,
+ BTORDER_PROC);
+ if (!RegProcedureIsValid(cmp_proc))
+ return 0; /* No support function, give up, do nothing. */
+
+ /* Sort the array elements */
+ fmgr_info(cmp_proc, &cxt->sortproc);
+ cxt->collation = collid;
+ cxt->reverse = reverse;
+ qsort_arg((void *) elems, nelems, sizeof(Datum),
+ compare_scalararray_elements, (void *) cxt);
+
+ /* Now scan the sorted elements and remove duplicates */
+ return qunique_arg(elems, nelems, sizeof(Datum),
+ compare_scalararray_elements, cxt);
+}
+
+static void extract_opc_info(int nums, Oid opcid, Oid opcfamily, Oid opcintype, void *infocxt)
+{
+ int i;
+ OpcInfoElement *opcele;
+ SortedOpclassInfo *sopcinfo = (SortedOpclassInfo*) infocxt;
+ if (sopcinfo->n_members == 0)
+ {
+ sopcinfo->opcies = palloc0(nums * (sizeof(OpcInfoElement*) + sizeof(OpcInfoElement)));
+ opcele = (OpcInfoElement*) (sopcinfo->opcies + nums);
+ for (i = 0; i < nums; i++)
+ sopcinfo->opcies[i] = opcele + i;
+ }
+
+ sopcinfo->opcies[sopcinfo->n_members]->opcfamily = opcfamily;
+ sopcinfo->opcies[sopcinfo->n_members]->opcid = opcid;
+ sopcinfo->opcies[sopcinfo->n_members]->opcintype = opcintype;
+ sopcinfo->n_members++;
+ Assert(sopcinfo->n_members <= nums);
+}
+
+static int opc_element_cmp(const void *p1, const void *p2)
+{
+ Oid v1 = (*((const OpcInfoElement **) p1))->opcintype;
+ Oid v2 = (*((const OpcInfoElement **) p2))->opcintype;
+
+ return pg_cmp_u32(v1, v2);
+}
+
+static Oid binary_search_opc_info(SortedOpclassInfo *sopi, Oid inputtype)
+{
+ Assert(sopi != NULL);
+ if (sopi->n_members > 0)
+ {
+ int i, l, r, res;
+ l = 0;
+ r = sopi->n_members - 1;
+ while (l <= r)
+ {
+ i = (l + r) / 2;
+ res = pg_cmp_u32(sopi->opcies[i]->opcintype, inputtype);
+ if (res == 0)
+ {
+ return sopi->opcies[i]->opcfamily;
+ }
+ else if (res < 0)
+ l = i + 1;
+ else
+ r = i - 1;
+ }
+ }
+ return InvalidOid;
+}
+
+static int ne_const_arg_cmp(const void *a, const void *b, void *arg)
+{
+ Datum da = *(((const NeConstDat *) a)->val);
+ Datum db = *(((const NeConstDat *) b)->val);
+ SortNeConstCxt *cncc = (SortNeConstCxt *) arg;
+ int32 compare;
+
+ compare = DatumGetInt32(FunctionCall2Coll(&cncc->cmp_proc,
+ cncc->collation,
+ da, db));
+ return compare;
+}
+
+static inline void init_ne_const(NeConstVal *nv)
+{
+ if (nv->capacity == 0)
+ {
+ nv->ncds = palloc0(DEFAULT_ELEMS_NUM * sizeof(NeConstDat));
+ nv->size = 0;
+ nv->capacity = DEFAULT_ELEMS_NUM;
+ }
+}
+
+static inline void insert_ne_const(NeConstVal *nv, uint32 idx, Datum *dat)
+{
+ if (nv->size == nv->capacity) {
+ nv->capacity *= 2;
+ nv->ncds = repalloc(nv->ncds, nv->capacity * sizeof(NeConstDat));
+ }
+ nv->ncds[nv->size].idx = idx;
+ nv->ncds[nv->size].val = dat;
+ nv->size++;
+ nv->sorted = false;
+}
+
+/* binary_search_ne_const
+ * Note: caller need to check number of elements in NeConstVal.
+ *
+ */
+static bool binary_search_ne_const(NeConstVal *nv, Datum *dat)
+{
+ int i, l, r, res;
+ NeConstDat ncd;
+ ncd.val = dat;
+ l = 0;
+ r = nv->size - 1;
+ while (l <= r)
+ {
+ i = (l + r) / 2;
+ res = ne_const_arg_cmp(&nv->ncds[i], &ncd, (void *) &nv->sncc);
+ if (res == 0)
+ {
+ return true;
+ }
+ else if (res < 0)
+ l = i + 1;
+ else
+ r = i - 1;
+ }
+ return false;
+}
+
+
+static bool search_ne_const(NeConstVal *nv, Oid collid, Datum *val)
+{
+ int i;
+ bool result;
+
+ if (nv->upper_ncv)
+ {
+ if (search_ne_const(nv->upper_ncv, collid, val))
+ return true;
+ }
+
+ if (nv->size == 0)
+ return false;
+
+ /* If there is no support function or size is small less than 4, use
+ * linear searching.
+ */
+ if (!nv->can_sort || nv->size <= DEFAULT_ELEMS_NUM)
+ {
+ for (i = 0; i < nv->size;i++)
+ {
+ result = DatumGetBool(FunctionCall2Coll(&nv->op_func,
+ collid,
+ *val,
+ *nv->ncds[i].val));
+ if (!result)
+ return true;
+ }
+ return false;
+ }
+
+ if (nv->can_sort && !nv->sorted)
+ {
+ qsort_arg((void *) nv->ncds, nv->size, sizeof(NeConstDat),
+ ne_const_arg_cmp, (void *) &nv->sncc);
+ nv->sorted = true;
+ }
+
+ if (binary_search_ne_const(nv, val))
+ return true;
+ return false;
+}
+
+static VarattInfo* get_varatt_info_internal(SelfExamContext *sec, ExtractedAttris *ea, Var *var)
+{
+ VarattInfo *attinfo, *attupper;
+ ConstVal *constv;
+ ExtractedAttris *up_ea;
+ NeConstVal **up_ncv;
+ int idx, i;
+ idx = var->varattno - ea->min_attr;
+ if (ea->array_vi[idx] == NULL)
+ {
+ attinfo = get_attinfo_cxt_internal(sec);
+ if (ea->att_lst)
+ {
+ attinfo->next = ea->att_lst;
+ ea->att_lst = attinfo;
+ }
+ else
+ ea->att_lst = ea->last = attinfo;
+ ea->array_vi[idx] = attinfo;
+
+ attinfo->stratcount = 0;
+ attinfo->null_test = 0;
+ attinfo->bool_test = 0;
+ attinfo->atidx = idx;
+ attinfo->collid = var->varcollid;
+ attinfo->type = var->vartype;
+ attinfo->ne_const.size = 0;
+ attinfo->ne_const.upper_ncv = NULL;
+ attinfo->saop.elemnents = NIL;
+ attinfo->saop.upper_elems = NIL;
+ for(i = 0; i < BTMaxStrategyNumber; i++)
+ attinfo->st_table[i].strategy = InvalidStrategy;
+
+ /* Copy push-down attribute particulars. */
+ up_ea = ea->upper_ea;
+ up_ncv = &attinfo->ne_const.upper_ncv;
+ while(up_ea)
+ {
+ if (up_ea->array_vi[idx])
+ {
+ attupper = up_ea->array_vi[idx];
+
+ if (attinfo->null_test == 0 && attupper->null_test != 0)
+ attinfo->null_test = attupper->null_test;
+ if (attinfo->bool_test == 0 && attupper->bool_test != 0)
+ attinfo->bool_test = attupper->bool_test;
+ if (!*up_ncv && attupper->ne_const.size != 0)
+ {
+ *up_ncv = &attupper->ne_const;
+ up_ncv = &(*up_ncv)->upper_ncv;
+ }
+ if (attinfo->stratcount == 0 && attupper->stratcount != 0)
+ {
+ attinfo->stratcount = attupper->stratcount;
+ for(i = 0; i < BTMaxStrategyNumber; i++)
+ {
+ constv = &attupper->st_table[i];
+ if (constv->strategy != InvalidStrategy)
+ {
+ memcpy(&attinfo->st_table[i], constv, sizeof(ConstVal));
+ attinfo->st_table[i].push_down = true;
+ }
+ }
+ }
+ if (attinfo->saop.upper_elems == NIL && attupper->saop.elemnents != NIL)
+ attinfo->saop.upper_elems = attupper->saop.elemnents;
+ }
+ up_ea = up_ea->upper_ea;
+ }
+ }
+ else
+ attinfo = ea->array_vi[idx];
+ return attinfo;
+}
+
+static bool deconstruct_nulltest_attr(Node *ntnode,
+ NullTestType ntt,
+ SelfExamContext *sec,
+ ExtractedAttris *ea)
+{
+ if (IsA(ntnode, Var))
+ {
+ VarattInfo *att_elem;
+ att_elem = get_varatt_info_internal(sec, ea, (Var *) ntnode);
+
+ if (ntt == IS_NULL)
+ att_elem->null_test = att_elem->null_test | NT_MARK | NT_IS_NULL;
+ else
+ att_elem->null_test = att_elem->null_test | NT_MARK | NT_IS_NOT_NULL;
+ if (att_elem->null_test == (NT_MARK | NT_IS_NULL | NT_IS_NOT_NULL))
+ {
+ return false;
+ }
+ }
+ else if (IsA(ntnode, ArrayExpr))
+ {
+ ListCell *l;
+ foreach(l, ((ArrayExpr *) ntnode)->elements)
+ {
+ if(!deconstruct_nulltest_attr((Node *) lfirst(l), ntt, sec, ea))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool add_binary_op_clause_info(VarattInfo *att_elem,
+ Datum *vals,
+ int nums,
+ uint32 idx,
+ uint16 strat,
+ RegProcedure opfuncid,
+ Expr *expr,
+ SelfExamContext *sec,
+ ClauseCxtWapper *ccw)
+{
+ ConstVal *constval;
+ ClauseContext *ccxt;
+ AttrOpFamily *atop;
+ Oid cmp_proc;
+ bool result;
+
+ if (strat == STRATEGY_NOT_EQUAL)
+ {
+ if (att_elem->st_table[BTEqualStrategyNumber-1].strategy != InvalidStrategy)
+ {
+ constval = &(att_elem->st_table[BTEqualStrategyNumber-1]);
+ result = DatumGetBool(FunctionCall2Coll(&constval->op_func,
+ att_elem->collid,
+ *vals,
+ *(constval->value)));
+ if (result)
+ return false;
+ }
+
+ if (att_elem->ne_const.size == 0)
+ {
+ init_ne_const(&att_elem->ne_const);
+ att_elem->ne_const.can_sort = false;
+ att_elem->ne_const.sorted = false;
+ fmgr_info(opfuncid, &(att_elem->ne_const.op_func));
+ atop = sec->attrsdc.atop_array[att_elem->atidx];
+ cmp_proc = get_opfamily_proc(atop->opfamily,
+ att_elem->type,
+ att_elem->type,
+ BTORDER_PROC);
+ if (!RegProcedureIsValid(cmp_proc))
+ {
+ /* No support function, use linear searching. */
+ att_elem->ne_const.can_sort = false;
+ }
+ else
+ {
+ att_elem->ne_const.sncc.reverse = false;
+ fmgr_info(cmp_proc, &att_elem->ne_const.sncc.cmp_proc);
+ att_elem->ne_const.sncc.collation = att_elem->collid;
+ att_elem->ne_const.can_sort = true;
+ }
+ }
+ insert_ne_const(&att_elem->ne_const, idx, vals);
+ }
+ else if (strat <= BTMaxStrategyNumber)
+ {
+ Assert(strat >= BTLessStrategyNumber);
+ constval = &(att_elem->st_table[strat-1]);
+ if (constval->strategy == InvalidStrategy)
+ {
+ att_elem->stratcount++;
+ constval->strategy = strat;
+ fmgr_info(opfuncid, &(constval->op_func));
+ constval->value = vals;
+ constval->expr = expr;
+ constval->push_down = false;
+ constval->idx = idx;
+ }
+ else
+ {
+ result = DatumGetBool(FunctionCall2Coll(&constval->op_func,
+ att_elem->collid,
+ *vals,
+ *(constval->value)));
+ /* Repeat operator = but the consts ain't equal ( eg. x=2 and x=3 ). */
+ if (strat == BTEqualStrategyNumber)
+ {
+ if (!result)
+ return false;
+ if (constval->push_down)
+ {
+ constval->value = vals;
+ constval->expr = expr;
+ constval->push_down = false;
+ constval->idx = idx;
+ }
+ else if (IsA(expr, OpExpr))
+ {
+ ccxt = get_clause_cxt_internal(sec);
+ ccxt->cct = CCT_DEL;
+ ccxt->idx = idx;
+ ccw->clausecxt = lappend(ccw->clausecxt, ccxt);
+ }
+ }
+ else if (result)
+ {
+ /* Current Expr is more restrict, so keep it. */
+ if (!constval->push_down && IsA(constval->expr, OpExpr))
+ {
+ ccxt = get_clause_cxt_internal(sec);
+ ccxt->cct = CCT_DEL;
+ ccxt->idx = constval->idx;
+ ccw->clausecxt = lappend(ccw->clausecxt, ccxt);
+ }
+ constval->value = vals;
+ constval->expr = expr;
+ constval->push_down = false;
+ constval->idx = idx;
+ }
+ else
+ {
+ /* Current Expr is less restrict, so abandon it. */
+ if (constval->push_down)
+ {
+ ccxt = get_clause_cxt_internal(sec);
+ ccxt->cct = CCT_REPLACE;
+ ccxt->idx = idx;
+ ccxt->cxt = copyObjectImpl(constval->expr);
+ ccw->clausecxt = lappend(ccw->clausecxt, ccxt);
+
+ constval->push_down = false;
+ constval->expr = ccxt->cxt;
+ constval->idx = idx;
+ }
+ else if (IsA(expr, OpExpr))
+ {
+ ccxt = get_clause_cxt_internal(sec);
+ ccxt->cct = CCT_DEL;
+ ccxt->idx = idx;
+ ccw->clausecxt = lappend(ccw->clausecxt, ccxt);
+ }
+ }
+ }
+ }
+ return true;
+}
+
+static bool self_contradictory_element(SelfExamContext *sec,
+ ClauseCxtWapper *ccw,
+ VarattInfo *att_elem)
+{
+ ConstVal *leftcv, *rightcv;
+ ClauseContext *ccxt;
+ int i;
+ uint8 btest;
+ bool result;
+ bool macthed;
+
+ if (att_elem->bool_test & BT_MARK)
+ {
+ btest = att_elem->bool_test & ~BT_MARK;
+ if (((btest & BT_IS_TRUE) && (btest & (BT_IS_NOT_TRUE | BT_IS_FALSE | BT_IS_UNKNOWN)))
+ || ((btest & BT_IS_FALSE) && (btest &(BT_IS_TRUE | BT_IS_NOT_FALSE | BT_IS_UNKNOWN)))
+ || ((btest & BT_IS_UNKNOWN) && (btest &(BT_IS_NOT_UNKNOWN | BT_IS_TRUE | BT_IS_FALSE))))
+ {
+ return true;
+ }
+ }
+
+ if (att_elem->null_test == (NT_MARK | NT_IS_NULL)
+ && (att_elem->stratcount > 0
+ || att_elem->ne_const.size != 0
+ || att_elem->ne_const.upper_ncv))
+ return true;
+
+ if ((att_elem->bool_test & BT_MARK) && (att_elem->null_test & NT_MARK))
+ {
+ if (att_elem->null_test == (NT_MARK | NT_IS_NULL)
+ && (btest & (BT_IS_TRUE | BT_IS_FALSE | BT_IS_NOT_UNKNOWN)))
+ return true;
+ else if (att_elem->null_test == (NT_MARK | NT_IS_NOT_NULL)
+ && (btest & BT_IS_UNKNOWN))
+ return true;
+ }
+
+ /* If operator '=' and '<>' are both appeared. */
+ if (att_elem->st_table[BTEqualStrategyNumber-1].strategy != 0
+ && (att_elem->ne_const.size != 0 || att_elem->ne_const.upper_ncv))
+ {
+ leftcv = &att_elem->st_table[BTEqualStrategyNumber-1];
+
+ if (search_ne_const(&att_elem->ne_const, att_elem->collid, leftcv->value))
+ return true;
+ /* If they are not contradictory, eliminate the not equalities. */
+ for (i = 0; i < att_elem->ne_const.size; i++)
+ {
+ ccxt = get_clause_cxt_internal(sec);
+ ccxt->cct = CCT_DEL;
+ ccxt->idx = att_elem->ne_const.ncds[i].idx;
+ ccw->clausecxt = lappend(ccw->clausecxt, ccxt);
+ }
+ att_elem->ne_const.size = 0;
+ }
+
+ /* Try to keep only one of <, <= */
+ if (att_elem->st_table[BTLessStrategyNumber - 1].strategy != 0
+ && att_elem->st_table[BTLessEqualStrategyNumber - 1].strategy != 0)
+ {
+ leftcv = &att_elem->st_table[BTLessStrategyNumber - 1];
+ rightcv = &att_elem->st_table[BTLessEqualStrategyNumber - 1];
+ result = DatumGetBool(FunctionCall2Coll(&(rightcv->op_func),
+ att_elem->collid,
+ *(leftcv->value),
+ *(rightcv->value)));
+ if (result)
+ {
+ rightcv->strategy = InvalidStrategy;
+ if (leftcv->push_down)
+ {
+ ccxt = get_clause_cxt_internal(sec);
+ ccxt->cct = CCT_REPLACE;
+ ccxt->idx = rightcv->idx;
+ ccxt->cxt = copyObjectImpl(leftcv->expr);
+ ccw->clausecxt = lappend(ccw->clausecxt, ccxt);
+
+ leftcv->push_down = false;
+ leftcv->expr = ccxt->cxt;
+ leftcv->idx = rightcv->idx;
+ }
+ else if (!rightcv->push_down)
+ {
+ ccxt = get_clause_cxt_internal(sec);
+ ccxt->cct = CCT_DEL;
+ ccxt->idx = rightcv->idx;
+ ccw->clausecxt = lappend(ccw->clausecxt, ccxt);
+ }
+ }
+ else
+ {
+ leftcv->strategy = InvalidStrategy;
+ if (rightcv->push_down)
+ {
+ ccxt = get_clause_cxt_internal(sec);
+ ccxt->cct = CCT_REPLACE;
+ ccxt->idx = leftcv->idx;
+ ccxt->cxt = copyObjectImpl(rightcv->expr);
+ ccw->clausecxt = lappend(ccw->clausecxt, ccxt);
+
+ rightcv->push_down = false;
+ rightcv->expr = ccxt->cxt;
+ rightcv->idx = leftcv->idx;
+ }
+ else if (!leftcv->push_down)
+ {
+ ccxt = get_clause_cxt_internal(sec);
+ ccxt->cct = CCT_DEL;
+ ccxt->idx = leftcv->idx;
+ ccw->clausecxt = lappend(ccw->clausecxt, ccxt);
+ }
+ }
+ att_elem->stratcount--;
+ }
+
+ /* try to keep only one of >, >= */
+ if (att_elem->st_table[BTGreaterStrategyNumber - 1].strategy != 0
+ && att_elem->st_table[BTGreaterEqualStrategyNumber - 1].strategy != 0)
+ {
+ leftcv = &att_elem->st_table[BTGreaterStrategyNumber - 1];
+ rightcv = &att_elem->st_table[BTGreaterEqualStrategyNumber - 1];
+ result = DatumGetBool(FunctionCall2Coll(&(rightcv->op_func),
+ att_elem->collid,
+ *(leftcv->value),
+ *(rightcv->value)));
+ if (result)
+ {
+ rightcv->strategy = InvalidStrategy;
+ if (leftcv->push_down)
+ {
+ ccxt = get_clause_cxt_internal(sec);
+ ccxt->cct = CCT_REPLACE;
+ ccxt->idx = rightcv->idx;
+ ccxt->cxt = copyObjectImpl(leftcv->expr);
+ ccw->clausecxt = lappend(ccw->clausecxt, ccxt);
+
+ leftcv->push_down = false;
+ leftcv->expr = ccxt->cxt;
+ leftcv->idx = rightcv->idx;
+ }
+ else if (!rightcv->push_down)
+ {
+ ccxt = get_clause_cxt_internal(sec);
+ ccxt->cct = CCT_DEL;
+ ccxt->idx = rightcv->idx;
+ ccw->clausecxt = lappend(ccw->clausecxt, ccxt);
+ }
+ }
+ else
+ {
+ leftcv->strategy = InvalidStrategy;
+ if (rightcv->push_down)
+ {
+ ccxt = get_clause_cxt_internal(sec);
+ ccxt->cct = CCT_REPLACE;
+ ccxt->idx = leftcv->idx;
+ ccxt->cxt = copyObjectImpl(rightcv->expr);
+ ccw->clausecxt = lappend(ccw->clausecxt, ccxt);
+
+ rightcv->push_down = false;
+ rightcv->expr = ccxt->cxt;
+ rightcv->idx = leftcv->idx;
+ }
+ else if (!leftcv->push_down)
+ {
+ ccxt = get_clause_cxt_internal(sec);
+ ccxt->cct = CCT_DEL;
+ ccxt->idx = leftcv->idx;
+ ccw->clausecxt = lappend(ccw->clausecxt, ccxt);
+ }
+ }
+ att_elem->stratcount--;
+ }
+
+ if (att_elem->type == BOOLOID && att_elem->stratcount > 0)
+ {
+ /*
+ * Beyond the scope of the defined values of boolean type,
+ * obviously it does not make sense.
+ */
+ if (att_elem->st_table[BTGreaterStrategyNumber - 1].strategy != 0)
+ {
+ leftcv = &att_elem->st_table[BTGreaterStrategyNumber - 1];
+ result = DatumGetBool(FunctionCall2Coll(&leftcv->op_func,
+ att_elem->collid,
+ BoolGetDatum(true),
+ *leftcv->value));
+ if (!result)
+ return true;
+ }
+ if (att_elem->st_table[BTLessStrategyNumber - 1].strategy != 0)
+ {
+ leftcv = &att_elem->st_table[BTLessStrategyNumber - 1];
+ result = DatumGetBool(FunctionCall2Coll(&leftcv->op_func,
+ att_elem->collid,
+ BoolGetDatum(false),
+ *leftcv->value));
+ if (!result)
+ return true;
+ }
+
+ if (att_elem->bool_test & BT_MARK)
+ {
+ btest = att_elem->bool_test & ~BT_MARK;
+ if (btest & BT_IS_UNKNOWN)
+ return true;
+ else
+ {
+ bool isvalue;
+ macthed = true;
+ /* If IS_NOT_FALSE is set, that mean the equivalent expression is
+ * (x IS NULL OR x IS TRUE). The NULL test will always fail with
+ * the strategy operator, so we only need to test whether the
+ * sub-expression (x IS TRUE) is contradictory to the strategy
+ * operator. If IS_NOT_TRUE is set, it's similar to IS_NOT_FALSE.
+ */
+ if (btest & (BT_IS_TRUE| BT_IS_NOT_FALSE))
+ isvalue = true;
+ else if (btest & (BT_IS_FALSE| BT_IS_NOT_TRUE))
+ isvalue = false;
+ else
+ macthed = false;
+ if (macthed)
+ {
+ for (i = BTMaxStrategyNumber; --i >= 0;)
+ {
+ leftcv = &att_elem->st_table[i];
+ if (leftcv->strategy == InvalidStrategy)
+ continue;
+ result = DatumGetBool(FunctionCall2Coll(&leftcv->op_func,
+ att_elem->collid,
+ BoolGetDatum(isvalue),
+ *leftcv->value));
+ if (!result)
+ return true;
+ }
+ }
+ }
+ }
+ }
+
+ if (att_elem->stratcount <=1)
+ return false;
+
+ if (att_elem->st_table[BTEqualStrategyNumber-1].strategy != 0)
+ {
+ leftcv = &att_elem->st_table[BTEqualStrategyNumber - 1];
+ for (i = BTMaxStrategyNumber; --i >= 0;)
+ {
+ rightcv = &att_elem->st_table[i];
+ if (rightcv->strategy == InvalidStrategy || i == (BTEqualStrategyNumber - 1))
+ continue;
+ result = DatumGetBool(FunctionCall2Coll(&(rightcv->op_func),
+ att_elem->collid,
+ *(leftcv->value),
+ *(rightcv->value)));
+ if (!result)
+ return true;
+ /* The element had be dominated by operator =, so abandon it. */
+ if (leftcv->push_down)
+ {
+ ccxt = get_clause_cxt_internal(sec);
+ ccxt->cct = CCT_REPLACE;
+ ccxt->idx = rightcv->idx;
+ ccxt->cxt = copyObjectImpl(leftcv->expr);
+ ccw->clausecxt = lappend(ccw->clausecxt, ccxt);
+
+ leftcv->push_down = false;
+ leftcv->expr = ccxt->cxt;
+ leftcv->idx = rightcv->idx;
+ }
+ else if (!rightcv->push_down)
+ {
+ ccxt = get_clause_cxt_internal(sec);
+ ccxt->cct = CCT_DEL;
+ ccxt->idx = rightcv->idx;
+ ccw->clausecxt = lappend(ccw->clausecxt, ccxt);
+ }
+ rightcv->strategy = InvalidStrategy;
+ }
+ /* The operator = has dominated others, so no need to check other case. */
+ return false;
+ }
+
+ /* Detect the contradictory case that like x <4 and x >10. */
+ macthed = true;
+ if (att_elem->st_table[BTGreaterStrategyNumber - 1].strategy != 0)
+ {
+ rightcv = &att_elem->st_table[BTGreaterStrategyNumber - 1];
+ if (att_elem->st_table[BTLessStrategyNumber - 1].strategy != 0)
+ leftcv = &att_elem->st_table[BTLessStrategyNumber - 1];
+ else if (att_elem->st_table[BTLessEqualStrategyNumber - 1].strategy != 0)
+ leftcv = &att_elem->st_table[BTLessEqualStrategyNumber - 1];
+ else
+ macthed = false;
+ }
+ else if (att_elem->st_table[BTLessStrategyNumber - 1].strategy != 0)
+ {
+ rightcv = &att_elem->st_table[BTLessStrategyNumber - 1];
+ if (att_elem->st_table[BTGreaterStrategyNumber - 1].strategy != 0)
+ leftcv = &att_elem->st_table[BTGreaterStrategyNumber - 1];
+ else if (att_elem->st_table[BTGreaterEqualStrategyNumber - 1].strategy != 0)
+ leftcv = &att_elem->st_table[BTGreaterEqualStrategyNumber - 1];
+ else
+ macthed = false;
+ }
+ else if (att_elem->st_table[BTLessEqualStrategyNumber - 1].strategy != 0
+ && att_elem->st_table[BTGreaterEqualStrategyNumber - 1].strategy != 0)
+ {
+ rightcv = &att_elem->st_table[BTGreaterEqualStrategyNumber - 1];
+ leftcv = &att_elem->st_table[BTLessEqualStrategyNumber - 1];
+ }
+ else
+ macthed = false;
+ if (macthed)
+ {
+ result = DatumGetBool(FunctionCall2Coll(&(rightcv->op_func),
+ att_elem->collid,
+ *(leftcv->value),
+ *(rightcv->value)));
+ if (!result)
+ return true;
+ }
+
+ return false;
+}
+
+static bool check_eq_sa_op_elemnet(Datum *value, VarattInfo *att_elem)
+{
+ ConstVal *constval;
+ int i;
+ bool result;
+ uint8 btest;
+ bool isvalue, macthed;
+
+ if (att_elem->null_test == (NT_MARK | NT_IS_NULL))
+ return true;
+
+ if (att_elem->bool_test & BT_MARK)
+ {
+ btest = att_elem->bool_test & ~BT_MARK;
+
+ if (btest & BT_IS_UNKNOWN)
+ return true;
+
+ macthed = true;
+ if (btest & (BT_IS_TRUE| BT_IS_NOT_FALSE))
+ isvalue = true;
+ else if (btest & (BT_IS_FALSE| BT_IS_NOT_TRUE))
+ isvalue = false;
+ else
+ macthed = false;
+
+ if (macthed && DatumGetBool(*value) != isvalue)
+ return true;
+ }
+
+ if (search_ne_const(&att_elem->ne_const, att_elem->collid, value))
+ return true;
+ if (att_elem->stratcount > 0)
+ {
+ for (i = BTMaxStrategyNumber; --i >= 0;)
+ {
+ constval = &att_elem->st_table[i];
+ if (constval->strategy == InvalidStrategy)
+ continue;
+ result = DatumGetBool(FunctionCall2Coll(&(constval->op_func),
+ att_elem->collid,
+ *(value),
+ *(constval->value)));
+ if (!result)
+ return true;
+ }
+ }
+ return false;
+}
+
+/*
+ * self_contradictory_saop
+ * The Scalar array expr of any-equality expression are postponed here
+ * to examine them (eg. x in (1,3) and x in (3,5) and x = 1 ).
+ * Extract intersection elements and report to the caller if there is
+ * no intersection element or check intersection elements one by one
+ * and eliminate it if it's self-contradictory. All of them are
+ * self-contradictory report it.
+ * Rebuilt the saop finally.
+ */
+static bool self_contradictory_saop(SelfExamContext *sec,
+ ClauseCxtWapper *ccw,
+ VarattInfo *att_elem)
+{
+ /* Scalar array expr of single attribute. */
+ ScalarArrayOpExpr *saopexpr;
+ SAEqualDatElem *saout;
+ ClauseContext *ccxt;
+ ListCell *lc;
+ Expr *newclause;
+ Const *con;
+ int i, j, initial_nums;
+
+ if (att_elem->saop.elemnents == NIL)
+ return false;
+
+ if (att_elem->saop.upper_elems != NIL)
+ att_elem->saop.elemnents = list_concat(att_elem->saop.elemnents, att_elem->saop.upper_elems);
+
+ saout = linitial(att_elem->saop.elemnents);
+ initial_nums = saout->elem_nums;
+ if (list_length(att_elem->saop.elemnents) > 1)
+ {
+ /* Initialize saout with the first one, merge the rest of elemnents
+ * one by one and extract the intersection element at the same time.
+ * Update the saout with merged result.
+ */
+ for_each_from(lc, att_elem->saop.elemnents, 1)
+ {
+ SAEqualDatElem *sade;
+ int nelems_dups;
+
+ sade =lfirst(lc);
+ nelems_dups = 0;
+ for (i = 0, j = 0; i < saout->elem_nums && j < sade->elem_nums;)
+ {
+ Datum *oelem = saout->elem_values + i,
+ *nelem = sade->elem_values + j;
+ int res = compare_scalararray_elements(oelem, nelem, &att_elem->saop.sortcxt);
+ if (res == 0)
+ {
+ saout->elem_values[nelems_dups++] = *oelem;
+ i++;
+ j++;
+ }
+ else if (res < 0)
+ i++;
+ else /* res > 0 */
+ j++;
+ }
+ if (nelems_dups == 0)
+ {
+ att_elem->saop.elemnents = NIL;
+ return true; /* No intersection element, so report it. */
+ }
+ else
+ saout->elem_nums = nelems_dups;
+ }
+ }
+
+ /* Examine the rest of intersection elements one by one. */
+ for(i = 0; i < saout->elem_nums;)
+ {
+ if (check_eq_sa_op_elemnet(&saout->elem_values[i], att_elem))
+ {
+ if (i < saout->elem_nums - 1)
+ memmove(saout->elem_values + i, saout->elem_values + i + 1,
+ sizeof(Datum) * (saout->elem_nums - i - 1));
+ saout->elem_nums--;
+ }
+ else
+ i++;
+ }
+ if (0 == saout->elem_nums)
+ {
+ att_elem->saop.elemnents = NIL;
+ return true;
+ }
+
+ /*
+ * Convert the intersection elements to a new clause and delete orignal
+ * elements.
+ */
+ saopexpr = (ScalarArrayOpExpr*)saout->expr;
+ if (saout->elem_nums == 1)
+ {
+ con = makeConst(att_elem->saop.sortcxt.elmtype,
+ -1, /* typmod -1 is OK for all cases */
+ InvalidOid,
+ att_elem->saop.sortcxt.elmlen,
+ saout->elem_values[0],
+ false,
+ att_elem->saop.sortcxt.elmbyval);
+ con->location = -1;
+ newclause = make_opclause(saopexpr->opno,
+ BOOLOID,
+ false,
+ linitial(saopexpr->args),
+ (Expr*)con,
+ InvalidOid,
+ saopexpr->inputcollid);
+ ccxt = get_clause_cxt_internal(sec);
+ ccxt->cct = CCT_REPLACE;
+ ccxt->idx = saout->idx;
+ ccxt->cxt = newclause;
+ ccw->clausecxt = lappend(ccw->clausecxt, ccxt);
+ add_binary_op_clause_info(att_elem,
+ &saout->elem_values[0],
+ 1,
+ saout->idx,
+ BTEqualStrategyNumber,
+ att_elem->saop.opfuncid,
+ newclause,
+ sec,
+ ccw);
+ }
+ else if (saout->elem_nums != initial_nums)
+ {
+ /* It's need to rebuilt the first saop if there are multi-saop,
+ * and delete others saop later.
+ */
+ ArrayType *arrval = construct_array(saout->elem_values,
+ saout->elem_nums,
+ att_elem->saop.sortcxt.elmtype,
+ att_elem->saop.sortcxt.elmlen,
+ att_elem->saop.sortcxt.elmbyval,
+ att_elem->saop.sortcxt.elmalign);
+ con = lsecond(saopexpr->args);
+ con->constvalue = PointerGetDatum(arrval);
+
+ ccxt = get_clause_cxt_internal(sec);
+ ccxt->cct = CCT_REPLACE;
+ ccxt->idx = saout->idx;
+ ccxt->cxt = saopexpr;
+ ccw->clausecxt = lappend(ccw->clausecxt, ccxt);
+
+ }
+
+ /* The push-down elements have finished their jobs, so truncate them. */
+ if (att_elem->saop.upper_elems != NIL)
+ { att_elem->saop.elemnents = list_truncate(att_elem->saop.elemnents, \
+ list_length(att_elem->saop.elemnents) - list_length(att_elem->saop.upper_elems));
+ }
+
+ /* Since the whole elements except first one have be merged into first one,
+ * it's time to delete them from the orignal clause list.
+ */
+ for_each_from(lc, att_elem->saop.elemnents, 1)
+ {
+ saout =lfirst(lc);
+ ccxt = get_clause_cxt_internal(sec);
+ ccxt->cct = CCT_DEL;
+ ccxt->idx = saout->idx;
+ ccw->clausecxt = lappend(ccw->clausecxt, ccxt);
+ }
+ /* It's need to truncate the list, it maybe push down to
+ * compare with lower level ScalarArrayOpExpr, since the
+ * whole elements except first one have already merged.
+ */
+ att_elem->saop.elemnents = list_truncate(att_elem->saop.elemnents, 1);
+ return false;
+}
+
+static bool self_contradictory_check(SelfExamContext *sec, ExtractedAttris *ea, ClauseCxtWapper *ccw)
+{
+ VarattInfo *attinfo;
+ if (!ea->addOp)
+ return false;
+ attinfo = ea->att_lst;
+ while(attinfo)
+ {
+ if (self_contradictory_element(sec, ccw, attinfo))
+ return true;
+
+ if (self_contradictory_saop(sec, ccw, attinfo))
+ return true;
+ attinfo = attinfo->next;
+ }
+ return false;
+}
+
+/*
+ * extract_binary_op_clause_info
+ * Extract binary operation clause information
+ *
+ * In practice, B-tree index is used widely; Binary operation
+ * expr that Var op Const is often written; Also without
+ * data type coercion and collation. So this routine support
+ * above features.
+ * There are several consideration 1) self-contradictory
+ * rel seldom appeared. 2) Invoker will get upset if spend
+ * too much effort on it and find that rel is not
+ * self-contradictory (eg. strict function sqrt, expr like
+ * sqrt(x) > 2 and sqrt(x) < 4 ). 3) Finally the expression
+ * evaluation mechanism will do the right things. So this is
+ * a compromise.
+ */
+static bool extract_binary_op_clause_info(void *expr,
+ Node *lop,
+ Node *rop,
+ uint32 idx,
+ Oid opno,
+ Oid collid,
+ SelfExamContext *sec,
+ ExtractedAttris *ea,
+ ClauseCxtWapper *ccw)
+{
+ VarattInfo *attinfo;
+ Node *leftop, *rightop;
+ AttrOpFamily *atop;
+ Expr *newclause;
+ Oid left_type, right_type;
+ Oid varcollid;
+ Oid opid, opfamily;
+ RegProcedure opfuncid;
+ StrategyNumber strat;
+ uint16 attidx;
+
+ if (!(IsA(lop, Const) || IsA(rop, Const)))
+ return true;
+
+ if (IsA(lop, Const))
+ {
+ opid = get_commutator(opno);
+ if (!OidIsValid(opid))
+ return true;
+ leftop = rop;
+ rightop = lop;
+ }
+ else
+ {
+ opid = opno;
+ leftop = lop;
+ rightop = rop;
+ }
+ opfuncid = get_opcode(opid);
+ Assert(OidIsValid(opfuncid));
+
+ if (((Const *) rightop)->constisnull)
+ return true;
+
+ left_type = InvalidOid;
+ right_type = ((Const *) rightop)->consttype;
+
+ if (IsA(expr, ScalarArrayOpExpr))
+ {
+ Oid typInput, typelem;
+ getTypeInputInfo(right_type, &typInput, &typelem);
+ right_type = typelem;
+ }
+
+ if (leftop && IsA(leftop, RelabelType))
+ {
+ left_type = ((RelabelType *) leftop)->resulttype;
+ varcollid = ((RelabelType *) leftop)->resultcollid;
+ leftop = (Node*)((RelabelType *) leftop)->arg;
+ }
+
+ if (IsA(leftop, Var))
+ {
+ if (((Var *) leftop)->varattno > sec->attrsdc.max_attr)
+ elog(ERROR, "bogus relation attribute");
+ attidx = ((Var *) leftop)->varattno - sec->attrsdc.min_attr;
+ }
+ else /* Don't spend much effort for other types, so skip it */
+ return true;
+
+ if (!OidIsValid(left_type))
+ {
+ left_type = ((Var *) leftop)->vartype;
+ varcollid = ((Var *) leftop)->varcollid;
+ }
+
+ if (left_type != right_type)
+ return true;
+ if (collid != varcollid)
+ return true;
+
+ /* Search attribute opfamily cache, be happy to use it if find. */
+ if (sec->attrsdc.atop_array[attidx])
+ {
+ atop = sec->attrsdc.atop_array[attidx];
+ if (!OidIsValid(atop->opfamily))
+ return true;
+ opfamily = atop->opfamily;
+ }
+ else
+ {
+ atop = get_atop_element_internal(&sec->attrsdc);
+ sec->attrsdc.atop_array[attidx] = atop;
+
+ opfamily = binary_search_opc_info(&sec->sopcinfo, left_type);
+ if (!OidIsValid(opfamily))
+ {
+ atop->opfamily = InvalidOid;
+ return true;
+ }
+ atop->opfamily = opfamily;
+ }
+
+ if (!OidIsValid(atop->negator) && atop->negator == opid)
+ strat = STRATEGY_NOT_EQUAL;
+ else
+ {
+ strat = get_op_opfamily_strategy(opid, opfamily);
+ if (strat == 0)
+ {
+ /* Perhaps it is a <> operator. See if it has a negator that is in an opfamily. */
+ Oid op_negator = get_negator(opid);
+ if (!OidIsValid(op_negator))
+ return true;
+ if (BTEqualStrategyNumber == get_op_opfamily_strategy(op_negator, opfamily))
+ {
+ atop->negator = opid;
+ strat = STRATEGY_NOT_EQUAL;
+ }
+ else
+ return true;
+ }
+ }
+
+ /* If it's scalar array expr, deconstruct the const values. */
+ if (unlikely(IsA(expr, ScalarArrayOpExpr)))
+ {
+ ArrayType *arrayval;
+ int num_elems;
+ Datum *elem_values, *one_elem;
+ bool *elem_nulls;
+ int num_nonnulls;
+ int j;
+ SortArrayContext sacontext;
+ ClauseContext *ccxt;
+ Const *con;
+ ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *)expr;
+ arrayval = DatumGetArrayTypeP(((Const *) rightop)->constvalue);
+ /* We could cache this data, but not clear it's worth it */
+ get_typlenbyvalalign(ARR_ELEMTYPE(arrayval),
+ &sacontext.elmlen, &sacontext.elmbyval, &sacontext.elmalign);
+ sacontext.elmtype = ARR_ELEMTYPE(arrayval);
+ deconstruct_array(arrayval,
+ ARR_ELEMTYPE(arrayval),
+ sacontext.elmlen, sacontext.elmbyval, sacontext.elmalign,
+ &elem_values, &elem_nulls, &num_elems);
+
+ /*
+ * Compress out any null elements. We can ignore them since we assume
+ * all B-tree operators are strict.
+ */
+ num_nonnulls = 0;
+ for (j = 0; j < num_elems; j++)
+ {
+ if (!elem_nulls[j])
+ elem_values[num_nonnulls++] = elem_values[j];
+ }
+ if (num_nonnulls == 0)
+ return true;
+
+ /* If NULL is existed and with ALL flag, report it. */
+ if (!saop->useOr && num_nonnulls != num_elems)
+ return false;
+
+ /* Sort the non-null elements and eliminate any duplicates.
+ * If there is no support function will return 0 and then
+ * give up.
+ */
+ if ( 0 == (num_elems = sort_scalararray_elements(&sacontext, right_type, opfamily, collid,
+ false, elem_values, num_nonnulls)))
+ return true;
+
+ attinfo = get_varatt_info_internal(sec, ea, (Var *) leftop);
+ if (unlikely(strat == STRATEGY_NOT_EQUAL))
+ {
+ /* operator <> */
+ if (!saop->useOr)
+ {
+ for (j = 0; j < num_elems; j++)
+ {
+ if (!add_binary_op_clause_info(attinfo,
+ &elem_values[j],
+ 1,
+ idx,
+ strat,
+ opfuncid,
+ expr,
+ sec,
+ ccw))
+ return false;
+ ea->addOp = true;
+ }
+ }
+ else
+ {
+ /* Treat it as and-expr implicitly if there is only one element. */
+ if (num_elems != 1)
+ return true; /* Don't flatten, forget it. */
+ con = makeConst(left_type,
+ -1, /* typmod -1 is OK for all cases */
+ InvalidOid,
+ sacontext.elmlen,
+ elem_values[0],
+ false,
+ sacontext.elmbyval);
+ con->location = -1;
+ newclause = make_opclause(opid,
+ BOOLOID,
+ false,
+ (Expr*)leftop,
+ (Expr*)con,
+ InvalidOid,
+ collid);
+ if (!add_binary_op_clause_info(attinfo,
+ &elem_values[0],
+ 1,
+ idx,
+ strat,
+ opfuncid,
+ newclause,
+ sec,
+ ccw))
+ return false;
+ ea->addOp = true;
+ ccxt = get_clause_cxt_internal(sec);
+ ccxt->cct = CCT_REPLACE;
+ ccxt->idx = idx;
+ ccxt->cxt = newclause;
+ ccw->clausecxt = lappend(ccw->clausecxt, ccxt);
+ }
+ }
+ else
+ {
+ switch (strat)
+ {
+ case BTLessStrategyNumber:
+ case BTLessEqualStrategyNumber:
+ if (!saop->useOr)
+ one_elem = &elem_values[0];
+ else
+ one_elem = &elem_values[num_elems-1];
+ break;
+ case BTEqualStrategyNumber:
+ /* If the number of elements is not one and postpone them,
+ * examine them later, because maybe there are multiple
+ * any-op ScalarArrayOpExpr (eg. x in(1,3) and x in(1,5)),
+ * see self_contradictory_saop comment.
+ */
+ if (num_elems != 1)
+ {
+ if (!saop->useOr)
+ return false; /* It's contradictory obviously. */
+ else
+ {
+ SAEqualDatElem *saopele;
+ if (attinfo->saop.elemnents == NIL)
+ {
+ attinfo->saop.opfuncid = opfuncid;
+ memcpy(&(attinfo->saop.sortcxt), &sacontext, sizeof(SortArrayContext));
+ }
+ saopele = palloc0(sizeof(SAEqualDatElem));
+ saopele->idx = idx;
+ saopele->expr = expr;
+ saopele->elem_nums = num_elems;
+ saopele->elem_values = elem_values;
+ attinfo->saop.elemnents = lappend(attinfo->saop.elemnents, saopele);
+ }
+ }
+ else
+ {
+ Assert(num_elems == 1);
+ one_elem = &elem_values[0];
+ }
+ break;
+ case BTGreaterEqualStrategyNumber:
+ case BTGreaterStrategyNumber:
+ if (!saop->useOr)
+ one_elem = &elem_values[num_elems-1];
+ else
+ one_elem = &elem_values[0];
+ break;
+ default:
+ elog(ERROR, "unrecognized StrategyNumber: %d",
+ strat);
+ break;
+ }
+ if (!(strat == BTEqualStrategyNumber && num_elems != 1))
+ {
+ con = makeConst(left_type,
+ -1, /* typmod -1 is OK for all cases */
+ InvalidOid,
+ sacontext.elmlen,
+ *one_elem,
+ false,
+ sacontext.elmbyval);
+ con->location = -1;
+ newclause = make_opclause(opid,
+ BOOLOID,
+ false,
+ (Expr*)leftop,
+ (Expr*)con,
+ InvalidOid,
+ collid);
+ if (!add_binary_op_clause_info(attinfo,
+ one_elem,
+ 1,
+ idx,
+ strat,
+ opfuncid,
+ newclause,
+ sec,
+ ccw))
+ return false;
+
+ ccxt = get_clause_cxt_internal(sec);
+ ccxt->cct = CCT_REPLACE;
+ ccxt->idx = idx;
+ ccxt->cxt = newclause;
+ ccw->clausecxt = lappend(ccw->clausecxt, ccxt);
+ }
+ }
+ }
+ else
+ {
+ attinfo = get_varatt_info_internal(sec, ea, (Var *) leftop);
+ if (!add_binary_op_clause_info(attinfo,
+ &((Const *) rightop)->constvalue,
+ 1,
+ idx,
+ strat,
+ opfuncid,
+ expr,
+ sec,
+ ccw))
+ return false;
+ }
+ ea->addOp = true;
+
+ return true;
+}
+
+/*
+ * row_comparsion_to_nonconstructor
+ * Convert a row comparison to nonconstructor
+ *
+ * We have checked the expression in analysis phase, so
+ * there is no need to check whether it can satisfy the
+ * required of B-tree or not.
+ */
+static int row_comparsion_to_nonconstructor(Expr *rowexpr, Expr **transformed)
+{
+ Oid left_type, right_type;
+ Oid varcollid;
+ ListCell *l_left_expr,
+ *l_right_expr,
+ *l_opno,
+ *l_opfamily,
+ *l_inputcollid;
+ ListCell *lc;
+ List *rcelst, *arglst;
+ BoolExpr *orclause, *andclause;
+ RowCompElem *rce;
+ Expr *newclause;
+ RowCompareExpr *rcexpr;
+ FmgrInfo op_func;
+ bool result, lasteva;
+
+ *transformed = NULL;
+ rcexpr = (RowCompareExpr *) rowexpr;
+ Assert(list_length(rcexpr->opnos) != 1);
+ Assert(rcexpr->rctype != ROWCOMPARE_EQ && rcexpr->rctype != ROWCOMPARE_NE);
+
+ rcelst = NIL;
+ orclause = (BoolExpr*)make_orclause(NIL);
+ forfive(l_left_expr, rcexpr->largs,
+ l_right_expr, rcexpr->rargs,
+ l_opno, rcexpr->opnos,
+ l_opfamily, rcexpr->opfamilies,
+ l_inputcollid, rcexpr->inputcollids)
+ {
+ RegProcedure opfuncid;
+ int strat;
+ Oid eqid;
+ Expr *tmp_expr;
+ Expr *left_expr = (Expr *) lfirst(l_left_expr);
+ Expr *right_expr = (Expr *) lfirst(l_right_expr);
+ Oid opno = lfirst_oid(l_opno);
+ Oid opfamily = lfirst_oid(l_opfamily);
+ Oid inputcollid = lfirst_oid(l_inputcollid);
+
+ if ((IsA(left_expr, Const)
+ && ((Const*)left_expr)->constisnull)
+ || (IsA(right_expr, Const)
+ && ((Const*)right_expr)->constisnull))
+ {
+ if (list_cell_number(rcexpr->opnos, l_opno) == 0)
+ return CCT_CONSTF;
+ lasteva = false;
+ break; /* The rest of pairs are dominated by the NULL, ignore them. */
+ }
+ if (equal(left_expr, right_expr))
+ {
+ if (!contain_volatile_functions((Node*)left_expr))
+ {
+ if (!IsA(left_expr, Const))
+ {
+ NullTest *nulltest = makeNode(NullTest);
+ nulltest->arg = left_expr;
+ nulltest->nulltesttype = IS_NOT_NULL;
+ nulltest->argisrow = false;
+ nulltest->location = -1;
+ rce = palloc0(sizeof(RowCompElem));
+ rce->contact = (Expr*)nulltest;
+ rcelst = lappend(rcelst, rce);
+ }
+ /* IF the last operator is > or <, the last sub-expr must be failed. */
+ if (l_opno == list_last_cell(rcexpr->opnos))
+ {
+ strat = get_op_opfamily_strategy(opno, opfamily);
+ if (strat == BTLessStrategyNumber || strat == BTGreaterStrategyNumber)
+ lasteva = false;
+ else
+ lasteva = true;
+ if (lasteva)
+ {
+ arglst = NIL;
+ foreach(lc, rcelst)
+ {
+ arglst = lappend(arglst, ((RowCompElem*)lfirst(lc))->contact);
+ }
+ goto lab_built;
+ }
+ else
+ break;
+ }
+ continue;
+ }
+ else
+ {
+ /* Forget this rcexpr, cann't do anything more. */
+ *transformed = NULL;
+ return 0;
+ }
+ }
+
+ /* If Const Op Const and are not equal. It's need to evaluate
+ * the expt is positive or not.
+ */
+ if (IsA(left_expr, Const) && IsA(right_expr, Const))
+ {
+ opfuncid = get_opcode(opno);
+ fmgr_info(opfuncid, &op_func);
+ result = DatumGetBool(FunctionCall2Coll(&op_func,
+ inputcollid,
+ ((Const *) left_expr)->constvalue,
+ ((Const *) right_expr)->constvalue));
+ if (result)
+ {
+ if (list_cell_number(rcexpr->opnos, l_opno) == 0)
+ return CCT_CONSTT;
+ else
+ {
+ arglst = NIL;
+ foreach(lc, rcelst)
+ {
+ arglst = lappend(arglst, ((RowCompElem*)lfirst(lc))->contact);
+ }
+ if (list_length(arglst) == 1)
+ {
+ orclause->args = lappend(orclause->args, linitial(arglst));
+ }
+ else if (list_length(arglst) > 1)
+ {
+ andclause = (BoolExpr*) make_andclause(arglst);
+ orclause->args = lappend(orclause->args, andclause);
+ }
+ lasteva = true;
+ break;
+ }
+ }
+ else
+ {
+ if (list_cell_number(rcexpr->opnos, l_opno) == 0)
+ return CCT_CONSTF;
+ else
+ {
+ lasteva = false;
+ break;
+ }
+ }
+ }
+
+ /* Only accept Var op Const, others cause the rcexpr will be ignored. */
+ if (!(IsA(left_expr, Const) || IsA(right_expr, Const)))
+ {
+ *transformed = NULL;
+ return 0;
+ }
+
+ if (IsA(left_expr, Const))
+ {
+ opno = get_commutator(opno);
+ tmp_expr = left_expr;
+ left_expr = right_expr;
+ right_expr = tmp_expr;
+ }
+
+ tmp_expr = left_expr;
+ if (IsA(left_expr, RelabelType))
+ {
+ left_type = ((RelabelType *) left_expr)->resulttype;
+ varcollid = ((RelabelType *) left_expr)->resultcollid;
+ left_expr = ((RelabelType *) left_expr)->arg;
+ }
+
+ if (IsA(left_expr, Var))
+ {
+ left_type = ((Var *) left_expr)->vartype;
+ varcollid = ((Var *) left_expr)->varcollid;
+ }
+ else
+ {
+ *transformed = NULL;
+ return 0;
+ }
+ right_type = ((Const *) right_expr)->consttype;
+ if ( left_type != right_type
+ || inputcollid != varcollid) /* Don't spend much effort for other types, so skip it */
+
+ {
+ *transformed = NULL;
+ return 0;
+ }
+ /* Built sub expr. */
+ rce = palloc0(sizeof(RowCompElem));
+ rce->opid = opno;
+ eqid = get_opfamily_member(opfamily, left_type, left_type, BTEqualStrategyNumber);
+ newclause = make_opclause(eqid,
+ BOOLOID,
+ false,
+ tmp_expr,
+ right_expr,
+ InvalidOid,
+ inputcollid);
+ rce->contact = newclause;
+ strat = get_op_opfamily_strategy(opno, opfamily);
+ if (strat == BTLessEqualStrategyNumber)
+ rce->stricter_opid = get_opfamily_member(opfamily, left_type, left_type, BTLessStrategyNumber);
+ else if (strat == BTGreaterEqualStrategyNumber)
+ rce->stricter_opid = get_opfamily_member(opfamily, left_type, left_type, BTGreaterStrategyNumber);
+ else
+ rce->stricter_opid = opno;
+
+ if (l_opno == list_last_cell(rcexpr->opnos))
+ opno = rce->opid;
+ else
+ opno = rce->stricter_opid;
+ newclause = make_opclause(opno,
+ BOOLOID,
+ false,
+ tmp_expr,
+ right_expr,
+ InvalidOid,
+ inputcollid);
+
+ arglst = NIL;
+ foreach(lc, rcelst)
+ {
+ arglst = lappend(arglst, ((RowCompElem*)lfirst(lc))->contact);
+ }
+ arglst = lappend(arglst, newclause);
+ rcelst = lappend(rcelst, rce);
+
+lab_built:
+ if (list_length(arglst) == 1)
+ {
+ orclause->args = lappend(orclause->args, linitial(arglst));
+ }
+ else if (list_length(arglst) > 1)
+ {
+ andclause = (BoolExpr*)make_andclause(NIL);
+ andclause->args = arglst;
+ orclause->args = lappend(orclause->args, andclause);
+ }
+ }
+
+ /* If or-clause args is empty, that mean all of pairs of elements
+ * are const equal, so check the result of last sub-expr.
+ */
+ if (orclause->args == NIL)
+ {
+ if (lasteva)
+ return CCT_CONSTT;
+ else
+ return CCT_CONSTF;
+ }
+
+ if (list_length(orclause->args) == 1)
+ {
+ *transformed = linitial(orclause->args);
+ }
+ else
+ *transformed = (Expr*)orclause;
+#ifdef DEBUG_ROW_DECODE
+ elog(NOTICE, "ROW COMPARSION TO NONCONSTRUCTOR: %s", nodeToString(*transformed));
+#endif
+ return 0;
+}
+
+
+/*
+ * self_contradictory_recurse
+ * Extract particulares of implict-AND clauses list
+ * passed in and check whether it
+ * is self contradictory or not. During the time of invoking routine
+ * also do the following jobs pruning and replacing and deleting clause.
+ *
+ * Returned value:
+ * 0: it's Ok.
+ * 1: is self-contradictory
+ * Function expect a couple of caluse that mean these clauses are
+ * implict-AND caluses. Once a pair of clauses or a clause are
+ * self-contradictory report to the caller immediately.
+ * A or-clause is a bit tricky, it's need to check every arg, if
+ * sub-arg is self-contradictory abandon it. After recursion
+ * if all of them are self contradictory that mean the or-clause
+ * is self contradictory and report to the caller, else rebuilt the
+ * or-clause (eg. x > 2 and x < 1 or y >3 in the case x > 2 and x < 1
+ * will be eliminated, the output expression is y > 3 ).
+ * We can push other expressions these have the same semantic level
+ * with OR-expression down into the OR-expression
+ * (eg. (x > 2 and x < 1 or y > 3) and y < 2, y < 2 will be
+ * push down to sub-arg y > 3, this clause is self-contradictory).
+ */
+static int self_contradictory_recurse(List *node,
+ ExtractedAttris *ea,
+ ClauseCxtWapper *ccw,
+ SelfExamContext *sec)
+{
+ int ret = 0;
+ int i;
+ Expr *inter_node;
+ VarattInfo *att_elem;
+ ListCell *lc;
+ ClauseContext *clausecxt;
+ NullTest *nt_node;
+ Var *varnode;
+ ExtractedAttris ea_info;
+ ClauseCxtWapper orccw;
+
+ ea_info.addOp = false;
+ ea_info.min_attr = sec->attrsdc.min_attr;
+ ea_info.att_lst = NULL;
+ ea_info.upper_ea = NULL;
+ ea_info.array_vi = palloc0((sec->attrsdc.max_attr - sec->attrsdc.min_attr + 1) * sizeof(VarattInfo*));
+ orccw.clausecxt = NIL;
+ if (ea)
+ ea_info.upper_ea = ea;
+
+ if (IsA(node, List))
+ {
+ i = -1;
+ foreach(lc, (List*) node)
+ {
+ inter_node = lfirst(lc);
+ i++;
+ if (IsA(inter_node, RestrictInfo))
+ {
+ RestrictInfo *rinfo = (RestrictInfo *) inter_node;
+ if (rinfo->pseudoconstant)
+ continue;
+ inter_node = rinfo->clause;
+ if (rinfo->fromec)
+ {
+ clausecxt = get_clause_cxt_internal(sec);
+ clausecxt->cct = CCT_DEL;
+ clausecxt->idx = i;
+ ccw->clausecxt = lappend(ccw->clausecxt, clausecxt);
+ }
+ }
+ if (IsA(inter_node, Var))
+ {
+ varnode = (Var*) inter_node;
+ if (varnode->vartype == BOOLOID)
+ {
+ att_elem = get_varatt_info_internal(sec, &ea_info, varnode);
+ att_elem->bool_test |= BT_MARK | BT_IS_TRUE;
+ ea_info.addOp = true;
+ }
+ }
+ else if (IsA(inter_node, BoolExpr))
+ {
+ /*
+ * It's need to postpone the or-expr, then the same
+ * level simple expr can be push down.
+ */
+ BoolExpr *boolnode;
+ boolnode = (BoolExpr*) inter_node;
+ if (boolnode->boolop == NOT_EXPR
+ && list_length(boolnode->args) == 1
+ && IsA(linitial(boolnode->args), Var))
+ {
+ varnode = (Var*) linitial(boolnode->args);
+ if (varnode->vartype == BOOLOID)
+ {
+ att_elem = get_varatt_info_internal(sec, &ea_info, varnode);
+ att_elem->bool_test |= BT_MARK | BT_IS_FALSE;
+ ea_info.addOp = true;
+ }
+ }
+ else
+ {
+ clausecxt = get_clause_cxt_internal(sec);
+ clausecxt->idx = i;
+ clausecxt->cxt = inter_node;
+ clausecxt->origin = inter_node;
+ orccw.clausecxt = lappend(orccw.clausecxt, clausecxt);
+ }
+ }
+ else if (IsA(inter_node, NullTest))
+ {
+ nt_node = (NullTest *)inter_node;
+ if (!nt_node->argisrow && nt_node->arg)
+ {
+ if(!deconstruct_nulltest_attr((Node *)nt_node->arg,
+ nt_node->nulltesttype, sec, &ea_info))
+ EXAMINE_ABORT(1);
+ ea_info.addOp = true;
+ }
+ }
+ else if (IsA(inter_node, BooleanTest))
+ {
+ Node *basenode;
+
+ BooleanTest *btest = (BooleanTest *) inter_node;
+ if (IsA(btest->arg, RelabelType))
+ basenode = (Node *) ((RelabelType *) btest->arg)->arg;
+ else
+ basenode = (Node *)btest->arg;
+ if (basenode && IsA(basenode, Var))
+ {
+ att_elem = get_varatt_info_internal(sec, &ea_info, (Var *) btest->arg);
+ switch (btest->booltesttype)
+ {
+ case IS_TRUE:
+ att_elem->bool_test |= BT_MARK | BT_IS_TRUE;
+ break;
+ case IS_NOT_TRUE:
+ att_elem->bool_test |= BT_MARK | BT_IS_NOT_TRUE;
+ break;
+ case IS_FALSE:
+ att_elem->bool_test |= BT_MARK | BT_IS_FALSE;
+ break;
+ case IS_NOT_FALSE:
+ att_elem->bool_test |= BT_MARK | BT_IS_NOT_FALSE;
+ break;
+ case IS_UNKNOWN:
+ att_elem->bool_test |= BT_MARK | BT_IS_UNKNOWN;
+ break;
+ case IS_NOT_UNKNOWN:
+ att_elem->bool_test |= BT_MARK | BT_IS_NOT_UNKNOWN;
+ break;
+ default:
+ elog(ERROR, "unrecognized booltesttype: %d",
+ (int) btest->booltesttype);
+ break;
+ }
+ ea_info.addOp = true;
+ }
+ }
+ else if (IsA(inter_node, OpExpr))
+ {
+ OpExpr *opexpr;
+ opexpr = (OpExpr *) inter_node;
+ if (list_length(opexpr->args) != 2)
+ continue;
+ if (!extract_binary_op_clause_info(opexpr,
+ linitial(opexpr->args),
+ lsecond(opexpr->args),
+ i,
+ opexpr->opno,
+ opexpr->inputcollid,
+ sec,
+ &ea_info,
+ ccw))
+ EXAMINE_ABORT(1);
+ }
+ else if (IsA(inter_node, ScalarArrayOpExpr))
+ {
+ ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) inter_node;
+ if (list_length(saop->args) != 2)
+ continue;
+ if (!extract_binary_op_clause_info(saop,
+ linitial(saop->args),
+ lsecond(saop->args),
+ i,
+ saop->opno,
+ saop->inputcollid,
+ sec,
+ &ea_info,
+ ccw))
+ EXAMINE_ABORT(1);
+ }
+ else if (IsA(inter_node, RowCompareExpr))
+ {
+ Expr *trans;
+ int result;
+ result = row_comparsion_to_nonconstructor(inter_node, &trans);
+ if (result == 0 && trans != NULL)
+ {
+ if (is_orclause(trans))
+ {
+ clausecxt = get_clause_cxt_internal(sec);
+ clausecxt->idx = i;
+ clausecxt->cxt = trans;
+ clausecxt->origin = inter_node;
+ orccw.clausecxt = lappend(orccw.clausecxt, clausecxt);
+ }
+ else if (is_andclause(trans))
+ {
+ /* Must be NullTest expr eg. row(a,b) >= row(a,b) */
+ ListCell *lnt;
+ foreach(lnt, ((BoolExpr*)trans)->args)
+ {
+ Assert(IsA(lfirst(lnt), NullTest));
+ nt_node = lfirst(lnt);
+ if(!deconstruct_nulltest_attr((Node *)nt_node->arg,
+ nt_node->nulltesttype,
+ sec,
+ &ea_info))
+ EXAMINE_ABORT(1);
+ }
+ ea_info.addOp = true;
+ }
+ else if (IsA(trans, OpExpr))
+ {
+ if (!extract_binary_op_clause_info(trans,
+ linitial(((OpExpr*)trans)->args),
+ lsecond(((OpExpr*)trans)->args),
+ i,
+ ((OpExpr*)trans)->opno,
+ ((OpExpr*)trans)->inputcollid,
+ sec,
+ &ea_info,
+ ccw))
+ EXAMINE_ABORT(1);
+ clausecxt = get_clause_cxt_internal(sec);
+ clausecxt->cct = CCT_REPLACE;
+ clausecxt->idx = i;
+ clausecxt->cxt = trans;
+ ccw->clausecxt = lappend(ccw->clausecxt, clausecxt);
+ }
+ else if (IsA(trans, NullTest))
+ {
+ nt_node = (NullTest *)trans;
+ if(!deconstruct_nulltest_attr((Node *)nt_node->arg,
+ nt_node->nulltesttype,
+ sec,
+ &ea_info))
+ EXAMINE_ABORT(1);
+ clausecxt = get_clause_cxt_internal(sec);
+ clausecxt->cct = CCT_REPLACE;
+ clausecxt->idx = i;
+ clausecxt->cxt = trans;
+ ccw->clausecxt = lappend(ccw->clausecxt, clausecxt);
+ }
+ }
+ else if (result == CCT_CONSTT)
+ {
+ /* (eg. row(1,2,3) >= row(1,2,3)) */
+ clausecxt = get_clause_cxt_internal(sec);
+ clausecxt->cct = CCT_CONSTT;
+ clausecxt->idx = i;
+ ccw->clausecxt = lappend(ccw->clausecxt, clausecxt);
+ }
+ else if (result == CCT_CONSTF)
+ EXAMINE_ABORT(1);
+ }
+ }
+ }
+ else
+ {
+ elog(ERROR, "unrecognized node type: %d",
+ (int) nodeTag(node));
+ }
+
+ /* All base particulars had been collected, it's time to examine. */
+ if(self_contradictory_check(sec, &ea_info, ccw))
+ EXAMINE_ABORT(1);
+
+ /* Examine the or-clause that was postponed here because every
+ * OpExpr at same semantic level can be push down ( eg. x > 10 and y > 12 and
+ * ( x < 9 or y < 11) ), this case can be transform to (x > 10 and y > 12 and
+ * x <9) or (x > 10 and y > 12 and y < 11).
+ */
+ foreach(lc, orccw.clausecxt)
+ {
+ ListCell *arg, *lc1;
+ List *arglst, *newraglst;
+ ClauseCxtWapper boolccw;
+ ClauseContext *ccxt;
+ BoolExpr *boolnode;
+ uint8 *delidx;
+ uint8 orchanged;
+ clausecxt = lfirst(lc);
+ boolnode = (BoolExpr *) clausecxt->cxt;
+
+ switch (boolnode->boolop)
+ {
+ case AND_EXPR:
+ delidx = palloc0((list_length(boolnode->args)+1) * sizeof(uint8));
+ delidx++;
+ boolccw.clausecxt = NIL;
+ ret = self_contradictory_recurse(boolnode->args, ea, &boolccw, sec);
+ if (ret > 0)
+ EXAMINE_ABORT(1);
+
+ foreach(lc1, boolccw.clausecxt)
+ {
+ ccxt = lfirst(lc1);
+ delidx[-1] = 0x01;
+ switch (ccxt->cct)
+ {
+ case CCT_DEL:
+ case CCT_CONSTT:
+ delidx[ccxt->idx] = 0x01;
+ break;
+ case CCT_REPLACE:
+ arg = list_nth_cell(boolnode->args, ccxt->idx);
+ /* It's need to be flatten if a and-expr, so flag it. */
+ if (is_andclause(ccxt->cxt))
+ delidx[ccxt->idx] = 0x02;
+ lfirst(arg) = ccxt->cxt;
+ break;
+ default:
+ break;
+ }
+ free_clause_cxt_internal(sec, ccxt);
+ }
+ /* OK, fix the args. */
+ if (delidx[-1])
+ {
+ i = 0;
+ arglst = NIL;
+ newraglst = NIL;
+ foreach(lc1, boolnode->args)
+ {
+ if (delidx[i] == 0x00)
+ arglst = lappend(arglst, lfirst(lc1));
+ else if (delidx[i] == 0x02)
+ newraglst = list_concat(newraglst, ((BoolExpr*)lfirst(lc1))->args);
+ i++;
+ }
+ boolnode->args = list_concat(arglst,newraglst);
+ ccxt = get_clause_cxt_internal(sec);
+ ccxt->idx = clausecxt->idx;
+ /* If the reset of args is empty, that mean the and-expr
+ * is const true, because only weaker restrictive expr will be
+ * delete and the args must be not empty.
+ */
+ if (boolnode->args == NIL)
+ ccxt->cct = CCT_CONSTT;
+ else
+ {
+ ccxt->cct = CCT_REPLACE;
+ if (list_length(boolnode->args) == 1)
+ ccxt->cxt = linitial(boolnode->args);
+ else
+ ccxt->cxt = boolnode;
+ }
+ ccw->clausecxt = lappend(ccw->clausecxt, ccxt);
+ }
+ break;
+ case OR_EXPR:
+ newraglst = NIL;
+ orchanged = 0x0;
+ foreach(arg, boolnode->args)
+ {
+ boolccw.clausecxt = NIL;
+ arglst = list_make1(lfirst(arg));
+ if (self_contradictory_recurse(arglst, &ea_info, &boolccw, sec))
+ {
+ orchanged = 0x01;
+ ret++;
+ }
+ else
+ {
+ Assert(list_length(boolccw.clausecxt) <= 1);
+ if (list_length(boolccw.clausecxt) == 1)
+ {
+ orchanged = 0x01;
+ ccxt = linitial(boolccw.clausecxt);
+ Assert(ccxt->idx == 0);
+ if (ccxt->cct == CCT_REPLACE)
+ lfirst(arg) = ccxt->cxt;
+ else if (ccxt->cct == CCT_CONSTT)
+ {
+ /*
+ * Once found a const true sub-arg, skip checking any others,
+ * the or-expr must be const true.
+ */
+ orchanged = 0x02;
+ free_clause_cxt_internal(sec, ccxt);
+ list_free(arglst);
+ break;
+ }
+ free_clause_cxt_internal(sec, ccxt);
+ }
+ if (is_orclause(lfirst(arg)))
+ newraglst = list_concat(newraglst, ((const BoolExpr *) lfirst(arg))->args);
+ else
+ newraglst = lappend(newraglst, lfirst(arg));
+ }
+ list_free(arglst);
+ }
+ if (ret == list_length(boolnode->args))
+ EXAMINE_ABORT(1);
+#ifndef DEBUG_ROW_DECODE
+ else if (orchanged == 0x01)
+ {
+ /*
+ * RowCompareExpr has been coverted to nonconstructor (OR-expression),
+ * if the number of the or-expr's args is more than
+ * one, it do not has benifit to subsequent planning, so
+ * do not do anything and keep itself.
+ */
+
+ if ((IsA(clausecxt->origin, RowCompareExpr)
+ && list_length(newraglst) != 1))
+ ;
+ else
+#else
+ else if (orchanged == 0x01 || (IsA(clausecxt->origin, RowCompareExpr) && orchanged != 0x02))
+ {
+#endif
+ {
+ ccxt = get_clause_cxt_internal(sec);
+ ccxt->cct = CCT_REPLACE;
+ ccxt->idx = clausecxt->idx;
+ if (list_length(newraglst) == 1)
+ ccxt->cxt = linitial(newraglst);
+ else
+ {
+ boolnode->args = newraglst;
+ ccxt->cxt = boolnode;
+ }
+ ccw->clausecxt = lappend(ccw->clausecxt, ccxt);
+ }
+ }
+ else if (orchanged == 0x02)
+ {
+ ccxt = get_clause_cxt_internal(sec);
+ ccxt->cct = CCT_CONSTT;
+ ccxt->idx = clausecxt->idx;
+ ccw->clausecxt = lappend(ccw->clausecxt, ccxt);
+ }
+ /* If or-expr is not changed, do nothing more. */
+ ret = 0;
+ break;
+ case NOT_EXPR:
+ break;
+ default:
+ elog(ERROR, "unrecognized boolop: %d", (int) boolnode->boolop);
+ break;
+ }
+ free_clause_cxt_internal(sec, clausecxt);
+ }
+
+finished:
+ if (ea_info.att_lst != NULL && ea_info.att_lst == ea_info.last)
+ {
+ free_attinfo_cxt_internal(sec, ea_info.att_lst);
+ }
+ else if (ea_info.att_lst != NULL)
+ {
+ ea_info.last->next = sec->vifree;
+ sec->vifree = ea_info.att_lst;
+ }
+ pfree(ea_info.array_vi);
+ return ret;
+}
+
+/*
+ * examine_self_contradictory_rels
+ *
+ * Examine the base rel's baserestrictinfo to confirm that it's a
+ * self-contradictory rel or not.
+ * Mark the rel as a dummy rel if it's a self-contradictory rel,
+ * this is a huge win for subsequent planning.
+ * Note: deduct will be set true if caller need to process EC.
+ */
+static void examine_self_contradictory_rels(PlannerInfo *root, RelOptInfo *rel, bool deduct)
+{
+ int n;
+ RestrictInfo *restrictinfo;
+ ClauseCxtWapper ccwapper;
+ SelfExamContext sec;
+
+ MemSet(&sec, 0, sizeof(SelfExamContext));
+ /*
+ * Initialize sopcinfo with opclass info. Extract all bt-am opclass
+ * particulars and sort by opcintype.
+ */
+ if (sec.sopcinfo.n_members == 0)
+ {
+ if (!default_opclassinfo_for_am(BTREE_AM_OID, extract_opc_info, &sec.sopcinfo))
+ elog(ERROR, "non default opclass records for AM %d", (int) BTREE_AM_OID);
+ qsort(sec.sopcinfo.opcies, sec.sopcinfo.n_members, sizeof(OpcInfoElement*), opc_element_cmp);
+ }
+
+ /* For every base rel reuse the AttrsDetailsCache memory. */
+ if (!sec.attrsdc.atop_array)
+ {
+ sec.attrsdc.atop_array = palloc0((rel->max_attr - rel->min_attr + 1) * sizeof(AttrOpFamily*));
+ sec.attrsdc.atop_set = palloc0(sizeof(AttrOpFamilySet));
+ }
+ else
+ {
+ AttrOpFamilySet *atfs, *atfs_tmp;
+ atfs = sec.attrsdc.atop_set->next;
+ n = rel->max_attr - rel->min_attr + 1;
+ /* If the number of current rel attri greater than previous rel and reset it. */
+ if (n > sec.attrsdc.max_attr - sec.attrsdc.min_attr + 1)
+ {
+ pfree(sec.attrsdc.atop_array);
+ sec.attrsdc.atop_array = palloc0(n * sizeof(AttrOpFamily*));
+ }
+ else
+ MemSet(sec.attrsdc.atop_array, 0, n * sizeof(AttrOpFamily*));
+ while(atfs)
+ {
+ atfs_tmp = atfs->next;
+ pfree(atfs);
+ atfs = atfs_tmp;
+ }
+ sec.attrsdc.len_set = 0;
+ }
+ sec.attrsdc.min_attr = rel->min_attr;
+ sec.attrsdc.max_attr = rel->max_attr;
+
+ ccwapper.clausecxt = NIL;
+ if (!self_contradictory_recurse(rel->baserestrictinfo, NULL, &ccwapper, &sec))
+ {
+ /* Check any pruned-clause and rebuilt it. */
+ List *arglst;
+ ListCell *br, *lc;
+ ListCell *arg;
+ BoolExpr *expression;
+ RestrictInfo *or_rinfo;
+ ClauseContext *ccxt;
+ bool *delidx = NULL;
+ if (list_length(ccwapper.clausecxt) > 0)
+ {
+ delidx = palloc0((list_length(rel->baserestrictinfo) + 1) * sizeof(bool));
+ delidx++;
+ }
+ foreach(lc, ccwapper.clausecxt)
+ {
+ ccxt = lfirst(lc);
+ br = list_nth_cell(rel->baserestrictinfo, ccxt->idx);
+ restrictinfo = lfirst(br);
+ switch (ccxt->cct)
+ {
+ case CCT_DEL:
+ /* Be carefull if it's keeped from EC,
+ * count baseri_nums because it will be delete below
+ * and can't count it in phase1.
+ */
+ if (deduct && restrictinfo->fromec)
+ rel->baseri_nums++;
+ delidx[-1] = delidx[ccxt->idx] = true;
+ break;
+ case CCT_CONSTT:
+ delidx[-1] = delidx[ccxt->idx] = true;
+ break;
+ case CCT_REPLACE:
+ Assert(!IsA(ccxt->cxt, List));
+ arglst = NIL;
+ if (is_andclause(ccxt->cxt))
+ {
+ expression = ccxt->cxt;
+ arglst = list_concat(arglst, expression->args);
+ }
+ else
+ arglst = lappend(arglst, ccxt->cxt);
+ delidx[-1] = delidx[ccxt->idx] = true;
+ foreach(arg, arglst)
+ {
+ or_rinfo = make_restrictinfo(root,
+ (Expr*) lfirst(arg),
+ restrictinfo->is_pushed_down,
+ restrictinfo->has_clone,
+ restrictinfo->is_clone,
+ restrictinfo->pseudoconstant,
+ restrictinfo->security_level,
+ NULL,
+ restrictinfo->incompatible_relids,
+ restrictinfo->outer_relids);
+ if (deduct)
+ {
+ check_mergejoinable(or_rinfo);
+ if (or_rinfo->mergeopfamilies)
+ {
+ if (restrictinfo->allow_equivalence)
+ {
+ if (process_equivalence(root, &or_rinfo, restrictinfo->jdomain))
+ {
+ rel->baseri_nums++;
+ continue;
+ }
+ if (or_rinfo->mergeopfamilies)
+ initialize_mergeclause_eclasses(root, or_rinfo);
+ }
+ else
+ initialize_mergeclause_eclasses(root, or_rinfo);
+ }
+ }
+ rel->baserestrictinfo = lappend(rel->baserestrictinfo, or_rinfo);
+ }
+ break;
+ default:
+ break;
+ }
+ free_clause_cxt_internal(&sec, ccxt);
+ }
+ if (delidx && delidx[-1])
+ {
+ List *rlist = NIL;
+ int i = 0;
+ foreach(lc, rel->baserestrictinfo)
+ {
+ if (!delidx[i++])
+ rlist = lappend(rlist, lfirst(lc));
+ }
+ rel->baserestrictinfo = rlist;
+ }
+ }
+ else
+ mark_dummy_rel(rel);
+}
+
+/*
+ * examine_self_contradictory_rels_phase1
+ *
+ * Some clause maybe be changed and the reult may match the
+ * EC mechanism, so it's need to add it into the EC.
+ */
+void examine_self_contradictory_rels_phase1(PlannerInfo *root)
+{
+ int rti;
+ RestrictInfo *rinfo;
+
+ for (rti = 1; rti < root->simple_rel_array_size; rti++)
+ {
+ RelOptInfo *rel = root->simple_rel_array[rti];
+ /* There may be empty slots corresponding to non-baserel RTEs */
+ if (rel == NULL)
+ continue;
+ /* Ignore any "otherrels". */
+ if (rel->reloptkind != RELOPT_BASEREL)
+ continue;
+ if (rel->baserestrictinfo == NIL)
+ continue;
+ if (list_length(rel->baserestrictinfo) == 1)
+ {
+ rinfo = linitial(rel->baserestrictinfo);
+ if (rinfo->fromec)
+ {
+ rel->baseri_nums = 1;
+ rel->baserestrictinfo = NIL;
+ continue;
+ }
+ }
+ examine_self_contradictory_rels(root, rel, true);
+ if (!is_dummy_rel(rel))
+ rel->baseri_nums += list_length(rel->baserestrictinfo);
+ }
+}
+
+/*
+ * examine_self_contradictory_rels_phase1
+ *
+ * Only care about rel's baserestrictinfo that had added a EC clause.
+ */
+void examine_self_contradictory_rels_phase2(PlannerInfo *root)
+{
+ int rti;
+ for (rti = 1; rti < root->simple_rel_array_size; rti++)
+ {
+ RelOptInfo *rel = root->simple_rel_array[rti];
+ /* There may be empty slots corresponding to non-baserel RTEs */
+ if (rel == NULL)
+ continue;
+ /* Ignore any "otherrels". */
+ if (rel->reloptkind != RELOPT_BASEREL)
+ continue;
+ if (rel->baserestrictinfo == NIL)
+ continue;
+ if (list_length(rel->baserestrictinfo) == 1)
+ continue;
+ if (is_dummy_rel(rel))
+ continue;
+ if (rel->baseri_nums != list_length(rel->baserestrictinfo))
+ examine_self_contradictory_rels(root, rel, false);
+ }
+}
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index 903c397d40..72445ba859 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -127,7 +127,7 @@ static void distribute_qual_to_rels(PlannerInfo *root, Node *clause,
List **postponed_oj_qual_list);
static bool check_redundant_nullability_qual(PlannerInfo *root, Node *clause);
static Relids get_join_domain_min_rels(PlannerInfo *root, Relids domain_relids);
-static void check_mergejoinable(RestrictInfo *restrictinfo);
+void check_mergejoinable(RestrictInfo *restrictinfo);
static void check_hashjoinable(RestrictInfo *restrictinfo);
static void check_memoizable(RestrictInfo *restrictinfo);
@@ -2534,7 +2534,8 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
relids,
incompatible_relids,
outerjoin_nonnullable);
-
+ restrictinfo->jdomain = jtitem->jdomain;
+ restrictinfo->allow_equivalence = allow_equivalence;
/*
* If it's a join clause, add vars used in the clause to targetlists of
* their relations, so that they will be emitted by the plan nodes that
@@ -2616,7 +2617,16 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
if (maybe_equivalence)
{
if (process_equivalence(root, &restrictinfo, jtitem->jdomain))
+ {
+ /* Distribute to base rel. */
+ int relid;
+ if (bms_get_singleton_member(restrictinfo->required_relids, &relid))
+ {
+ restrictinfo->fromec = true;
+ distribute_restrictinfo_to_rels(root, restrictinfo);
+ }
return;
+ }
/* EC rejected it, so set left_ec/right_ec the hard way ... */
if (restrictinfo->mergeopfamilies) /* EC might have changed this */
initialize_mergeclause_eclasses(root, restrictinfo);
@@ -3519,7 +3529,7 @@ match_foreign_keys_to_quals(PlannerInfo *root)
* the operator is a mergejoinable operator. The arguments can be
* anything --- as long as there are no volatile functions in them.
*/
-static void
+void
check_mergejoinable(RestrictInfo *restrictinfo)
{
Expr *clause = restrictinfo->clause;
diff --git a/src/backend/optimizer/plan/meson.build b/src/backend/optimizer/plan/meson.build
index c3b191cdf8..2f8c32fe5d 100644
--- a/src/backend/optimizer/plan/meson.build
+++ b/src/backend/optimizer/plan/meson.build
@@ -9,4 +9,5 @@ backend_sources += files(
'planner.c',
'setrefs.c',
'subselect.c',
+ 'contradictory.c',
)
diff --git a/src/backend/optimizer/plan/planmain.c b/src/backend/optimizer/plan/planmain.c
index e17d31a5c3..34cc104f1b 100644
--- a/src/backend/optimizer/plan/planmain.c
+++ b/src/backend/optimizer/plan/planmain.c
@@ -187,6 +187,8 @@ query_planner(PlannerInfo *root,
joinlist = deconstruct_jointree(root);
+ examine_self_contradictory_rels_phase1(root);
+
/*
* Reconsider any postponed outer-join quals now that we have built up
* equivalence classes. (This could result in further additions or
@@ -201,6 +203,8 @@ query_planner(PlannerInfo *root,
*/
generate_base_implied_equalities(root);
+ examine_self_contradictory_rels_phase2(root);
+
/*
* We have completed merging equivalence sets, so it's now possible to
* generate pathkeys in canonical form; so compute query_pathkeys and
diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c
index a85dc0d891..bdebae5dbb 100644
--- a/src/backend/utils/cache/lsyscache.c
+++ b/src/backend/utils/cache/lsyscache.c
@@ -1181,6 +1181,45 @@ get_language_name(Oid langoid, bool missing_ok)
/* ---------- OPCLASS CACHE ---------- */
+/*
+ * default_opclassinfo_for_am
+ *
+ * Extract all records these opcdefault is true with specified AM oid.
+ */
+bool
+default_opclassinfo_for_am(Oid amoid, SortOpclassCallback callback, void *infocxt)
+{
+ bool result = false;
+ CatCList *opclist;
+ int i;
+
+ /*
+ * Search through all the specified AM's opclass details to
+ * grab records which opcintype is true.
+ */
+ opclist = SearchSysCacheList1(CLAAMNAMENSP, ObjectIdGetDatum(amoid));
+
+ for (i = 0; i < opclist->n_members; i++)
+ {
+ HeapTuple classtup = &opclist->members[i]->tuple;
+ Form_pg_opclass classform = (Form_pg_opclass) GETSTRUCT(classtup);
+
+ if (classform->opcdefault)
+ {
+ callback(opclist->n_members,
+ classform->oid,
+ classform->opcfamily,
+ classform->opcintype,
+ infocxt);
+ }
+ }
+ if (opclist->n_members > 0)
+ result = true;
+ ReleaseCatCacheList(opclist);
+
+ return result;
+}
+
/*
* get_opclass_family
*
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index add0f9e45f..36d7e2bc21 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -982,6 +982,7 @@ typedef struct RelOptInfo
* used by various scans and joins:
*/
/* RestrictInfo structures (if base rel) */
+ uint32 baseri_nums;
List *baserestrictinfo;
/* cost of evaluating the above */
QualCost baserestrictcost;
@@ -2573,6 +2574,12 @@ typedef struct RestrictInfo
/* the represented clause of WHERE or JOIN */
Expr *clause;
+ JoinDomain *jdomain pg_node_attr(copy_as_scalar, equal_ignore, read_write_ignore);
+
+ bool fromec;
+
+ bool allow_equivalence;
+
/* true if clause was pushed down in level */
bool is_pushed_down;
diff --git a/src/include/optimizer/planmain.h b/src/include/optimizer/planmain.h
index 93137261e4..943e279bd8 100644
--- a/src/include/optimizer/planmain.h
+++ b/src/include/optimizer/planmain.h
@@ -66,6 +66,8 @@ extern Limit *make_limit(Plan *lefttree, Node *limitOffset, Node *limitCount,
*/
extern PGDLLIMPORT int from_collapse_limit;
extern PGDLLIMPORT int join_collapse_limit;
+extern void examine_self_contradictory_rels_phase1(PlannerInfo *root);
+extern void examine_self_contradictory_rels_phase2(PlannerInfo *root);
extern void add_base_rels_to_query(PlannerInfo *root, Node *jtnode);
extern void add_other_rels_to_query(PlannerInfo *root);
diff --git a/src/include/utils/lsyscache.h b/src/include/utils/lsyscache.h
index 20446f6f83..17faf447ef 100644
--- a/src/include/utils/lsyscache.h
+++ b/src/include/utils/lsyscache.h
@@ -61,6 +61,8 @@ typedef struct AttStatsSlot
void *numbers_arr; /* palloc'd numbers array, if any */
} AttStatsSlot;
+typedef void (*SortOpclassCallback) (int nums, Oid opcid, Oid opcfamily, Oid opcintype, void *infocxt);
+
/* Hook for plugins to get control in get_attavgwidth() */
typedef int32 (*get_attavgwidth_hook_type) (Oid relid, AttrNumber attnum);
extern PGDLLIMPORT get_attavgwidth_hook_type get_attavgwidth_hook;
@@ -103,6 +105,7 @@ extern Oid get_constraint_index(Oid conoid);
extern char get_constraint_type(Oid conoid);
extern char *get_language_name(Oid langoid, bool missing_ok);
+extern bool default_opclassinfo_for_am(Oid amoid, SortOpclassCallback callback, void *infocxt);
extern Oid get_opclass_family(Oid opclass);
extern Oid get_opclass_input_type(Oid opclass);
extern bool get_opclass_opfamily_and_input_type(Oid opclass,
--
2.43.0.windows.1
[application/octet-stream] regresssion_patch.diff (151.0K, ../TYCPR01MB6093E2A06F3F8CF8DF17B5CE852E2@TYCPR01MB6093.jpnprd01.prod.outlook.com/4-regresssion_patch.diff)
download | inline diff:
From 065b6fca4a1457b1175fceb64de153716f671376 Mon Sep 17 00:00:00 2001
From: wq <[email protected]>
Date: Mon, 25 Nov 2024 16:32:59 +0800
Subject: [PATCH] Regression test of self contradictory examining on rel's
baserestrictinfo
---
src/test/regress/expected/create_index.out | 46 +-
src/test/regress/expected/equivclass.out | 15 +-
src/test/regress/expected/horology.out | 6 +-
src/test/regress/expected/inherit.out | 6 +-
src/test/regress/expected/join.out | 24 +-
src/test/regress/expected/partition_prune.out | 76 +-
src/test/regress/expected/rowsecurity.out | 18 +-
.../regress/expected/self_contradictory.out | 2607 +++++++++++++++++
src/test/regress/expected/stats_ext.out | 34 +-
src/test/regress/expected/updatable_views.out | 50 +-
src/test/regress/parallel_schedule | 3 +
src/test/regress/sql/self_contradictory.sql | 1481 ++++++++++
12 files changed, 4228 insertions(+), 138 deletions(-)
create mode 100644 src/test/regress/expected/self_contradictory.out
create mode 100644 src/test/regress/sql/self_contradictory.sql
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 1b0a5f0e9e..a0e460ef40 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2275,10 +2275,10 @@ ORDER BY thousand DESC, tenthous DESC;
--
explain (costs off)
SELECT unique1 FROM tenk1 WHERE unique1 IN (1, 42, 7) and unique1 = ANY('{7, 8, 9}');
- QUERY PLAN
-----------------------------------------------------------------------------------------------------
+ QUERY PLAN
+----------------------------------------------
Index Only Scan using tenk1_unique1 on tenk1
- Index Cond: ((unique1 = ANY ('{1,42,7}'::integer[])) AND (unique1 = ANY ('{7,8,9}'::integer[])))
+ Index Cond: (unique1 = 7)
(2 rows)
SELECT unique1 FROM tenk1 WHERE unique1 IN (1, 42, 7) and unique1 = ANY('{7, 8, 9}');
@@ -2302,10 +2302,10 @@ SELECT unique1 FROM tenk1 WHERE unique1 = ANY('{7, 14, 22}') and unique1 = ANY('
explain (costs off)
SELECT unique1 FROM tenk1 WHERE unique1 IN (1, 42, 7) and unique1 = 1;
- QUERY PLAN
----------------------------------------------------------------------------
+ QUERY PLAN
+----------------------------------------------
Index Only Scan using tenk1_unique1 on tenk1
- Index Cond: ((unique1 = ANY ('{1,42,7}'::integer[])) AND (unique1 = 1))
+ Index Cond: (unique1 = 1)
(2 rows)
SELECT unique1 FROM tenk1 WHERE unique1 IN (1, 42, 7) and unique1 = 1;
@@ -2316,10 +2316,10 @@ SELECT unique1 FROM tenk1 WHERE unique1 IN (1, 42, 7) and unique1 = 1;
explain (costs off)
SELECT unique1 FROM tenk1 WHERE unique1 IN (1, 42, 7) and unique1 = 12345;
- QUERY PLAN
--------------------------------------------------------------------------------
- Index Only Scan using tenk1_unique1 on tenk1
- Index Cond: ((unique1 = ANY ('{1,42,7}'::integer[])) AND (unique1 = 12345))
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
(2 rows)
SELECT unique1 FROM tenk1 WHERE unique1 IN (1, 42, 7) and unique1 = 12345;
@@ -2329,10 +2329,10 @@ SELECT unique1 FROM tenk1 WHERE unique1 IN (1, 42, 7) and unique1 = 12345;
explain (costs off)
SELECT unique1 FROM tenk1 WHERE unique1 IN (1, 42, 7) and unique1 >= 42;
- QUERY PLAN
------------------------------------------------------------------------------
+ QUERY PLAN
+----------------------------------------------------
Index Only Scan using tenk1_unique1 on tenk1
- Index Cond: ((unique1 = ANY ('{1,42,7}'::integer[])) AND (unique1 >= 42))
+ Index Cond: ((unique1 >= 42) AND (unique1 = 42))
(2 rows)
SELECT unique1 FROM tenk1 WHERE unique1 IN (1, 42, 7) and unique1 >= 42;
@@ -2343,10 +2343,10 @@ SELECT unique1 FROM tenk1 WHERE unique1 IN (1, 42, 7) and unique1 >= 42;
explain (costs off)
SELECT unique1 FROM tenk1 WHERE unique1 IN (1, 42, 7) and unique1 > 42;
- QUERY PLAN
-----------------------------------------------------------------------------
- Index Only Scan using tenk1_unique1 on tenk1
- Index Cond: ((unique1 = ANY ('{1,42,7}'::integer[])) AND (unique1 > 42))
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
(2 rows)
SELECT unique1 FROM tenk1 WHERE unique1 IN (1, 42, 7) and unique1 > 42;
@@ -2356,10 +2356,10 @@ SELECT unique1 FROM tenk1 WHERE unique1 IN (1, 42, 7) and unique1 > 42;
explain (costs off)
SELECT unique1 FROM tenk1 WHERE unique1 > 9996 and unique1 >= 9999;
- QUERY PLAN
---------------------------------------------------------
+ QUERY PLAN
+----------------------------------------------
Index Only Scan using tenk1_unique1 on tenk1
- Index Cond: ((unique1 > 9996) AND (unique1 >= 9999))
+ Index Cond: (unique1 >= 9999)
(2 rows)
SELECT unique1 FROM tenk1 WHERE unique1 > 9996 and unique1 >= 9999;
@@ -2370,10 +2370,10 @@ SELECT unique1 FROM tenk1 WHERE unique1 > 9996 and unique1 >= 9999;
explain (costs off)
SELECT unique1 FROM tenk1 WHERE unique1 < 3 and unique1 <= 3;
- QUERY PLAN
---------------------------------------------------
+ QUERY PLAN
+----------------------------------------------
Index Only Scan using tenk1_unique1 on tenk1
- Index Cond: ((unique1 < 3) AND (unique1 <= 3))
+ Index Cond: (unique1 < 3)
(2 rows)
SELECT unique1 FROM tenk1 WHERE unique1 < 3 and unique1 <= 3;
diff --git a/src/test/regress/expected/equivclass.out b/src/test/regress/expected/equivclass.out
index 5622750500..970186e5c8 100644
--- a/src/test/regress/expected/equivclass.out
+++ b/src/test/regress/expected/equivclass.out
@@ -143,12 +143,12 @@ explain (costs off)
explain (costs off)
select * from ec1, ec2 where ff = x1 and ff = '42'::int8;
- QUERY PLAN
--------------------------------------------------------------------
+ QUERY PLAN
+-----------------------------------------
Nested Loop
Join Filter: (ec1.ff = ec2.x1)
-> Index Scan using ec1_pkey on ec1
- Index Cond: ((ff = '42'::bigint) AND (ff = '42'::bigint))
+ Index Cond: (ff = '42'::bigint)
-> Seq Scan on ec2
(5 rows)
@@ -233,13 +233,12 @@ explain (costs off)
union all
select ff + 4 as x from ec1) as ss1
where ss1.x = ec1.f1 and ec1.ff = 42::int8 and ec1.ff = ec1.f1;
- QUERY PLAN
--------------------------------------------------------------------
+ QUERY PLAN
+-----------------------------------------------------------
Nested Loop
Join Filter: ((((ec1_1.ff + 2) + 1)) = ec1.f1)
-> Index Scan using ec1_pkey on ec1
- Index Cond: ((ff = '42'::bigint) AND (ff = '42'::bigint))
- Filter: (ff = f1)
+ Index Cond: (ff = '42'::bigint)
-> Append
-> Index Scan using ec1_expr2 on ec1 ec1_1
Index Cond: (((ff + 2) + 1) = '42'::bigint)
@@ -247,7 +246,7 @@ explain (costs off)
Index Cond: (((ff + 3) + 1) = '42'::bigint)
-> Index Scan using ec1_expr4 on ec1 ec1_3
Index Cond: ((ff + 4) = '42'::bigint)
-(12 rows)
+(11 rows)
explain (costs off)
select * from ec1,
diff --git a/src/test/regress/expected/horology.out b/src/test/regress/expected/horology.out
index 6d7dd5c988..4e075d6cdf 100644
--- a/src/test/regress/expected/horology.out
+++ b/src/test/regress/expected/horology.out
@@ -2541,11 +2541,11 @@ select count(*) from date_tbl
explain (costs off)
select count(*) from date_tbl
where f1 between symmetric '1997-01-01' and '1998-01-01';
- QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------------
+ QUERY PLAN
+-----------------------------------------------------------------------------
Aggregate
-> Seq Scan on date_tbl
- Filter: (((f1 >= '01-01-1997'::date) AND (f1 <= '01-01-1998'::date)) OR ((f1 >= '01-01-1998'::date) AND (f1 <= '01-01-1997'::date)))
+ Filter: ((f1 >= '01-01-1997'::date) AND (f1 <= '01-01-1998'::date))
(3 rows)
select count(*) from date_tbl
diff --git a/src/test/regress/expected/inherit.out b/src/test/regress/expected/inherit.out
index bb81f6d2b4..c8ad0af7a4 100644
--- a/src/test/regress/expected/inherit.out
+++ b/src/test/regress/expected/inherit.out
@@ -2766,10 +2766,10 @@ explain (costs off) select * from list_parted where a in ('ab', 'cd', 'ef');
(5 rows)
explain (costs off) select * from list_parted where a = 'ab' or a in (null, 'cd');
- QUERY PLAN
----------------------------------------------------------------------------------
+ QUERY PLAN
+----------------------------------------------------------
Seq Scan on part_ab_cd list_parted
- Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
+ Filter: (((a)::text = 'ab'::text) OR (a = 'cd'::text))
(2 rows)
explain (costs off) select * from list_parted where a = 'ab';
diff --git a/src/test/regress/expected/join.out b/src/test/regress/expected/join.out
index ebf2e3f851..a8115414bf 100644
--- a/src/test/regress/expected/join.out
+++ b/src/test/regress/expected/join.out
@@ -8001,15 +8001,17 @@ where j1.id1 % 1000 = 1 and j2.id1 % 1000 = 1;
explain (costs off) select * from j1
inner join j2 on j1.id1 = j2.id1 and j1.id2 = j2.id2
where j1.id1 % 1000 = 1 and j2.id1 % 1000 = 1 and j2.id1 = any (array[1]);
- QUERY PLAN
-----------------------------------------------------
+ QUERY PLAN
+-------------------------------------------
Merge Join
- Merge Cond: (j1.id1 = j2.id1)
- Join Filter: (j2.id2 = j1.id2)
- -> Index Scan using j1_id1_idx on j1
- -> Index Scan using j2_id1_idx on j2
- Index Cond: (id1 = ANY ('{1}'::integer[]))
-(6 rows)
+ Merge Cond: (j1.id2 = j2.id2)
+ -> Index Only Scan using j1_pkey on j1
+ Index Cond: (id1 = 1)
+ Filter: ((id1 % 1000) = 1)
+ -> Index Only Scan using j2_pkey on j2
+ Index Cond: (id1 = 1)
+ Filter: ((id1 % 1000) = 1)
+(8 rows)
select * from j1
inner join j2 on j1.id1 = j2.id1 and j1.id2 = j2.id2
@@ -8024,14 +8026,14 @@ where j1.id1 % 1000 = 1 and j2.id1 % 1000 = 1 and j2.id1 = any (array[1]);
explain (costs off) select * from j1
inner join j2 on j1.id1 = j2.id1 and j1.id2 = j2.id2
where j1.id1 % 1000 = 1 and j2.id1 % 1000 = 1 and j2.id1 >= any (array[1,5]);
- QUERY PLAN
--------------------------------------------------------
+ QUERY PLAN
+-----------------------------------------
Merge Join
Merge Cond: (j1.id1 = j2.id1)
Join Filter: (j2.id2 = j1.id2)
-> Index Scan using j1_id1_idx on j1
-> Index Scan using j2_id1_idx on j2
- Index Cond: (id1 >= ANY ('{1,5}'::integer[]))
+ Index Cond: (id1 >= 1)
(6 rows)
select * from j1
diff --git a/src/test/regress/expected/partition_prune.out b/src/test/regress/expected/partition_prune.out
index 7a03b4e360..5debaf4ca0 100644
--- a/src/test/regress/expected/partition_prune.out
+++ b/src/test/regress/expected/partition_prune.out
@@ -632,10 +632,10 @@ explain (costs off) select * from rlp3 where a = 20; /* empty */
-- redundant clauses are eliminated
explain (costs off) select * from rlp where a > 1 and a = 10; /* only default */
- QUERY PLAN
-----------------------------------
+ QUERY PLAN
+--------------------------------
Seq Scan on rlp_default_10 rlp
- Filter: ((a > 1) AND (a = 10))
+ Filter: (a = 10)
(2 rows)
explain (costs off) select * from rlp where a > 1 and a >=15; /* rlp3 onwards, including default */
@@ -643,27 +643,27 @@ explain (costs off) select * from rlp where a > 1 and a >=15; /* rlp3 onwards, i
----------------------------------------------
Append
-> Seq Scan on rlp3abcd rlp_1
- Filter: ((a > 1) AND (a >= 15))
+ Filter: (a >= 15)
-> Seq Scan on rlp3efgh rlp_2
- Filter: ((a > 1) AND (a >= 15))
+ Filter: (a >= 15)
-> Seq Scan on rlp3nullxy rlp_3
- Filter: ((a > 1) AND (a >= 15))
+ Filter: (a >= 15)
-> Seq Scan on rlp3_default rlp_4
- Filter: ((a > 1) AND (a >= 15))
+ Filter: (a >= 15)
-> Seq Scan on rlp4_1 rlp_5
- Filter: ((a > 1) AND (a >= 15))
+ Filter: (a >= 15)
-> Seq Scan on rlp4_2 rlp_6
- Filter: ((a > 1) AND (a >= 15))
+ Filter: (a >= 15)
-> Seq Scan on rlp4_default rlp_7
- Filter: ((a > 1) AND (a >= 15))
+ Filter: (a >= 15)
-> Seq Scan on rlp5_1 rlp_8
- Filter: ((a > 1) AND (a >= 15))
+ Filter: (a >= 15)
-> Seq Scan on rlp5_default rlp_9
- Filter: ((a > 1) AND (a >= 15))
+ Filter: (a >= 15)
-> Seq Scan on rlp_default_30 rlp_10
- Filter: ((a > 1) AND (a >= 15))
+ Filter: (a >= 15)
-> Seq Scan on rlp_default_default rlp_11
- Filter: ((a > 1) AND (a >= 15))
+ Filter: (a >= 15)
(23 rows)
explain (costs off) select * from rlp where a = 1 and a = 3; /* empty */
@@ -674,20 +674,18 @@ explain (costs off) select * from rlp where a = 1 and a = 3; /* empty */
(2 rows)
explain (costs off) select * from rlp where (a = 1 and a = 3) or (a > 1 and a = 15);
- QUERY PLAN
--------------------------------------------------------------------
+ QUERY PLAN
+--------------------------------------
Append
- -> Seq Scan on rlp2 rlp_1
- Filter: (((a = 1) AND (a = 3)) OR ((a > 1) AND (a = 15)))
- -> Seq Scan on rlp3abcd rlp_2
- Filter: (((a = 1) AND (a = 3)) OR ((a > 1) AND (a = 15)))
- -> Seq Scan on rlp3efgh rlp_3
- Filter: (((a = 1) AND (a = 3)) OR ((a > 1) AND (a = 15)))
- -> Seq Scan on rlp3nullxy rlp_4
- Filter: (((a = 1) AND (a = 3)) OR ((a > 1) AND (a = 15)))
- -> Seq Scan on rlp3_default rlp_5
- Filter: (((a = 1) AND (a = 3)) OR ((a > 1) AND (a = 15)))
-(11 rows)
+ -> Seq Scan on rlp3abcd rlp_1
+ Filter: (a = 15)
+ -> Seq Scan on rlp3efgh rlp_2
+ Filter: (a = 15)
+ -> Seq Scan on rlp3nullxy rlp_3
+ Filter: (a = 15)
+ -> Seq Scan on rlp3_default rlp_4
+ Filter: (a = 15)
+(9 rows)
-- multi-column keys
create table mc3p (a int, b int, c int) partition by range (a, abs(b), c);
@@ -1561,10 +1559,10 @@ explain (costs off) select * from coercepart where a = any ('{ab,bc}');
(5 rows)
explain (costs off) select * from coercepart where a = any ('{ab,null}');
- QUERY PLAN
----------------------------------------------------
+ QUERY PLAN
+--------------------------------------
Seq Scan on coercepart_ab coercepart
- Filter: ((a)::text = ANY ('{ab,NULL}'::text[]))
+ Filter: (a = 'ab'::text)
(2 rows)
explain (costs off) select * from coercepart where a = any (null::text[]);
@@ -1575,10 +1573,10 @@ explain (costs off) select * from coercepart where a = any (null::text[]);
(2 rows)
explain (costs off) select * from coercepart where a = all ('{ab}');
- QUERY PLAN
-----------------------------------------------
+ QUERY PLAN
+--------------------------------------
Seq Scan on coercepart_ab coercepart
- Filter: ((a)::text = ALL ('{ab}'::text[]))
+ Filter: (a = 'ab'::text)
(2 rows)
explain (costs off) select * from coercepart where a = all ('{ab,bc}');
@@ -4174,20 +4172,20 @@ create table rp_prefix_test3_p2 partition of rp_prefix_test3 for values from (2,
-- Test that get_steps_using_prefix() handles a prefix that contains multiple
-- clauses for the partition key b (ie, b >= 1 and b >= 2)
explain (costs off) select * from rp_prefix_test3 where a >= 1 and b >= 1 and b >= 2 and c >= 2 and d >= 0;
- QUERY PLAN
---------------------------------------------------------------------------
+ QUERY PLAN
+-------------------------------------------------------------
Seq Scan on rp_prefix_test3_p2 rp_prefix_test3
- Filter: ((a >= 1) AND (b >= 1) AND (b >= 2) AND (c >= 2) AND (d >= 0))
+ Filter: ((a >= 1) AND (b >= 2) AND (c >= 2) AND (d >= 0))
(2 rows)
-- Test that get_steps_using_prefix() handles a prefix that contains multiple
-- clauses for the partition key b (ie, b >= 1 and b = 2) (This also tests
-- that the caller arranges clauses in that prefix in the required order)
explain (costs off) select * from rp_prefix_test3 where a >= 1 and b >= 1 and b = 2 and c = 2 and d >= 0;
- QUERY PLAN
-------------------------------------------------------------------------
+ QUERY PLAN
+-----------------------------------------------------------
Seq Scan on rp_prefix_test3_p2 rp_prefix_test3
- Filter: ((a >= 1) AND (b >= 1) AND (d >= 0) AND (b = 2) AND (c = 2))
+ Filter: ((a >= 1) AND (d >= 0) AND (b = 2) AND (c = 2))
(2 rows)
drop table rp_prefix_test1;
diff --git a/src/test/regress/expected/rowsecurity.out b/src/test/regress/expected/rowsecurity.out
index fd5654df35..04f99ccf78 100644
--- a/src/test/regress/expected/rowsecurity.out
+++ b/src/test/regress/expected/rowsecurity.out
@@ -1934,21 +1934,21 @@ INSERT INTO bv1 VALUES (11, 'xxx'); -- should fail RLS check
ERROR: new row violates row-level security policy for table "b1"
INSERT INTO bv1 VALUES (12, 'xxx'); -- ok
EXPLAIN (COSTS OFF) UPDATE bv1 SET b = 'yyy' WHERE a = 4 AND f_leak(b);
- QUERY PLAN
------------------------------------------------------------------------
+ QUERY PLAN
+-----------------------------------------------------------
Update on b1
-> Seq Scan on b1
- Filter: ((a > 0) AND (a = 4) AND ((a % 2) = 0) AND f_leak(b))
+ Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b))
(3 rows)
UPDATE bv1 SET b = 'yyy' WHERE a = 4 AND f_leak(b);
NOTICE: f_leak => 4b227777d4dd1fc61c6f884f48641d02
EXPLAIN (COSTS OFF) DELETE FROM bv1 WHERE a = 6 AND f_leak(b);
- QUERY PLAN
------------------------------------------------------------------------
+ QUERY PLAN
+-----------------------------------------------------------
Delete on b1
-> Seq Scan on b1
- Filter: ((a > 0) AND (a = 6) AND ((a % 2) = 0) AND f_leak(b))
+ Filter: ((a = 6) AND ((a % 2) = 0) AND f_leak(b))
(3 rows)
DELETE FROM bv1 WHERE a = 6 AND f_leak(b);
@@ -3085,10 +3085,10 @@ SET SESSION AUTHORIZATION regress_rls_bob;
CREATE VIEW rls_sbv WITH (security_barrier) AS
SELECT * FROM y1 WHERE f_leak(b);
EXPLAIN (COSTS OFF) SELECT * FROM rls_sbv WHERE (a = 1);
- QUERY PLAN
-------------------------------------------------------------------
+ QUERY PLAN
+-----------------------------------------------------
Seq Scan on y1
- Filter: ((a = 1) AND ((a > 2) OR ((a % 2) = 0)) AND f_leak(b))
+ Filter: ((a = 1) AND ((a % 2) = 0) AND f_leak(b))
(2 rows)
DROP VIEW rls_sbv;
diff --git a/src/test/regress/expected/self_contradictory.out b/src/test/regress/expected/self_contradictory.out
new file mode 100644
index 0000000000..3d7cdcb333
--- /dev/null
+++ b/src/test/regress/expected/self_contradictory.out
@@ -0,0 +1,2607 @@
+--
+-- SELF CONTRADICTORY
+--
+-- Create table
+--
+CREATE TABLE self_a (a INT, b INT, c INT, d INT, z BOOL);
+CREATE TABLE self_b (a VARCHAR(6));
+--INSERT INTO self_a
+--SELECT ceil(rANDom()*(1000-1)+1) ,
+--ceil(RANDOM()*(1000-1)+1) ,
+--ceil(RANDOM()*(1000-1)+1) ,
+--ceil(RANDOM()*(1000-1)+1) ,
+--(RANDOM())::int::bool
+--FROM generate_series(1 , 300);
+--Load data
+--
+INSERT INTO self_a VALUES (56 , 118 , 32 , 780 , true);
+INSERT INTO self_a VALUES (854 , 610 , 991 , 526 , false);
+INSERT INTO self_a VALUES (837 , 872 , 417 , 130 , true);
+INSERT INTO self_a VALUES (193 , 326 , 902 , 976 , false);
+INSERT INTO self_a VALUES (414 , 913 , 549 , 289 , true);
+INSERT INTO self_a VALUES (733 , 159 , 285 , 496 , false);
+INSERT INTO self_a VALUES (44 , 253 , 569 , 357 , true);
+INSERT INTO self_a VALUES (269 , 39 , 540 , 941 , true);
+INSERT INTO self_a VALUES (807 , 974 , 329 , 4 , false);
+INSERT INTO self_a VALUES (392 , 582 , 559 , 657 , true);
+INSERT INTO self_a VALUES (836 , 337 , 672 , 303 , false);
+INSERT INTO self_a VALUES (241 , 161 , 464 , 926 , true);
+INSERT INTO self_a VALUES (569 , 792 , 682 , 462 , false);
+INSERT INTO self_a VALUES (994 , 629 , 653 , 562 , true);
+INSERT INTO self_a VALUES (614 , 505 , 543 , 510 , false);
+INSERT INTO self_a VALUES (796 , 634 , 72 , 519 , false);
+INSERT INTO self_a VALUES (982 , 357 , 767 , 752 , true);
+INSERT INTO self_a VALUES (318 , 13 , 119 , 148 , false);
+INSERT INTO self_a VALUES (568 , 940 , 548 , 426 , true);
+INSERT INTO self_a VALUES (356 , 732 , 660 , 303 , true);
+INSERT INTO self_a VALUES (332 , 755 , 409 , 493 , true);
+INSERT INTO self_a VALUES (263 , 710 , 622 , 40 , false);
+INSERT INTO self_a VALUES (205 , 128 , 909 , 468 , true);
+INSERT INTO self_a VALUES (6 , 514 , 536 , 746 , false);
+INSERT INTO self_a VALUES (153 , 850 , 127 , 470 , true);
+INSERT INTO self_a VALUES (289 , 430 , 843 , 929 , true);
+INSERT INTO self_a VALUES (797 , 168 , 438 , 902 , false);
+INSERT INTO self_a VALUES (870 , 667 , 792 , 275 , false);
+INSERT INTO self_a VALUES (247 , 382 , 911 , 522 , false);
+INSERT INTO self_a VALUES (27 , 203 , 125 , 400 , false);
+INSERT INTO self_a VALUES (153 , 678 , 79 , 278 , false);
+INSERT INTO self_a VALUES (731 , 516 , 81 , 324 , false);
+INSERT INTO self_a VALUES (602 , 648 , 892 , 787 , true);
+INSERT INTO self_a VALUES (691 , 177 , 873 , 183 , false);
+INSERT INTO self_a VALUES (455 , 962 , 675 , 268 , false);
+INSERT INTO self_a VALUES (899 , 679 , 71 , 88 , false);
+INSERT INTO self_a VALUES (755 , 985 , 569 , 555 , false);
+INSERT INTO self_a VALUES (862 , 344 , 659 , 984 , true);
+INSERT INTO self_a VALUES (222 , 163 , 299 , 75 , false);
+INSERT INTO self_a VALUES (139 , 603 , 93 , 681 , false);
+INSERT INTO self_a VALUES (196 , 783 , 85 , 485 , false);
+INSERT INTO self_a VALUES (688 , 963 , 463 , 465 , true);
+INSERT INTO self_a VALUES (804 , 894 , 833 , 52 , false);
+INSERT INTO self_a VALUES (254 , 332 , 481 , 563 , true);
+INSERT INTO self_a VALUES (564 , 43 , 33 , 445 , false);
+INSERT INTO self_a VALUES (283 , 4 , 598 , 347 , true);
+INSERT INTO self_a VALUES (108 , 736 , 693 , 731 , false);
+INSERT INTO self_a VALUES (836 , 502 , 543 , 294 , false);
+INSERT INTO self_a VALUES (900 , 739 , 645 , 132 , true);
+INSERT INTO self_a VALUES (918 , 798 , 360 , 621 , false);
+INSERT INTO self_a VALUES (302 , 998 , 212 , 696 , true);
+INSERT INTO self_a VALUES (711 , 906 , 273 , 384 , false);
+INSERT INTO self_a VALUES (699 , 884 , 563 , 120 , true);
+INSERT INTO self_a VALUES (357 , 456 , 709 , 762 , true);
+INSERT INTO self_a VALUES (708 , 276 , 237 , 862 , false);
+INSERT INTO self_a VALUES (274 , 40 , 478 , 495 , true);
+INSERT INTO self_a VALUES (564 , 973 , 743 , 123 , true);
+INSERT INTO self_a VALUES (195 , 848 , 401 , 908 , false);
+INSERT INTO self_a VALUES (819 , 38 , 449 , 715 , false);
+INSERT INTO self_a VALUES (688 , 549 , 702 , 819 , false);
+INSERT INTO self_a VALUES (242 , 716 , 55 , 88 , true);
+INSERT INTO self_a VALUES (866 , 508 , 610 , 30 , false);
+INSERT INTO self_a VALUES (720 , 558 , 719 , 721 , true);
+INSERT INTO self_a VALUES (895 , 106 , 7 , 231 , false);
+INSERT INTO self_a VALUES (895 , 926 , 991 , 18 , true);
+INSERT INTO self_a VALUES (15 , 49 , 670 , 482 , true);
+INSERT INTO self_a VALUES (499 , 122 , 139 , 68 , false);
+INSERT INTO self_a VALUES (44 , 486 , 900 , 526 , false);
+INSERT INTO self_a VALUES (502 , 390 , 266 , 59 , true);
+INSERT INTO self_a VALUES (197 , 481 , 798 , 954 , true);
+INSERT INTO self_a VALUES (1000 , 512 , 245 , 310 , false);
+INSERT INTO self_a VALUES (207 , 938 , 856 , 191 , true);
+INSERT INTO self_a VALUES (666 , 883 , 47 , 664 , false);
+INSERT INTO self_a VALUES (964 , 852 , 439 , 173 , false);
+INSERT INTO self_a VALUES (294 , 262 , 404 , 259 , false);
+INSERT INTO self_a VALUES (81 , 799 , 100 , 620 , true);
+INSERT INTO self_a VALUES (633 , 272 , 145 , 644 , true);
+INSERT INTO self_a VALUES (287 , 256 , 875 , 53 , false);
+INSERT INTO self_a VALUES (962 , 216 , 696 , 315 , false);
+INSERT INTO self_a VALUES (299 , 875 , 355 , 584 , false);
+INSERT INTO self_a VALUES (645 , 249 , 655 , 667 , true);
+INSERT INTO self_a VALUES (223 , 71 , 627 , 251 , true);
+INSERT INTO self_a VALUES (677 , 849 , 978 , 114 , false);
+INSERT INTO self_a VALUES (130 , 199 , 836 , 596 , false);
+INSERT INTO self_a VALUES (710 , 775 , 416 , 215 , false);
+INSERT INTO self_a VALUES (146 , 621 , 442 , 338 , true);
+INSERT INTO self_a VALUES (924 , 349 , 600 , 116 , false);
+INSERT INTO self_a VALUES (165 , 330 , 678 , 57 , true);
+INSERT INTO self_a VALUES (593 , 187 , 258 , 974 , true);
+INSERT INTO self_a VALUES (951 , 698 , 928 , 139 , false);
+INSERT INTO self_a VALUES (322 , 965 , 961 , 464 , false);
+INSERT INTO self_a VALUES (884 , 683 , 173 , 38 , true);
+INSERT INTO self_a VALUES (701 , 443 , 368 , 748 , true);
+INSERT INTO self_a VALUES (461 , 619 , 15 , 596 , true);
+INSERT INTO self_a VALUES (526 , 364 , 607 , 397 , true);
+INSERT INTO self_a VALUES (13 , 937 , 247 , 801 , false);
+INSERT INTO self_a VALUES (538 , 82 , 145 , 879 , false);
+INSERT INTO self_a VALUES (169 , 168 , 389 , 321 , true);
+INSERT INTO self_a VALUES (405 , 769 , 699 , 908 , true);
+INSERT INTO self_a VALUES (348 , 429 , 644 , 521 , false);
+INSERT INTO self_a VALUES (838 , 877 , 729 , 7 , false);
+INSERT INTO self_a VALUES (989 , 254 , 808 , 71 , true);
+INSERT INTO self_a VALUES (699 , 140 , 379 , 557 , true);
+INSERT INTO self_a VALUES (493 , 671 , 500 , 809 , true);
+INSERT INTO self_a VALUES (177 , 403 , 995 , 70 , true);
+INSERT INTO self_a VALUES (750 , 967 , 470 , 128 , true);
+INSERT INTO self_a VALUES (955 , 473 , 813 , 315 , true);
+INSERT INTO self_a VALUES (742 , 784 , 627 , 420 , false);
+INSERT INTO self_a VALUES (403 , 717 , 646 , 329 , true);
+INSERT INTO self_a VALUES (292 , 990 , 701 , 988 , false);
+INSERT INTO self_a VALUES (79 , 78 , 834 , 834 , false);
+INSERT INTO self_a VALUES (440 , 724 , 690 , 536 , false);
+INSERT INTO self_a VALUES (707 , 875 , 351 , 404 , true);
+INSERT INTO self_a VALUES (945 , 955 , 885 , 897 , false);
+INSERT INTO self_a VALUES (108 , 476 , 668 , 405 , false);
+INSERT INTO self_a VALUES (986 , 343 , 552 , 587 , true);
+INSERT INTO self_a VALUES (629 , 22 , 667 , 504 , true);
+INSERT INTO self_a VALUES (104 , 146 , 576 , 513 , true);
+INSERT INTO self_a VALUES (356 , 991 , 397 , 396 , true);
+INSERT INTO self_a VALUES (899 , 817 , 237 , 392 , true);
+INSERT INTO self_a VALUES (240 , 393 , 590 , 310 , false);
+INSERT INTO self_a VALUES (906 , 573 , 999 , 354 , false);
+INSERT INTO self_a VALUES (907 , 66 , 936 , 59 , false);
+INSERT INTO self_a VALUES (577 , 327 , 245 , 713 , false);
+INSERT INTO self_a VALUES (254 , 271 , 113 , 58 , true);
+INSERT INTO self_a VALUES (326 , 43 , 673 , 87 , true);
+INSERT INTO self_a VALUES (867 , 954 , 699 , 647 , false);
+INSERT INTO self_a VALUES (99 , 826 , 378 , 172 , false);
+INSERT INTO self_a VALUES (158 , 375 , 950 , 802 , false);
+INSERT INTO self_a VALUES (104 , 157 , 523 , 396 , true);
+INSERT INTO self_a VALUES (902 , 125 , 613 , 44 , false);
+INSERT INTO self_a VALUES (564 , 635 , 608 , 48 , true);
+INSERT INTO self_a VALUES (753 , 539 , 692 , 111 , true);
+INSERT INTO self_a VALUES (27 , 613 , 633 , 693 , true);
+INSERT INTO self_a VALUES (859 , 855 , 512 , 28 , false);
+INSERT INTO self_a VALUES (684 , 452 , 757 , 209 , false);
+INSERT INTO self_a VALUES (198 , 591 , 500 , 940 , false);
+INSERT INTO self_a VALUES (442 , 198 , 182 , 663 , true);
+INSERT INTO self_a VALUES (797 , 965 , 909 , 98 , false);
+INSERT INTO self_a VALUES (466 , 665 , 849 , 828 , true);
+INSERT INTO self_a VALUES (615 , 689 , 767 , 773 , false);
+INSERT INTO self_a VALUES (743 , 760 , 860 , 232 , true);
+INSERT INTO self_a VALUES (86 , 444 , 683 , 217 , true);
+INSERT INTO self_a VALUES (772 , 725 , 436 , 862 , true);
+INSERT INTO self_a VALUES (34 , 820 , 627 , 320 , true);
+INSERT INTO self_a VALUES (5 , 437 , 23 , 829 , false);
+INSERT INTO self_a VALUES (697 , 222 , 752 , 984 , true);
+INSERT INTO self_a VALUES (426 , 273 , 972 , 901 , false);
+INSERT INTO self_a VALUES (782 , 610 , 78 , 267 , true);
+INSERT INTO self_a VALUES (238 , 126 , 75 , 601 , true);
+INSERT INTO self_a VALUES (385 , 443 , 912 , 100 , true);
+INSERT INTO self_a VALUES (939 , 715 , 692 , 21 , true);
+INSERT INTO self_a VALUES (108 , 291 , 894 , 132 , false);
+INSERT INTO self_a VALUES (632 , 316 , 108 , 815 , true);
+INSERT INTO self_a VALUES (849 , 847 , 786 , 601 , false);
+INSERT INTO self_a VALUES (218 , 153 , 138 , 574 , true);
+INSERT INTO self_a VALUES (947 , 673 , 758 , 151 , true);
+INSERT INTO self_a VALUES (146 , 807 , 30 , 963 , false);
+INSERT INTO self_a VALUES (748 , 222 , 931 , 664 , true);
+INSERT INTO self_a VALUES (916 , 19 , 100 , 457 , false);
+INSERT INTO self_a VALUES (921 , 287 , 386 , 201 , true);
+INSERT INTO self_a VALUES (521 , 177 , 935 , 268 , true);
+INSERT INTO self_a VALUES (58 , 222 , 195 , 749 , true);
+INSERT INTO self_a VALUES (95 , 430 , 46 , 825 , true);
+INSERT INTO self_a VALUES (290 , 121 , 520 , 759 , false);
+INSERT INTO self_a VALUES (655 , 640 , 203 , 331 , false);
+INSERT INTO self_a VALUES (30 , 950 , 632 , 526 , true);
+INSERT INTO self_a VALUES (997 , 996 , 179 , 575 , true);
+INSERT INTO self_a VALUES (523 , 881 , 463 , 602 , false);
+INSERT INTO self_a VALUES (277 , 298 , 806 , 724 , true);
+INSERT INTO self_a VALUES (601 , 467 , 772 , 305 , false);
+INSERT INTO self_a VALUES (169 , 341 , 646 , 492 , false);
+INSERT INTO self_a VALUES (739 , 718 , 98 , 513 , true);
+INSERT INTO self_a VALUES (91 , 996 , 871 , 954 , true);
+INSERT INTO self_a VALUES (248 , 367 , 704 , 899 , true);
+INSERT INTO self_a VALUES (679 , 192 , 687 , 192 , true);
+INSERT INTO self_a VALUES (840 , 429 , 830 , 93 , false);
+INSERT INTO self_a VALUES (750 , 263 , 652 , 749 , true);
+INSERT INTO self_a VALUES (835 , 478 , 266 , 402 , true);
+INSERT INTO self_a VALUES (264 , 277 , 668 , 230 , true);
+INSERT INTO self_a VALUES (55 , 662 , 473 , 776 , true);
+INSERT INTO self_a VALUES (800 , 594 , 825 , 638 , true);
+INSERT INTO self_a VALUES (549 , 29 , 951 , 607 , false);
+INSERT INTO self_a VALUES (472 , 908 , 939 , 703 , true);
+INSERT INTO self_a VALUES (536 , 969 , 814 , 303 , true);
+INSERT INTO self_a VALUES (316 , 173 , 228 , 312 , false);
+INSERT INTO self_a VALUES (584 , 885 , 329 , 479 , false);
+INSERT INTO self_a VALUES (229 , 716 , 536 , 417 , false);
+INSERT INTO self_a VALUES (177 , 769 , 282 , 339 , true);
+INSERT INTO self_a VALUES (987 , 512 , 477 , 629 , false);
+INSERT INTO self_a VALUES (744 , 252 , 336 , 551 , false);
+INSERT INTO self_a VALUES (655 , 429 , 250 , 603 , true);
+INSERT INTO self_a VALUES (965 , 733 , 863 , 363 , false);
+INSERT INTO self_a VALUES (459 , 276 , 576 , 510 , true);
+INSERT INTO self_a VALUES (626 , 986 , 829 , 345 , false);
+INSERT INTO self_a VALUES (434 , 614 , 655 , 288 , true);
+INSERT INTO self_a VALUES (570 , 17 , 675 , 416 , true);
+INSERT INTO self_a VALUES (882 , 270 , 147 , 862 , false);
+INSERT INTO self_a VALUES (593 , 669 , 145 , 386 , false);
+INSERT INTO self_a VALUES (313 , 369 , 21 , 781 , true);
+INSERT INTO self_a VALUES (869 , 116 , 133 , 611 , true);
+INSERT INTO self_a VALUES (604 , 368 , 695 , 100 , true);
+INSERT INTO self_a VALUES (943 , 847 , 120 , 483 , true);
+INSERT INTO self_a VALUES (396 , 231 , 437 , 772 , false);
+INSERT INTO self_a VALUES (583 , 177 , 580 , 506 , true);
+INSERT INTO self_a VALUES (170 , 542 , 784 , 61 , false);
+INSERT INTO self_a VALUES (978 , 493 , 12 , 236 , false);
+INSERT INTO self_a VALUES (222 , 162 , 612 , 15 , false);
+INSERT INTO self_a VALUES (585 , 138 , 641 , 274 , true);
+INSERT INTO self_a VALUES (246 , 657 , 243 , 852 , true);
+INSERT INTO self_a VALUES (62 , 869 , 96 , 25 , false);
+INSERT INTO self_a VALUES (847 , 224 , 676 , 869 , false);
+INSERT INTO self_a VALUES (211 , 709 , 672 , 470 , true);
+INSERT INTO self_a VALUES (366 , 647 , 964 , 221 , false);
+INSERT INTO self_a VALUES (980 , 847 , 37 , 587 , false);
+INSERT INTO self_a VALUES (450 , 386 , 594 , 112 , false);
+INSERT INTO self_a VALUES (729 , 463 , 931 , 920 , false);
+INSERT INTO self_a VALUES (498 , 604 , 51 , 871 , false);
+INSERT INTO self_a VALUES (464 , 727 , 491 , 891 , false);
+INSERT INTO self_a VALUES (522 , 316 , 82 , 316 , true);
+INSERT INTO self_a VALUES (32 , 27 , 138 , 337 , false);
+INSERT INTO self_a VALUES (733 , 939 , 991 , 449 , true);
+INSERT INTO self_a VALUES (221 , 235 , 992 , 855 , false);
+INSERT INTO self_a VALUES (770 , 463 , 881 , 616 , false);
+INSERT INTO self_a VALUES (558 , 738 , 71 , 74 , false);
+INSERT INTO self_a VALUES (914 , 682 , 217 , 242 , false);
+INSERT INTO self_a VALUES (524 , 444 , 281 , 455 , false);
+INSERT INTO self_a VALUES (778 , 756 , 230 , 393 , false);
+INSERT INTO self_a VALUES (114 , 63 , 606 , 47 , true);
+INSERT INTO self_a VALUES (657 , 625 , 890 , 806 , false);
+INSERT INTO self_a VALUES (988 , 903 , 337 , 739 , true);
+INSERT INTO self_a VALUES (536 , 189 , 430 , 446 , true);
+INSERT INTO self_a VALUES (357 , 44 , 70 , 638 , false);
+INSERT INTO self_a VALUES (540 , 578 , 772 , 484 , true);
+INSERT INTO self_a VALUES (567 , 975 , 658 , 611 , true);
+INSERT INTO self_a VALUES (458 , 747 , 744 , 234 , false);
+INSERT INTO self_a VALUES (695 , 291 , 666 , 535 , false);
+INSERT INTO self_a VALUES (4 , 23 , 607 , 997 , true);
+INSERT INTO self_a VALUES (345 , 401 , 923 , 576 , true);
+INSERT INTO self_a VALUES (634 , 912 , 328 , 860 , true);
+INSERT INTO self_a VALUES (104 , 807 , 925 , 747 , true);
+INSERT INTO self_a VALUES (155 , 19 , 238 , 464 , true);
+INSERT INTO self_a VALUES (569 , 117 , 844 , 808 , false);
+INSERT INTO self_a VALUES (171 , 227 , 751 , 287 , true);
+INSERT INTO self_a VALUES (196 , 762 , 443 , 759 , true);
+INSERT INTO self_a VALUES (657 , 445 , 668 , 569 , false);
+INSERT INTO self_a VALUES (372 , 215 , 899 , 368 , true);
+INSERT INTO self_a VALUES (223 , 794 , 499 , 736 , false);
+INSERT INTO self_a VALUES (433 , 94 , 321 , 359 , true);
+INSERT INTO self_a VALUES (423 , 575 , 251 , 637 , false);
+INSERT INTO self_a VALUES (508 , 734 , 783 , 781 , true);
+INSERT INTO self_a VALUES (278 , 653 , 931 , 500 , false);
+INSERT INTO self_a VALUES (726 , 993 , 9 , 298 , true);
+INSERT INTO self_a VALUES (677 , 426 , 376 , 226 , false);
+INSERT INTO self_a VALUES (967 , 639 , 659 , 731 , false);
+INSERT INTO self_a VALUES (488 , 774 , 321 , 573 , false);
+INSERT INTO self_a VALUES (65 , 909 , 5 , 331 , true);
+INSERT INTO self_a VALUES (426 , 554 , 297 , 168 , true);
+INSERT INTO self_a VALUES (460 , 846 , 500 , 416 , true);
+INSERT INTO self_a VALUES (887 , 664 , 705 , 592 , true);
+INSERT INTO self_a VALUES (98 , 83 , 24 , 146 , false);
+INSERT INTO self_a VALUES (79 , 343 , 431 , 601 , false);
+INSERT INTO self_a VALUES (127 , 942 , 871 , 783 , true);
+INSERT INTO self_a VALUES (20 , 441 , 998 , 508 , false);
+INSERT INTO self_a VALUES (267 , 62 , 303 , 239 , true);
+INSERT INTO self_a VALUES (239 , 62 , 439 , 837 , true);
+INSERT INTO self_a VALUES (89 , 686 , 252 , 569 , false);
+INSERT INTO self_a VALUES (891 , 135 , 718 , 114 , true);
+INSERT INTO self_a VALUES (606 , 246 , 74 , 214 , false);
+INSERT INTO self_a VALUES (552 , 359 , 115 , 783 , false);
+INSERT INTO self_a VALUES (712 , 930 , 700 , 976 , false);
+INSERT INTO self_a VALUES (107 , 852 , 200 , 230 , true);
+INSERT INTO self_a VALUES (554 , 263 , 759 , 69 , false);
+INSERT INTO self_a VALUES (391 , 345 , 544 , 436 , false);
+INSERT INTO self_a VALUES (12 , 425 , 493 , 606 , false);
+INSERT INTO self_a VALUES (869 , 453 , 75 , 48 , true);
+INSERT INTO self_a VALUES (455 , 58 , 920 , 372 , true);
+INSERT INTO self_a VALUES (227 , 864 , 928 , 982 , false);
+INSERT INTO self_a VALUES (6 , 513 , 218 , 928 , false);
+INSERT INTO self_a VALUES (844 , 740 , 455 , 993 , false);
+INSERT INTO self_a VALUES (850 , 418 , 336 , 521 , false);
+INSERT INTO self_a VALUES (209 , 470 , 482 , 456 , true);
+INSERT INTO self_a VALUES (177 , 631 , 900 , 590 , true);
+INSERT INTO self_a VALUES (899 , 485 , 322 , 890 , true);
+INSERT INTO self_a VALUES (733 , 33 , 64 , 48 , true);
+INSERT INTO self_a VALUES (700 , 47 , 989 , 640 , false);
+INSERT INTO self_a VALUES (252 , 571 , 608 , 239 , false);
+INSERT INTO self_a VALUES (480 , 100 , 299 , 783 , false);
+INSERT INTO self_a VALUES (40 , 341 , 956 , 192 , false);
+INSERT INTO self_a VALUES (304 , 201 , 128 , 344 , true);
+INSERT INTO self_a VALUES (150 , 276 , 114 , 435 , false);
+INSERT INTO self_a VALUES (412 , 482 , 930 , 265 , false);
+INSERT INTO self_a VALUES (219 , 597 , 726 , 347 , true);
+INSERT INTO self_a VALUES (248 , 74 , 303 , 763 , true);
+INSERT INTO self_a VALUES (402 , 604 , 706 , 483 , true);
+INSERT INTO self_a VALUES (491 , 662 , 324 , 100 , false);
+INSERT INTO self_a VALUES (680 , 890 , 651 , 440 , true);
+INSERT INTO self_a VALUES (42 , 791 , 890 , 623 , true);
+INSERT INTO self_a VALUES (144 , 166 , 928 , 774 , false);
+INSERT INTO self_a VALUES (272 , 507 , 710 , 514 , true);
+INSERT INTO self_a VALUES (NULL, NULL, NULL, NULL);
+CREATE INDEX idx_self_a ON self_a USING BTREE (a , b , c);
+ANALYZE self_a;
+--
+-- Test single attribute self-contradictory
+--
+explain (costs off)
+SELECT * FROM self_a WHERE a > 10 AND a < 9;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a >= 10 AND a < 10;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a <= 10 AND a > 10;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a <= 10 AND a >= 10;
+ QUERY PLAN
+-------------------------------------
+ Seq Scan on self_a
+ Filter: ((a <= 10) AND (a >= 10))
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a >= 10 AND a < 10 AND a > 8 AND a <= 12;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a > 10 AND a = 10;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a >= 10 AND a = 10;
+ QUERY PLAN
+--------------------
+ Seq Scan on self_a
+ Filter: (a = 10)
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a < 10 AND a = 10;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a <= 10 AND a = 10;
+ QUERY PLAN
+--------------------
+ Seq Scan on self_a
+ Filter: (a = 10)
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a = 10 AND a <> 10;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a = 10 AND a <> 9;
+ QUERY PLAN
+--------------------
+ Seq Scan on self_a
+ Filter: (a = 10)
+(2 rows)
+
+--
+-- Boolean type is a little tricky.
+--
+explain (costs off)
+SELECT * FROM self_a WHERE z IS TRUE AND z IS NOT TRUE;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z IS TRUE AND z IS FALSE;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z IS TRUE AND z IS NOT FALSE;
+ QUERY PLAN
+----------------------------------------------
+ Seq Scan on self_a
+ Filter: ((z IS TRUE) AND (z IS NOT FALSE))
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z IS TRUE AND z IS UNKNOWN;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z IS TRUE AND z IS NOT UNKNOWN;
+ QUERY PLAN
+------------------------------------------------
+ Seq Scan on self_a
+ Filter: ((z IS TRUE) AND (z IS NOT UNKNOWN))
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z IS FALSE AND z IS NOT FALSE;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z IS FALSE AND z IS UNKNOWN;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z IS FALSE AND z IS NOT UNKNOWN;
+ QUERY PLAN
+-------------------------------------------------
+ Seq Scan on self_a
+ Filter: ((z IS FALSE) AND (z IS NOT UNKNOWN))
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z IS UNKNOWN AND z IS TRUE;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z IS UNKNOWN AND z IS NOT TRUE;
+ QUERY PLAN
+------------------------------------------------
+ Seq Scan on self_a
+ Filter: ((z IS UNKNOWN) AND (z IS NOT TRUE))
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z IS UNKNOWN AND z IS NOT UNKNOWN;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z AND z IS NOT TRUE;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z AND z IS NOT FALSE;
+ QUERY PLAN
+------------------------------------
+ Seq Scan on self_a
+ Filter: (z AND (z IS NOT FALSE))
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z AND z IS FALSE;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z AND z IS TRUE;
+ QUERY PLAN
+-------------------------------
+ Seq Scan on self_a
+ Filter: (z AND (z IS TRUE))
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z AND z IS UNKNOWN;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE NOT z AND z IS NOT UNKNOWN;
+ QUERY PLAN
+--------------------------------------------
+ Seq Scan on self_a
+ Filter: ((NOT z) AND (z IS NOT UNKNOWN))
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE NOT z AND z IS NOT TRUE;
+ QUERY PLAN
+-----------------------------------------
+ Seq Scan on self_a
+ Filter: ((NOT z) AND (z IS NOT TRUE))
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE NOT z AND z IS NOT FALSE;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE NOT z AND z IS FALSE;
+ QUERY PLAN
+--------------------------------------
+ Seq Scan on self_a
+ Filter: ((NOT z) AND (z IS FALSE))
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE NOT z AND z IS TRUE;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE NOT z AND z IS UNKNOWN;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE NOT z AND z IS NOT UNKNOWN;
+ QUERY PLAN
+--------------------------------------------
+ Seq Scan on self_a
+ Filter: ((NOT z) AND (z IS NOT UNKNOWN))
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z = TRUE AND NOT z;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z >= TRUE AND NOT z;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z >= FALSE AND NOT z;
+ QUERY PLAN
+--------------------------------------
+ Seq Scan on self_a
+ Filter: ((NOT z) AND (z >= false))
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z = TRUE AND z;
+ QUERY PLAN
+---------------------
+ Seq Scan on self_a
+ Filter: (z AND z)
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z = TRUE AND z IS TRUE;
+ QUERY PLAN
+-------------------------------
+ Seq Scan on self_a
+ Filter: (z AND (z IS TRUE))
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z = TRUE AND z IS FALSE;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z = TRUE AND z IS NOT TRUE;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z = TRUE AND z IS NOT FALSE;
+ QUERY PLAN
+------------------------------------
+ Seq Scan on self_a
+ Filter: (z AND (z IS NOT FALSE))
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z = TRUE AND z IS UNKNOWN;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z = TRUE AND z IS NOT UNKNOWN;
+ QUERY PLAN
+--------------------------------------
+ Seq Scan on self_a
+ Filter: (z AND (z IS NOT UNKNOWN))
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z = TRUE AND z >= TRUE;
+ QUERY PLAN
+-------------------------------
+ Seq Scan on self_a
+ Filter: (z AND (z >= true))
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z = TRUE AND z > TRUE;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z = TRUE AND z <= TRUE;
+ QUERY PLAN
+-------------------------------
+ Seq Scan on self_a
+ Filter: (z AND (z <= true))
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z = TRUE AND z < TRUE;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z < FALSE;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z > TRUE;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z >= TRUE AND z IS UNKNOWN;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z >= TRUE AND z IS NOT TRUE;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z >= TRUE AND z IS NOT FALSE;
+ QUERY PLAN
+----------------------------------------------
+ Seq Scan on self_a
+ Filter: ((z IS NOT FALSE) AND (z >= true))
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z >= TRUE AND z IS FALSE;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z > FALSE AND z IS UNKNOWN;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z > FALSE AND z IS NOT UNKNOWN;
+ QUERY PLAN
+------------------------------------------------
+ Seq Scan on self_a
+ Filter: ((z IS NOT UNKNOWN) AND (z > false))
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z > FALSE AND NOT z;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z > FALSE AND z IS NOT TRUE;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z >= FALSE AND z IS NOT TRUE;
+ QUERY PLAN
+----------------------------------------------
+ Seq Scan on self_a
+ Filter: ((z IS NOT TRUE) AND (z >= false))
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z > FALSE AND z IS NOT FALSE;
+ QUERY PLAN
+----------------------------------------------
+ Seq Scan on self_a
+ Filter: ((z IS NOT FALSE) AND (z > false))
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z > FALSE AND z IS FALSE;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z <> TRUE AND z;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z <> TRUE AND NOT z;
+ QUERY PLAN
+---------------------------------
+ Seq Scan on self_a
+ Filter: ((NOT z) AND (NOT z))
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z <> TRUE AND z = true;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z <> TRUE AND z > false;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z <> TRUE AND z >= false;
+ QUERY PLAN
+--------------------------------------
+ Seq Scan on self_a
+ Filter: ((NOT z) AND (z >= false))
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z <> TRUE AND z >= true;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z <> FALSE AND NOT z;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z <> FALSE AND z >= false;
+ QUERY PLAN
+--------------------------------
+ Seq Scan on self_a
+ Filter: (z AND (z >= false))
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z <> FALSE AND z <= false;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+--
+-- Null test
+--
+explain (costs off)
+SELECT * FROM self_a WHERE a IS NULL AND a IS NOT NULL;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a IS NOT NULL AND a > 10;
+ QUERY PLAN
+------------------------------------------
+ Seq Scan on self_a
+ Filter: ((a IS NOT NULL) AND (a > 10))
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a IS NULL AND a = 10;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a IS NULL AND a > 10;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a IS NULL AND a <> 10;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z IS NULL AND z;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z IS NULL AND NOT z;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z IS NULL AND z <> TRUE;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z IS NULL AND z IS TRUE;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z IS NULL AND z IS NOT TRUE;
+ QUERY PLAN
+---------------------------------------------
+ Seq Scan on self_a
+ Filter: ((z IS NULL) AND (z IS NOT TRUE))
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z IS NULL AND z IS UNKNOWN;
+ QUERY PLAN
+--------------------------------------------
+ Seq Scan on self_a
+ Filter: ((z IS NULL) AND (z IS UNKNOWN))
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z IS NULL AND z IS NOT UNKNOWN;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z IS NOT NULL AND NOT z;
+ QUERY PLAN
+-----------------------------------------
+ Seq Scan on self_a
+ Filter: ((z IS NOT NULL) AND (NOT z))
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z IS NOT NULL AND z <> TRUE;
+ QUERY PLAN
+-----------------------------------------
+ Seq Scan on self_a
+ Filter: ((z IS NOT NULL) AND (NOT z))
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z IS NOT NULL AND z IS TRUE;
+ QUERY PLAN
+---------------------------------------------
+ Seq Scan on self_a
+ Filter: ((z IS NOT NULL) AND (z IS TRUE))
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z IS NOT NULL AND z IS NOT TRUE;
+ QUERY PLAN
+-------------------------------------------------
+ Seq Scan on self_a
+ Filter: ((z IS NOT NULL) AND (z IS NOT TRUE))
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z IS NOT NULL AND z IS NOT UNKNOWN;
+ QUERY PLAN
+----------------------------------------------------
+ Seq Scan on self_a
+ Filter: ((z IS NOT NULL) AND (z IS NOT UNKNOWN))
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z IS NOT NULL AND z IS UNKNOWN;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+--
+-- Test weak restriction that have the sematic of same level will being eliminated and IS self contradictory or not
+--
+explain (costs off)
+SELECT * FROM self_a WHERE a > 4 AND a > 5;
+ QUERY PLAN
+--------------------
+ Seq Scan on self_a
+ Filter: (a > 5)
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a > 4 AND a > 5 AND a < 5;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a > 4 AND a >= 5;
+ QUERY PLAN
+--------------------
+ Seq Scan on self_a
+ Filter: (a >= 5)
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a > 4 AND a >= 5 AND a < 5;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a > 4 AND a >= 4;
+ QUERY PLAN
+--------------------
+ Seq Scan on self_a
+ Filter: (a > 4)
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a > 4 AND a >= 4 AND a < 4;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a >= 4 AND a >= 5;
+ QUERY PLAN
+--------------------
+ Seq Scan on self_a
+ Filter: (a >= 5)
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a >= 4 AND a >= 5 AND a < 5;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a >= 4 AND a > 5;
+ QUERY PLAN
+--------------------
+ Seq Scan on self_a
+ Filter: (a > 5)
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a >= 4 AND a > 5 AND a < 5;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a >= 4 AND a = 4;
+ QUERY PLAN
+--------------------
+ Seq Scan on self_a
+ Filter: (a = 4)
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a >= 4 AND a = 4 AND a <> 4;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a >= 3 AND a = 4;
+ QUERY PLAN
+--------------------
+ Seq Scan on self_a
+ Filter: (a = 4)
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a >= 3 AND a = 4 AND a < 4;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a > 3 AND a = 4;
+ QUERY PLAN
+--------------------
+ Seq Scan on self_a
+ Filter: (a = 4)
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a <> 3 AND a = 4;
+ QUERY PLAN
+--------------------
+ Seq Scan on self_a
+ Filter: (a = 4)
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a <> 3 AND a = 4 AND a > 4;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+--
+-- Test same type coercion will be accepted
+--
+explain (costs off)
+select * from self_a WHERE a = 1 AND a <>'1'::int;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+--
+-- Test different type coercion will be ignored
+--
+explain (costs off)
+SELECT * FROM self_a WHERE a = 1 AND a <>'1'::bigint;
+ QUERY PLAN
+--------------------------------------------
+ Seq Scan on self_a
+ Filter: ((a <> '1'::bigint) AND (a = 1))
+(2 rows)
+
+--
+-- Test specified collation will be ignored
+--
+explain (costs off)
+SELECT * FROM self_b WHERE a > 'c' AND a < 'b' COLLATE "pg_c_utf8";
+ QUERY PLAN
+-----------------------------------------------------------------------------------
+ Seq Scan on self_b
+ Filter: (((a)::text > 'c'::text) AND ((a)::text < 'b'::text COLLATE pg_c_utf8))
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_b WHERE a > 'c' AND a < 'b';
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+--
+-- Redundant clause will be eliminated
+--
+explain (costs off)
+select * from self_a WHERE a = 1 AND a = 1;
+ QUERY PLAN
+--------------------
+ Seq Scan on self_a
+ Filter: (a = 1)
+(2 rows)
+
+explain (costs off)
+select * from self_a WHERE a > 10 AND a > 10;
+ QUERY PLAN
+--------------------
+ Seq Scan on self_a
+ Filter: (a > 10)
+(2 rows)
+
+explain (costs off)
+select * from self_a WHERE a >= 10 AND a >= 10;
+ QUERY PLAN
+---------------------
+ Seq Scan on self_a
+ Filter: (a >= 10)
+(2 rows)
+
+explain (costs off)
+select * from self_a WHERE a < 4 AND a < 4;
+ QUERY PLAN
+--------------------
+ Seq Scan on self_a
+ Filter: (a < 4)
+(2 rows)
+
+explain (costs off)
+select * from self_a WHERE a <= 4 AND a <= 4;
+ QUERY PLAN
+--------------------
+ Seq Scan on self_a
+ Filter: (a <= 4)
+(2 rows)
+
+--
+-- Test base or-clause
+--
+--
+-- Test or-clause self-contradictory
+--
+explain (costs off)
+SELECT * FROM self_a WHERE a > 10 AND a < 9 OR b > 8 AND b < 6;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a > 10 AND a < 9 OR ((b > 8 AND b < 7 or b = 10) AND b < 6);
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+--
+-- Test or-clause can be pruned
+--
+explain (costs off)
+SELECT * FROM self_a WHERE a < 9 AND a > 10 OR b < 8;
+ QUERY PLAN
+--------------------
+ Seq Scan on self_a
+ Filter: (b < 8)
+(2 rows)
+
+SELECT * FROM self_a WHERE a < 9 AND a > 10 OR b < 8;
+ a | b | c | d | z
+-----+---+-----+-----+---
+ 283 | 4 | 598 | 347 | t
+(1 row)
+
+--
+-- Test or-clause redundant clause will be eliminated
+--
+explain (costs off)
+SELECT * FROM self_a WHERE a < 14 AND a < 10 OR b < 8;
+ QUERY PLAN
+---------------------------------
+ Seq Scan on self_a
+ Filter: ((a < 10) OR (b < 8))
+(2 rows)
+
+SELECT * FROM self_a WHERE a < 14 AND a < 10 OR b < 8;
+ a | b | c | d | z
+-----+-----+-----+-----+---
+ 6 | 514 | 536 | 746 | f
+ 283 | 4 | 598 | 347 | t
+ 5 | 437 | 23 | 829 | f
+ 4 | 23 | 607 | 997 | t
+ 6 | 513 | 218 | 928 | f
+(5 rows)
+
+--
+-- Test same level and-clause whether can be push down into or-clause to test self-contradictory and can be pruned
+--
+explain (costs off)
+SELECT * FROM self_a WHERE a > 10 AND b > 12 AND (a < 9 OR b < 11);
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a > 10 AND b > 12 AND (a < 9 AND b < 11 OR b <=16);
+ QUERY PLAN
+-------------------------------------------------
+ Seq Scan on self_a
+ Filter: ((a > 10) AND (b > 12) AND (b <= 16))
+(2 rows)
+
+SELECT * FROM self_a WHERE a > 10 AND b > 12 AND (a < 9 AND b < 11 OR b <=16);
+ a | b | c | d | z
+-----+----+-----+-----+---
+ 318 | 13 | 119 | 148 | f
+(1 row)
+
+--
+-- Test mixed expr clause
+--
+explain (costs off)
+SELECT * FROM self_a WHERE NOT(a = 1 AND a <>1) AND a = 1;
+ QUERY PLAN
+--------------------
+ Seq Scan on self_a
+ Filter: (a = 1)
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a IS NULL AND a IS NOT NULL OR a = 1;
+ QUERY PLAN
+--------------------
+ Seq Scan on self_a
+ Filter: (a = 1)
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a IS NULL AND a IS NOT NULL OR a = 1 AND a > 2;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z IS TRUE AND z IS NOT TRUE OR a = 1 AND a > 2;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE z = TRUE AND z IS NOT TRUE OR z IS NULL AND z IS NOT NULL;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a BETWEEN 10 AND 5;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE (a > 4::bigint AND a > 4 AND a < 4 OR b > 3 AND b < 2) OR (a < 20);
+ QUERY PLAN
+--------------------
+ Seq Scan on self_a
+ Filter: (a < 20)
+(2 rows)
+
+SELECT * FROM self_a WHERE (a > 1 AND a <1 OR b < 10 ) AND z IS TRUE OR b < 20 or z IS null;
+ a | b | c | d | z
+-----+----+-----+-----+---
+ 318 | 13 | 119 | 148 | f
+ 283 | 4 | 598 | 347 | t
+ 916 | 19 | 100 | 457 | f
+ 570 | 17 | 675 | 416 | t
+ 155 | 19 | 238 | 464 | t
+ | | | |
+(6 rows)
+
+--
+-- Test pruned and self-contradictory mixed case
+--
+explain (costs off)
+SELECT * FROM self_a WHERE (a > 10 AND a > 12 OR b > 8) AND b < 7 AND b < 15;
+ QUERY PLAN
+----------------------------------
+ Seq Scan on self_a
+ Filter: ((b < 7) AND (a > 12))
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a > 10 AND b > 12 AND (a > 10 AND a < 9 OR b < 11 OR a < 7);
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a > 10 AND b > 12 AND (((a < 9 OR b < 11) OR (b < 15 AND b < 17 OR a <12)) OR b >=8 AND a < 14);
+ QUERY PLAN
+-----------------------------------------------------------------------------------------
+ Seq Scan on self_a
+ Filter: ((a > 10) AND (b > 12) AND ((b < 15) OR (a < 12) OR ((b > 12) AND (a < 14))))
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a <> 3 AND a <> 4 AND a <> 8 AND (b > 12 AND c < 80 OR c = 16 AND (a = 4 OR a = 8));
+ QUERY PLAN
+--------------------------------------------------------------------------
+ Seq Scan on self_a
+ Filter: ((a <> 3) AND (a <> 4) AND (a <> 8) AND (b > 12) AND (c < 80))
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a IS not null AND (b > 12 AND c < 80 OR c = 16 AND (a IS null OR a = 8));
+ QUERY PLAN
+-------------------------------------------------------------------------------------
+ Seq Scan on self_a
+ Filter: ((a IS NOT NULL) AND (((b > 12) AND (c < 80)) OR ((c = 16) AND (a = 8))))
+(2 rows)
+
+--
+-- Test self-contradictory join case
+--
+explain (costs off)
+SELECT * FROM self_a a LEFT JOIN self_a b ON a.a = b.a WHERE b.a > 300 AND a.a = 145;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+select * from self_a a JOIN self_a b ON a.a =b.a WHERE a.a= 145 AND b.a < 79;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+--
+-- Test row comparison
+-- It's need to add define DEBUG_ROW_DECODE for debug
+--
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b) > (NULL , 3);
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , c) < (100 , null , 3);
+ QUERY PLAN
+---------------------
+ Seq Scan on self_a
+ Filter: (a < 100)
+(2 rows)
+
+--Equal expression
+--a<100
+--or a=100 and b<null
+--or a=100 and b=null and c<3
+--After converted
+--a<100
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , c) < (100 , null , 3) AND a = 101;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , c) > (1 , 2 , null);
+ QUERY PLAN
+-----------------------------------------------------
+ Seq Scan on self_a
+ Filter: (ROW(a, b, c) > ROW(1, 2, NULL::integer))
+(2 rows)
+
+--Equal expression
+--a>1
+--or a=1 AND b>2
+--or a=1 AND b=2 AND c>null
+--After converted
+--a>1
+--or a=1 AND b>2
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , c) > (1 , 2 , null) AND a < 1;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(NULL , b) > (3 , 3);
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , null , b) > (2 , 3 , 4);
+ QUERY PLAN
+--------------------
+ Seq Scan on self_a
+ Filter: (a > 2)
+(2 rows)
+
+--Equal expression
+--a>2
+--or a=2 and null>3
+--or a=2 and null=3 and b>4
+--After converted
+--a>2
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , null , b) > (2 , 3 , 4) AND a = 2;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , null) >= (2 , 3 , 4);
+ QUERY PLAN
+------------------------------------------------------
+ Seq Scan on self_a
+ Filter: (ROW(a, b, NULL::integer) >= ROW(2, 3, 4))
+(2 rows)
+
+--Equal expression
+--a>2
+--or a=2 and b>3
+--or a=2 and b=3 and null>=4
+--After converted
+--a>2
+--or a=2 and b>3
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , null) >= (2 , 3 , 4) AND a < 2;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , null) > (2 , 3 , 4);
+ QUERY PLAN
+-----------------------------------------------------
+ Seq Scan on self_a
+ Filter: (ROW(a, b, NULL::integer) > ROW(2, 3, 4))
+(2 rows)
+
+--Equal expression
+--a>2
+--or a=2 and b>3
+--or a=2 and b=3 and null>4
+--After converted
+--a>2
+--or a=2 and b>3
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , c) >= (a , 3 , 4);
+ QUERY PLAN
+------------------------------------------
+ Seq Scan on self_a
+ Filter: (ROW(a, b, c) >= ROW(a, 3, 4))
+(2 rows)
+
+--Equal expression
+--a>a
+--or a=a AND b>3
+--or a=a AND b=3 AND c>=4
+--After converted
+--a is not null and b>3
+--or a IS not null and b=3 AND c>=4
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , c) >= (a , 3 , 4) AND a IS NULL;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , c) > (a , 3 , 4);
+ QUERY PLAN
+-----------------------------------------
+ Seq Scan on self_a
+ Filter: (ROW(a, b, c) > ROW(a, 3, 4))
+(2 rows)
+
+--Equal expression
+--a>a
+--or a=a AND b>3
+--or a=a AND b=3 AND c>4
+--After converted
+--a is not null and b>3
+--or a IS not null and b=3 AND c>4
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , c) >= (2 , b , 4);
+ QUERY PLAN
+------------------------------------------
+ Seq Scan on self_a
+ Filter: (ROW(a, b, c) >= ROW(2, b, 4))
+(2 rows)
+
+--Equal expression
+--a>2
+--or a=2 and b>b
+--or a=2 AND b=b AND c >=4
+--After converted
+--a>2
+--or a=2 AND b IS not null AND c >=4
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , c) >= (2 , b , 4) AND a = 2 AND c < 4;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , c) > (2 , b , 4);
+ QUERY PLAN
+-----------------------------------------
+ Seq Scan on self_a
+ Filter: (ROW(a, b, c) > ROW(2, b, 4))
+(2 rows)
+
+--Equal expression
+--a>2
+--or a=2 and b>b
+--or a=2 AND b=b AND c >4
+--After converted
+--a>2
+--or a=2 AND b IS not null AND c >4
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , c) >= (2 , 3 , c);
+ QUERY PLAN
+------------------------------------------
+ Seq Scan on self_a
+ Filter: (ROW(a, b, c) >= ROW(2, 3, c))
+(2 rows)
+
+--Equal expression
+--a>2
+--or a=2 AND b>3
+--or a=2 AND b=3 AND c>=c
+--After converted
+--a>2
+--or a=2 AND b>3
+--or a=2 AND b=3 AND c IS not null
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , c) >= (2 , 3 , c) AND a = 2 AND c = 3 AND c IS NULL;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , c) > (2 , 3 , c);
+ QUERY PLAN
+-----------------------------------------
+ Seq Scan on self_a
+ Filter: (ROW(a, b, c) > ROW(2, 3, c))
+(2 rows)
+
+--Equal expression
+--a>2
+--or a=2 AND b>3
+--or a=2 AND b=3 AND c>c
+--After converted
+--a>2
+--or a=2 AND b>3
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , c) > (2 , b , c);
+ QUERY PLAN
+--------------------
+ Seq Scan on self_a
+ Filter: (a > 2)
+(2 rows)
+
+--Equal expression
+--a>2
+--or a=2 AND b>b
+--or a=2 AND b=b AND c>c
+--After converted
+--a>2
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , c) > (2 , b , c) AND a = 2;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , c) >= (2 , b , c);
+ QUERY PLAN
+------------------------------------------
+ Seq Scan on self_a
+ Filter: (ROW(a, b, c) >= ROW(2, b, c))
+(2 rows)
+
+--Equal expression
+--a>2
+--or a=2 AND b>b
+--or a=2 AND b=b AND c>=c
+--After converted
+--a>2
+--or a=2 AND b=b AND c>=c
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , c) >= (2 , b , c) AND a = 2 AND b IS NULL;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , c) > (a , b , c);
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+--Equal expression
+--a>a
+--or a=a AND b>b
+--or a=a AND b=b AND c>c
+--After converted
+--false
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , c) >= (a , b , c);
+ QUERY PLAN
+------------------------------------------
+ Seq Scan on self_a
+ Filter: (ROW(a, b, c) >= ROW(a, b, c))
+(2 rows)
+
+--Equal expression
+--a>a
+--or a=a AND b>b
+--or a=a AND b=b AND c>=c
+--After converted
+--a=a AND b=b AND c>=c
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , c) >= (a , b , c) AND a IS NULL;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(2 , b , c) >= (2 , 3 , 4);
+ QUERY PLAN
+------------------------------------------
+ Seq Scan on self_a
+ Filter: (ROW(2, b, c) >= ROW(2, 3, 4))
+(2 rows)
+
+--Equal expression
+--2>2
+--or 2=2 AND b>3
+--or 2=2 AND b=3 AND c>=4
+--After converted
+--b>3
+--or b=3 AND c>=4
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(2 , b , c) >= (2 , 3 , 4) AND c < 4 AND b = 3;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(2 , b , c) > (2 , 3 , 4);
+ QUERY PLAN
+-----------------------------------------
+ Seq Scan on self_a
+ Filter: (ROW(2, b, c) > ROW(2, 3, 4))
+(2 rows)
+
+--Equal expression
+--2>2
+--or 2=2 AND b>3
+--or 2=2 AND b=3 AND c>=4
+--After converted
+--b>3
+--or b=3 AND c>4
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , 3 , c) >= (2 , 3 , 4);
+ QUERY PLAN
+------------------------------------------
+ Seq Scan on self_a
+ Filter: (ROW(a, 3, c) >= ROW(2, 3, 4))
+(2 rows)
+
+--Equal expression
+--a>2
+--or a=2 AND 3>3
+--or a=2 AND 3=3 AND c>=4
+--After converted
+--a>2
+--or a=2 AND c>=4
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , 3 , c) >= (2 , 3 , 4) AND c < 4 AND a = 1;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , 4) >= (2 , 3 , 4);
+ QUERY PLAN
+------------------------------------------
+ Seq Scan on self_a
+ Filter: (ROW(a, b, 4) >= ROW(2, 3, 4))
+(2 rows)
+
+--Equal expression
+--a>2
+--or a=2 AND b>3
+--or a=2 AND b=3 AND 4>=4
+--After converted
+--a>2
+--or a=2 AND b>3
+--or a=2 AND b=3
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , 4) >= (2 , 3 , 4) AND b = 3 AND a = 1;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , 4) > (2 , 3 , 4);
+ QUERY PLAN
+-----------------------------------------
+ Seq Scan on self_a
+ Filter: (ROW(a, b, 4) > ROW(2, 3, 4))
+(2 rows)
+
+--Equal expression
+--a>2
+--or a=2 AND b>3
+--or a=2 AND b=3 AND 4>4
+--After converted
+--a>2
+--or a=2 AND b>3
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , 4) > (2 , 3 , 4) AND a = 2 AND b = 1;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , 3 , 4) >= (2 , 3 , 4);
+ QUERY PLAN
+------------------------------------------
+ Seq Scan on self_a
+ Filter: (ROW(a, 3, 4) >= ROW(2, 3, 4))
+(2 rows)
+
+--Equal expression
+--a>2
+--or a=2 AND 3>3
+--or a=2 AND 3=3 AND 4>=4
+--After converted
+--a>2
+--or a=2
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , 3 , 4) >= (2 , 3 , 4) AND a = 1;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , 3 , 4) > (2 , 3 , 4);
+ QUERY PLAN
+--------------------
+ Seq Scan on self_a
+ Filter: (a > 2)
+(2 rows)
+
+--Equal expression
+--a>2
+--or a=2 AND 3>3
+--or a=2 AND 3=3 AND 4>4
+--After converted
+--a>2
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , 3 , 4) > (2 , 3 , 4) AND a = 1;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(2 , 3 , 4) >= (2 , 3 , 4);
+ QUERY PLAN
+---------------------------------------------------
+ Result
+ One-Time Filter: (ROW(2, 3, 4) >= ROW(2, 3, 4))
+ -> Seq Scan on self_a
+(3 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(2 , 3 , 4) > (2 , 3 , 4);
+ QUERY PLAN
+--------------------------------------------------
+ Result
+ One-Time Filter: (ROW(2, 3, 4) > ROW(2, 3, 4))
+ -> Seq Scan on self_a
+(3 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , 3 , 4) > (a , 3 , 4);
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+--Equal expression
+--a>a
+--or a=a AND 3>3
+--or a=a AND 3=3 AND 4>4
+--After converted
+--false
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , 3 , 4) >= (a , 3 , 4);
+ QUERY PLAN
+---------------------------
+ Seq Scan on self_a
+ Filter: (a IS NOT NULL)
+(2 rows)
+
+--Equal expression
+--a>a
+--or a=a AND 3>3
+--or a=a AND 3=3 AND 4>=4
+--After converted
+--a IS NOT NULL
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , 3 , 4) >= (a , 3 , 4) AND a IS NULL;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(4 , a , b) > (4 , a , b);
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+--After converted
+--false
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(4 , a , b) >= (4 , a , b);
+ QUERY PLAN
+------------------------------------------
+ Seq Scan on self_a
+ Filter: (ROW(4, a, b) >= ROW(4, a, b))
+(2 rows)
+
+--Equal expression
+--4>4
+--or 4=4 AND a>a
+--or 4=4 AND a=a AND b>=b
+--After converted
+--a IS NOT NULL and b IS NOT NULL
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(4 , a , b) >= (4 , a , b) AND a IS NULL;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , 4 , b) >= (a , 4 , b);
+ QUERY PLAN
+------------------------------------------
+ Seq Scan on self_a
+ Filter: (ROW(a, 4, b) >= ROW(a, 4, b))
+(2 rows)
+
+--Equal expression
+--a>a
+--or a=a AND 4>4
+--or a=a AND 4=4 AND b>=b
+--After converted
+--a IS NOT NULL and b IS NOT NULL
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(4 , a , 4) >= (4 , a , 4);
+ QUERY PLAN
+---------------------------
+ Seq Scan on self_a
+ Filter: (a IS NOT NULL)
+(2 rows)
+
+--Equal expression
+--4>4
+--or 4=4 AND a>a
+--or 4=4 AND a=a AND 4>=4
+--After converted
+--a IS NOT NULL
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , a , a) >= (a , a , a);
+ QUERY PLAN
+------------------------------------------
+ Seq Scan on self_a
+ Filter: (ROW(a, a, a) >= ROW(a, a, a))
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , a , a) > (a , a , a);
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+--Test const are not equal
+--negative
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(1 , b , c) >= (2 , 3 , 4);
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+--Equal expression
+--1>2
+--or 1=2 AND b>3
+--or 1=2 AND b=3 AND c>=4
+--After converted
+--false
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(1 , b , c) > (2 , 3 , 4);
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+--Equal expression
+--1>2
+--or 1=2 AND b>3
+--or 1=2 AND b=3 AND c>4
+--After converted
+--false
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , 2 , c) >= (2 , 3 , 4);
+ QUERY PLAN
+--------------------
+ Seq Scan on self_a
+ Filter: (a > 2)
+(2 rows)
+
+--Equal expression
+--a>2
+--or a=2 AND 2>3
+--or a=2 AND 2=3 AND c>=4
+--After converted
+--a>2
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , 2 , c) >= (2 , 3 , 4) AND a = 2;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , 3) >= (2 , 3 , 4);
+ QUERY PLAN
+------------------------------------------
+ Seq Scan on self_a
+ Filter: (ROW(a, b, 3) >= ROW(2, 3, 4))
+(2 rows)
+
+--Equal expression
+--a>2
+--or a=2 AND b>3
+--or a=2 AND b=3 AND 3>=4
+--After converted
+--a>2
+--or a=2 AND b>3
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , 3) >= (2 , 3 , 4) AND a < 2;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , 3 , c) >= (2 , 3 , 4 , 5);
+ QUERY PLAN
+------------------------------------------------
+ Seq Scan on self_a
+ Filter: (ROW(a, b, 3, c) >= ROW(2, 3, 4, 5))
+(2 rows)
+
+--Equal expression
+--a>2
+--or a=2 AND b>3
+--or a=2 AND b=3 AND 3>=4
+--or a=2 AND b=3 AND 3=4 and c>=5
+--After converted
+--a>2
+--or a=2 AND b>3
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , 3) >= (a , b , 4);
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+--Equal expression
+--a>a
+--or a=a AND b>b
+--or a=a AND b=b AND 3>=4
+--After converted
+--false
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , 5 , b , 3) >= (a , 5 , b , 4);
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+--Equal expression
+--a>a
+--or a=a AND 5>5
+--or a=a AND 5=5 and b>b
+--or a=a AND 5=5 and b=b and 3>=4
+--After converted
+--false
+--positive
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(5 , b , c) > (2 , 3 , 4);
+ QUERY PLAN
+--------------------
+ Seq Scan on self_a
+(1 row)
+
+--Equal expression
+--5>2
+--or 5=2 AND b>3
+--or 5=2 AND b=3 AND c>4
+--After converted
+--true
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , 5 , c) >= (2 , 3 , 4);
+ QUERY PLAN
+------------------------------------------
+ Seq Scan on self_a
+ Filter: (ROW(a, 5, c) >= ROW(2, 3, 4))
+(2 rows)
+
+--Equal expression
+--a>2
+--or a=2 AND 5>3
+--or a=2 AND 5=3 AND c>=4
+--After converted
+--a>2
+--or a=2
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , 5 , c) >= (2 , 3 , 4) AND a = 1;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , 5) >= (2 , 3 , 4);
+ QUERY PLAN
+------------------------------------------
+ Seq Scan on self_a
+ Filter: (ROW(a, b, 5) >= ROW(2, 3, 4))
+(2 rows)
+
+--Equal expression
+--a>2
+--or a=2 AND b>3
+--or a=2 AND b=3 AND 5>=4
+--After converted
+--a>2
+--or a=2 AND b>3
+--or a=2 AND b=3
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , 5) >= (2 , 3 , 4) AND a = 2 AND b < 3;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , 5 , c) >= (2 , 3 , 4 , 6);
+ QUERY PLAN
+------------------------------------------------
+ Seq Scan on self_a
+ Filter: (ROW(a, b, 5, c) >= ROW(2, 3, 4, 6))
+(2 rows)
+
+--Equal expression
+--a>2
+--or a=2 AND b>3
+--or a=2 AND b=3 AND 5>=4
+--or a=2 AND b=3 AND 5=4 and c>=6
+--After converted
+--a>2
+--or a=2 AND b>3
+--or a=2 AND b=3
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , 2 , b , 4 , 3 , c) >= (108 , 2 , b , 2 , 4 , 5);
+ QUERY PLAN
+--------------------------------------------------------------
+ Seq Scan on self_a
+ Filter: (ROW(a, 2, b, 4, 3, c) >= ROW(108, 2, b, 2, 4, 5))
+(2 rows)
+
+--Equal expression
+--a>108
+--or a=108 and 2>2
+--or a=108 and 2=2 and b>b
+--or a=108 and 2=2 and b=b and 4>2
+--or a=108 and 2=2 and b=b and 4=2 and 3>4
+--or a=108 and 2=2 and b=b and 4=2 and 3=4 and c>=5
+--After converted
+--a>108
+--or a=108 and b IS NOT NULL
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , 2 , b , 4 , 3 , c) >= (108 , 2 , b , 2 , 4 , 5) AND a = 108 AND b is NULL;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+--Only keep expr that is simple after converted.
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b, c) > (23, 34, 56) AND b = 34 AND c = 56;
+ QUERY PLAN
+------------------------------------------------
+ Seq Scan on self_a
+ Filter: ((a > 23) AND (b = 34) AND (c = 56))
+(2 rows)
+
+--Test row comparison under the or-expr is const true and the or-expr will be const true.
+explain (costs off)
+SELECT * FROM self_a WHERE (ROW(2,a,b) > (1,3,5) OR c < 345 AND a = 89) AND a < 150 OR c = 178;
+ QUERY PLAN
+------------------------------------
+ Seq Scan on self_a
+ Filter: ((a < 150) OR (c = 178))
+(2 rows)
+
+--
+-- Test scalar array operation expr
+--
+explain (costs off)
+SELECT * FROM self_a WHERE a <> ALL (array[2 , 3 , 4]) AND a = 2;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a <> ALL (array[2 , 3 , 4]) AND a < 20;
+ QUERY PLAN
+---------------------------------------------
+ Bitmap Heap Scan on self_a
+ Recheck Cond: (a < 20)
+ Filter: (a <> ALL ('{2,3,4}'::integer[]))
+ -> Bitmap Index Scan on idx_self_a
+ Index Cond: (a < 20)
+(5 rows)
+
+SELECT COUNT(*) FROM self_a WHERE a <> ALL (array[2 , 3 , 4]) AND a < 20;
+ count
+-------
+ 6
+(1 row)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a <> ALL (array[2 , 3 , 4]) AND (a = 2 or a = 4);
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a <> ALL (array[2 , 2]) AND a = 2;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a <> ANY (array[2 , 2]) AND a = 2;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a < ALL (array[20 , 30 , 40]) AND a = 27;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a < ALL (array[20 , 30 , 40]) AND a > 25;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a < ALL (array[20 , 20]) AND a >= 25;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a < ANY (array[20 , 30 , 40]) AND a >= 25;
+ QUERY PLAN
+----------------------------------------------
+ Bitmap Heap Scan on self_a
+ Recheck Cond: ((a >= 25) AND (a < 40))
+ -> Bitmap Index Scan on idx_self_a
+ Index Cond: ((a >= 25) AND (a < 40))
+(4 rows)
+
+SELECT COUNT(*) FROM self_a WHERE a < ANY (array[20 , 30 , 40]) AND a >= 25;
+ count
+-------
+ 5
+(1 row)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a < ANY (array[20 , 30 , 40]) AND a > 40;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a < ANY (array[20 , 20]) AND a > 20;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a = ALL (array[2 , 3]);
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a = ALL (array[54, NULL]);
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a = ALL (array[2 , 2]) AND a <> 2;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a = ALL (array[27 , 27]) AND (a <> 27 OR a =27);
+ QUERY PLAN
+--------------------
+ Seq Scan on self_a
+ Filter: (a = 27)
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a = ANY (array[2]) AND a <> 2;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a = ANY (array[2 , 2]) AND a <> 2;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a = ANY (array[2 , 3 , 4]) AND a < 2;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a IN (2 , 3 , 4) AND a IN (5);
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a < ANY (array[1 , 2]) AND a > ANY (array[2 , 3]);
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a > ALL (array[2 , 3]) AND a <=3;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a > ANY (array[2 , 3]) AND a <=3;
+ QUERY PLAN
+----------------------------------
+ Seq Scan on self_a
+ Filter: ((a <= 3) AND (a > 2))
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a > ANY (array[2 , 3]) AND a <=2;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a IN (58 , 32 , 4) AND a IN (1 , 32 , 6);
+ QUERY PLAN
+--------------------
+ Seq Scan on self_a
+ Filter: (a = 32)
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a IN (58 , 32 , 4) AND a IN (1 , 3 , 6);
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a IN (1 , 2 , 3) AND a IN (1 , 3 , 6) AND a > 1;
+ QUERY PLAN
+---------------------------------
+ Seq Scan on self_a
+ Filter: ((a > 1) AND (a = 3))
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a > ANY (array[2 , 3]) AND a <=2 OR a = ANY (array[2 , 3]) AND a > 4;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+-- Test push scalar array expr down.
+explain (costs off)
+SELECT * FROM self_a WHERE a IN (89, 12, 219) AND (b > 50 OR c < 300 AND a IN (89, 121, 319));
+ QUERY PLAN
+---------------------------------------------------------------------------------------------
+ Seq Scan on self_a
+ Filter: ((a = ANY ('{89,12,219}'::integer[])) AND ((b > 50) OR ((c < 300) AND (a = 89))))
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a IN (89, 12, 219) AND (b > 50 OR (c < 345 AND c < 78 OR a IN (89, 121, 319)));
+ QUERY PLAN
+-----------------------------------------------------------------------------------------
+ Seq Scan on self_a
+ Filter: ((a = ANY ('{89,12,219}'::integer[])) AND ((b > 50) OR (c < 78) OR (a = 89)))
+(2 rows)
+
+--
+-- Test push scalar array expr that operator is <> down.
+--
+explain (costs off)
+SELECT * FROM self_a WHERE a not in (89, 12, 219) AND (b > 50 OR c < 345 AND a = 89);
+ QUERY PLAN
+----------------------------------------------------------------
+ Seq Scan on self_a
+ Filter: ((b > 50) AND (a <> ALL ('{89,12,219}'::integer[])))
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a not in (89, 12, 219) AND (b > 50 OR (c < 345 AND c < 78 OR a = 89));
+ QUERY PLAN
+------------------------------------------------------------------------------
+ Seq Scan on self_a
+ Filter: ((a <> ALL ('{89,12,219}'::integer[])) AND ((b > 50) OR (c < 78)))
+(2 rows)
+
+explain (costs off)
+SELECT * FROM self_a WHERE a not in (89, 12, 219) AND (b > 50 and a = 12 OR (c < 345 AND c < 78 and a = 219 OR a = 89));
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+--Test using binary search.
+explain (costs off)
+SELECT * FROM self_a WHERE a not in (89, 12, 219, 78, 69) AND (b > 50 and a = 12 OR (c < 345 AND c < 78 and a = 219 OR a = 89));
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
diff --git a/src/test/regress/expected/stats_ext.out b/src/test/regress/expected/stats_ext.out
index a4c7be487e..48114881a3 100644
--- a/src/test/regress/expected/stats_ext.out
+++ b/src/test/regress/expected/stats_ext.out
@@ -1219,19 +1219,19 @@ SELECT * FROM check_estimated_rows('SELECT * FROM functional_dependencies WHERE
SELECT * FROM check_estimated_rows('SELECT * FROM functional_dependencies WHERE a < ANY (ARRAY[1, 51]) AND b > ''1''');
estimated | actual
-----------+--------
- 2472 | 2400
+ 2448 | 2400
(1 row)
SELECT * FROM check_estimated_rows('SELECT * FROM functional_dependencies WHERE a >= ANY (ARRAY[1, 51]) AND b <= ANY (ARRAY[''1'', ''2''])');
estimated | actual
-----------+--------
- 1441 | 1250
+ 1287 | 1250
(1 row)
SELECT * FROM check_estimated_rows('SELECT * FROM functional_dependencies WHERE a <= ANY (ARRAY[1, 2, 51, 52]) AND b >= ANY (ARRAY[''1'', ''2''])');
estimated | actual
-----------+--------
- 3909 | 2550
+ 2597 | 2550
(1 row)
-- ALL (should not benefit from functional dependencies)
@@ -1244,13 +1244,13 @@ SELECT * FROM check_estimated_rows('SELECT * FROM functional_dependencies WHERE
SELECT * FROM check_estimated_rows('SELECT * FROM functional_dependencies WHERE a IN (1, 51) AND b = ALL (ARRAY[''1'', ''2''])');
estimated | actual
-----------+--------
- 1 | 0
+ 0 | 0
(1 row)
SELECT * FROM check_estimated_rows('SELECT * FROM functional_dependencies WHERE a IN (1, 2, 51, 52) AND b = ALL (ARRAY[''1'', ''2''])');
estimated | actual
-----------+--------
- 1 | 0
+ 0 | 0
(1 row)
-- create statistics
@@ -1385,38 +1385,38 @@ SELECT * FROM check_estimated_rows('SELECT * FROM functional_dependencies WHERE
SELECT * FROM check_estimated_rows('SELECT * FROM functional_dependencies WHERE a < ANY (ARRAY[1, 51]) AND b > ''1''');
estimated | actual
-----------+--------
- 2472 | 2400
+ 2448 | 2400
(1 row)
SELECT * FROM check_estimated_rows('SELECT * FROM functional_dependencies WHERE a >= ANY (ARRAY[1, 51]) AND b <= ANY (ARRAY[''1'', ''2''])');
estimated | actual
-----------+--------
- 1441 | 1250
+ 1287 | 1250
(1 row)
SELECT * FROM check_estimated_rows('SELECT * FROM functional_dependencies WHERE a <= ANY (ARRAY[1, 2, 51, 52]) AND b >= ANY (ARRAY[''1'', ''2''])');
estimated | actual
-----------+--------
- 3909 | 2550
+ 2597 | 2550
(1 row)
-- ALL (should not benefit from functional dependencies)
SELECT * FROM check_estimated_rows('SELECT * FROM functional_dependencies WHERE a IN (1, 51) AND b = ALL (ARRAY[''1''])');
estimated | actual
-----------+--------
- 2 | 100
+ 100 | 100
(1 row)
SELECT * FROM check_estimated_rows('SELECT * FROM functional_dependencies WHERE a IN (1, 51) AND b = ALL (ARRAY[''1'', ''2''])');
estimated | actual
-----------+--------
- 1 | 0
+ 0 | 0
(1 row)
SELECT * FROM check_estimated_rows('SELECT * FROM functional_dependencies WHERE a IN (1, 2, 51, 52) AND b = ALL (ARRAY[''1'', ''2''])');
estimated | actual
-----------+--------
- 1 | 0
+ 0 | 0
(1 row)
-- changing the type of column c causes all its stats to be dropped, reverting
@@ -2032,37 +2032,37 @@ SELECT * FROM check_estimated_rows('SELECT * FROM mcv_lists WHERE a = ANY (ARRAY
SELECT * FROM check_estimated_rows('SELECT * FROM mcv_lists WHERE a <= ANY (ARRAY[1, 2, 3]) AND b IN (''1'', ''2'', ''3'')');
estimated | actual
-----------+--------
- 26 | 150
+ 12 | 150
(1 row)
SELECT * FROM check_estimated_rows('SELECT * FROM mcv_lists WHERE a <= ANY (ARRAY[1, NULL, 2, 3]) AND b IN (''1'', ''2'', NULL, ''3'')');
estimated | actual
-----------+--------
- 26 | 150
+ 12 | 150
(1 row)
SELECT * FROM check_estimated_rows('SELECT * FROM mcv_lists WHERE a < ALL (ARRAY[4, 5]) AND c > ANY (ARRAY[1, 2, 3])');
estimated | actual
-----------+--------
- 10 | 100
+ 184 | 100
(1 row)
SELECT * FROM check_estimated_rows('SELECT * FROM mcv_lists WHERE a < ALL (ARRAY[4, 5]) AND c > ANY (ARRAY[1, 2, 3, NULL])');
estimated | actual
-----------+--------
- 10 | 100
+ 184 | 100
(1 row)
SELECT * FROM check_estimated_rows('SELECT * FROM mcv_lists WHERE a < ALL (ARRAY[4, 5]) AND b IN (''1'', ''2'', ''3'') AND c > ANY (ARRAY[1, 2, 3])');
estimated | actual
-----------+--------
- 1 | 100
+ 11 | 100
(1 row)
SELECT * FROM check_estimated_rows('SELECT * FROM mcv_lists WHERE a < ALL (ARRAY[4, 5]) AND b IN (''1'', ''2'', NULL, ''3'') AND c > ANY (ARRAY[1, 2, NULL, 3])');
estimated | actual
-----------+--------
- 1 | 100
+ 11 | 100
(1 row)
SELECT * FROM check_estimated_rows('SELECT * FROM mcv_lists WHERE a = ANY (ARRAY[4,5]) AND 4 = ANY(ia)');
diff --git a/src/test/regress/expected/updatable_views.out b/src/test/regress/expected/updatable_views.out
index 8786058ed0..8f6e59f054 100644
--- a/src/test/regress/expected/updatable_views.out
+++ b/src/test/regress/expected/updatable_views.out
@@ -535,7 +535,7 @@ EXPLAIN (costs off) UPDATE rw_view1 SET a=6 WHERE a=5;
--------------------------------------------------
Update on base_tbl
-> Index Scan using base_tbl_pkey on base_tbl
- Index Cond: ((a > 0) AND (a = 5))
+ Index Cond: (a = 5)
(3 rows)
EXPLAIN (costs off) DELETE FROM rw_view1 WHERE a=5;
@@ -543,7 +543,7 @@ EXPLAIN (costs off) DELETE FROM rw_view1 WHERE a=5;
--------------------------------------------------
Delete on base_tbl
-> Index Scan using base_tbl_pkey on base_tbl
- Index Cond: ((a > 0) AND (a = 5))
+ Index Cond: (a = 5)
(3 rows)
EXPLAIN (costs off)
@@ -553,7 +553,7 @@ MERGE INTO rw_view1 t USING (VALUES (5, 'X')) AS v(a,b) ON t.a = v.a
--------------------------------------------------
Merge on base_tbl
-> Index Scan using base_tbl_pkey on base_tbl
- Index Cond: ((a > 0) AND (a = 5))
+ Index Cond: (a = 5)
(3 rows)
EXPLAIN (costs off)
@@ -728,19 +728,19 @@ SELECT * FROM rw_view2 ORDER BY aaa;
(3 rows)
EXPLAIN (costs off) UPDATE rw_view2 SET aaa=5 WHERE aaa=4;
- QUERY PLAN
---------------------------------------------------------
+ QUERY PLAN
+--------------------------------------------------
Update on base_tbl
-> Index Scan using base_tbl_pkey on base_tbl
- Index Cond: ((a < 10) AND (a > 0) AND (a = 4))
+ Index Cond: (a = 4)
(3 rows)
EXPLAIN (costs off) DELETE FROM rw_view2 WHERE aaa=4;
- QUERY PLAN
---------------------------------------------------------
+ QUERY PLAN
+--------------------------------------------------
Delete on base_tbl
-> Index Scan using base_tbl_pkey on base_tbl
- Index Cond: ((a < 10) AND (a > 0) AND (a = 4))
+ Index Cond: (a = 4)
(3 rows)
DROP TABLE base_tbl CASCADE;
@@ -924,14 +924,14 @@ MERGE INTO rw_view2 t USING (VALUES (3, 'Row 3')) AS v(a,b) ON t.a = v.a
ERROR: cannot execute MERGE on relation "rw_view1"
DETAIL: MERGE is not supported for relations with rules.
EXPLAIN (costs off) UPDATE rw_view2 SET a=3 WHERE a=2;
- QUERY PLAN
-----------------------------------------------------------------
+ QUERY PLAN
+------------------------------------------------------------
Update on base_tbl
-> Nested Loop
-> Index Scan using base_tbl_pkey on base_tbl
Index Cond: (a = 2)
-> Subquery Scan on rw_view1
- Filter: ((rw_view1.a < 10) AND (rw_view1.a = 2))
+ Filter: (rw_view1.a = 2)
-> Bitmap Heap Scan on base_tbl base_tbl_1
Recheck Cond: (a > 0)
-> Bitmap Index Scan on base_tbl_pkey
@@ -939,14 +939,14 @@ EXPLAIN (costs off) UPDATE rw_view2 SET a=3 WHERE a=2;
(10 rows)
EXPLAIN (costs off) DELETE FROM rw_view2 WHERE a=2;
- QUERY PLAN
-----------------------------------------------------------------
+ QUERY PLAN
+------------------------------------------------------------
Delete on base_tbl
-> Nested Loop
-> Index Scan using base_tbl_pkey on base_tbl
Index Cond: (a = 2)
-> Subquery Scan on rw_view1
- Filter: ((rw_view1.a < 10) AND (rw_view1.a = 2))
+ Filter: (rw_view1.a = 2)
-> Bitmap Heap Scan on base_tbl base_tbl_1
Recheck Cond: (a > 0)
-> Bitmap Index Scan on base_tbl_pkey
@@ -1202,11 +1202,11 @@ SELECT * FROM base_tbl ORDER BY a;
(6 rows)
EXPLAIN (costs off) UPDATE rw_view2 SET a=3 WHERE a=2;
- QUERY PLAN
-----------------------------------------------------------
+ QUERY PLAN
+------------------------------------------------------
Update on rw_view1 rw_view1_1
-> Subquery Scan on rw_view1
- Filter: ((rw_view1.a < 10) AND (rw_view1.a = 2))
+ Filter: (rw_view1.a = 2)
-> Bitmap Heap Scan on base_tbl
Recheck Cond: (a > 0)
-> Bitmap Index Scan on base_tbl_pkey
@@ -1214,11 +1214,11 @@ EXPLAIN (costs off) UPDATE rw_view2 SET a=3 WHERE a=2;
(7 rows)
EXPLAIN (costs off) DELETE FROM rw_view2 WHERE a=2;
- QUERY PLAN
-----------------------------------------------------------
+ QUERY PLAN
+------------------------------------------------------
Delete on rw_view1 rw_view1_1
-> Subquery Scan on rw_view1
- Filter: ((rw_view1.a < 10) AND (rw_view1.a = 2))
+ Filter: (rw_view1.a = 2)
-> Bitmap Heap Scan on base_tbl
Recheck Cond: (a > 0)
-> Bitmap Index Scan on base_tbl_pkey
@@ -3265,7 +3265,7 @@ UPDATE v1 SET a=a+1 WHERE snoop(a) AND leakproof(a) AND a = 8;
-> Append
-> Index Scan using t1_a_idx on public.t1 t1_1
Output: t1_1.a, t1_1.tableoid, t1_1.ctid
- Index Cond: ((t1_1.a > 5) AND (t1_1.a = 8))
+ Index Cond: (t1_1.a = 8)
Filter: (EXISTS(SubPlan 1) AND snoop(t1_1.a) AND leakproof(t1_1.a))
SubPlan 1
-> Append
@@ -3275,15 +3275,15 @@ UPDATE v1 SET a=a+1 WHERE snoop(a) AND leakproof(a) AND a = 8;
Filter: (t12_2.a = t1_1.a)
-> Index Scan using t11_a_idx on public.t11 t1_2
Output: t1_2.a, t1_2.tableoid, t1_2.ctid
- Index Cond: ((t1_2.a > 5) AND (t1_2.a = 8))
+ Index Cond: (t1_2.a = 8)
Filter: (EXISTS(SubPlan 1) AND snoop(t1_2.a) AND leakproof(t1_2.a))
-> Index Scan using t12_a_idx on public.t12 t1_3
Output: t1_3.a, t1_3.tableoid, t1_3.ctid
- Index Cond: ((t1_3.a > 5) AND (t1_3.a = 8))
+ Index Cond: (t1_3.a = 8)
Filter: (EXISTS(SubPlan 1) AND snoop(t1_3.a) AND leakproof(t1_3.a))
-> Index Scan using t111_a_idx on public.t111 t1_4
Output: t1_4.a, t1_4.tableoid, t1_4.ctid
- Index Cond: ((t1_4.a > 5) AND (t1_4.a = 8))
+ Index Cond: (t1_4.a = 8)
Filter: (EXISTS(SubPlan 1) AND snoop(t1_4.a) AND leakproof(t1_4.a))
(30 rows)
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 81e4222d26..a48841601a 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -136,3 +136,6 @@ test: fast_default
# run tablespace test at the end because it drops the tablespace created during
# setup that other tests may use.
test: tablespace
+
+# run self-contradictory checking test
+test: self_contradictory
\ No newline at end of file
diff --git a/src/test/regress/sql/self_contradictory.sql b/src/test/regress/sql/self_contradictory.sql
new file mode 100644
index 0000000000..921cef335e
--- /dev/null
+++ b/src/test/regress/sql/self_contradictory.sql
@@ -0,0 +1,1481 @@
+--
+-- SELF CONTRADICTORY
+--
+
+-- Create table
+--
+CREATE TABLE self_a (a INT, b INT, c INT, d INT, z BOOL);
+CREATE TABLE self_b (a VARCHAR(6));
+
+--INSERT INTO self_a
+--SELECT ceil(rANDom()*(1000-1)+1) ,
+--ceil(RANDOM()*(1000-1)+1) ,
+--ceil(RANDOM()*(1000-1)+1) ,
+--ceil(RANDOM()*(1000-1)+1) ,
+--(RANDOM())::int::bool
+--FROM generate_series(1 , 300);
+
+--Load data
+--
+
+INSERT INTO self_a VALUES (56 , 118 , 32 , 780 , true);
+INSERT INTO self_a VALUES (854 , 610 , 991 , 526 , false);
+INSERT INTO self_a VALUES (837 , 872 , 417 , 130 , true);
+INSERT INTO self_a VALUES (193 , 326 , 902 , 976 , false);
+INSERT INTO self_a VALUES (414 , 913 , 549 , 289 , true);
+INSERT INTO self_a VALUES (733 , 159 , 285 , 496 , false);
+INSERT INTO self_a VALUES (44 , 253 , 569 , 357 , true);
+INSERT INTO self_a VALUES (269 , 39 , 540 , 941 , true);
+INSERT INTO self_a VALUES (807 , 974 , 329 , 4 , false);
+INSERT INTO self_a VALUES (392 , 582 , 559 , 657 , true);
+INSERT INTO self_a VALUES (836 , 337 , 672 , 303 , false);
+INSERT INTO self_a VALUES (241 , 161 , 464 , 926 , true);
+INSERT INTO self_a VALUES (569 , 792 , 682 , 462 , false);
+INSERT INTO self_a VALUES (994 , 629 , 653 , 562 , true);
+INSERT INTO self_a VALUES (614 , 505 , 543 , 510 , false);
+INSERT INTO self_a VALUES (796 , 634 , 72 , 519 , false);
+INSERT INTO self_a VALUES (982 , 357 , 767 , 752 , true);
+INSERT INTO self_a VALUES (318 , 13 , 119 , 148 , false);
+INSERT INTO self_a VALUES (568 , 940 , 548 , 426 , true);
+INSERT INTO self_a VALUES (356 , 732 , 660 , 303 , true);
+INSERT INTO self_a VALUES (332 , 755 , 409 , 493 , true);
+INSERT INTO self_a VALUES (263 , 710 , 622 , 40 , false);
+INSERT INTO self_a VALUES (205 , 128 , 909 , 468 , true);
+INSERT INTO self_a VALUES (6 , 514 , 536 , 746 , false);
+INSERT INTO self_a VALUES (153 , 850 , 127 , 470 , true);
+INSERT INTO self_a VALUES (289 , 430 , 843 , 929 , true);
+INSERT INTO self_a VALUES (797 , 168 , 438 , 902 , false);
+INSERT INTO self_a VALUES (870 , 667 , 792 , 275 , false);
+INSERT INTO self_a VALUES (247 , 382 , 911 , 522 , false);
+INSERT INTO self_a VALUES (27 , 203 , 125 , 400 , false);
+INSERT INTO self_a VALUES (153 , 678 , 79 , 278 , false);
+INSERT INTO self_a VALUES (731 , 516 , 81 , 324 , false);
+INSERT INTO self_a VALUES (602 , 648 , 892 , 787 , true);
+INSERT INTO self_a VALUES (691 , 177 , 873 , 183 , false);
+INSERT INTO self_a VALUES (455 , 962 , 675 , 268 , false);
+INSERT INTO self_a VALUES (899 , 679 , 71 , 88 , false);
+INSERT INTO self_a VALUES (755 , 985 , 569 , 555 , false);
+INSERT INTO self_a VALUES (862 , 344 , 659 , 984 , true);
+INSERT INTO self_a VALUES (222 , 163 , 299 , 75 , false);
+INSERT INTO self_a VALUES (139 , 603 , 93 , 681 , false);
+INSERT INTO self_a VALUES (196 , 783 , 85 , 485 , false);
+INSERT INTO self_a VALUES (688 , 963 , 463 , 465 , true);
+INSERT INTO self_a VALUES (804 , 894 , 833 , 52 , false);
+INSERT INTO self_a VALUES (254 , 332 , 481 , 563 , true);
+INSERT INTO self_a VALUES (564 , 43 , 33 , 445 , false);
+INSERT INTO self_a VALUES (283 , 4 , 598 , 347 , true);
+INSERT INTO self_a VALUES (108 , 736 , 693 , 731 , false);
+INSERT INTO self_a VALUES (836 , 502 , 543 , 294 , false);
+INSERT INTO self_a VALUES (900 , 739 , 645 , 132 , true);
+INSERT INTO self_a VALUES (918 , 798 , 360 , 621 , false);
+INSERT INTO self_a VALUES (302 , 998 , 212 , 696 , true);
+INSERT INTO self_a VALUES (711 , 906 , 273 , 384 , false);
+INSERT INTO self_a VALUES (699 , 884 , 563 , 120 , true);
+INSERT INTO self_a VALUES (357 , 456 , 709 , 762 , true);
+INSERT INTO self_a VALUES (708 , 276 , 237 , 862 , false);
+INSERT INTO self_a VALUES (274 , 40 , 478 , 495 , true);
+INSERT INTO self_a VALUES (564 , 973 , 743 , 123 , true);
+INSERT INTO self_a VALUES (195 , 848 , 401 , 908 , false);
+INSERT INTO self_a VALUES (819 , 38 , 449 , 715 , false);
+INSERT INTO self_a VALUES (688 , 549 , 702 , 819 , false);
+INSERT INTO self_a VALUES (242 , 716 , 55 , 88 , true);
+INSERT INTO self_a VALUES (866 , 508 , 610 , 30 , false);
+INSERT INTO self_a VALUES (720 , 558 , 719 , 721 , true);
+INSERT INTO self_a VALUES (895 , 106 , 7 , 231 , false);
+INSERT INTO self_a VALUES (895 , 926 , 991 , 18 , true);
+INSERT INTO self_a VALUES (15 , 49 , 670 , 482 , true);
+INSERT INTO self_a VALUES (499 , 122 , 139 , 68 , false);
+INSERT INTO self_a VALUES (44 , 486 , 900 , 526 , false);
+INSERT INTO self_a VALUES (502 , 390 , 266 , 59 , true);
+INSERT INTO self_a VALUES (197 , 481 , 798 , 954 , true);
+INSERT INTO self_a VALUES (1000 , 512 , 245 , 310 , false);
+INSERT INTO self_a VALUES (207 , 938 , 856 , 191 , true);
+INSERT INTO self_a VALUES (666 , 883 , 47 , 664 , false);
+INSERT INTO self_a VALUES (964 , 852 , 439 , 173 , false);
+INSERT INTO self_a VALUES (294 , 262 , 404 , 259 , false);
+INSERT INTO self_a VALUES (81 , 799 , 100 , 620 , true);
+INSERT INTO self_a VALUES (633 , 272 , 145 , 644 , true);
+INSERT INTO self_a VALUES (287 , 256 , 875 , 53 , false);
+INSERT INTO self_a VALUES (962 , 216 , 696 , 315 , false);
+INSERT INTO self_a VALUES (299 , 875 , 355 , 584 , false);
+INSERT INTO self_a VALUES (645 , 249 , 655 , 667 , true);
+INSERT INTO self_a VALUES (223 , 71 , 627 , 251 , true);
+INSERT INTO self_a VALUES (677 , 849 , 978 , 114 , false);
+INSERT INTO self_a VALUES (130 , 199 , 836 , 596 , false);
+INSERT INTO self_a VALUES (710 , 775 , 416 , 215 , false);
+INSERT INTO self_a VALUES (146 , 621 , 442 , 338 , true);
+INSERT INTO self_a VALUES (924 , 349 , 600 , 116 , false);
+INSERT INTO self_a VALUES (165 , 330 , 678 , 57 , true);
+INSERT INTO self_a VALUES (593 , 187 , 258 , 974 , true);
+INSERT INTO self_a VALUES (951 , 698 , 928 , 139 , false);
+INSERT INTO self_a VALUES (322 , 965 , 961 , 464 , false);
+INSERT INTO self_a VALUES (884 , 683 , 173 , 38 , true);
+INSERT INTO self_a VALUES (701 , 443 , 368 , 748 , true);
+INSERT INTO self_a VALUES (461 , 619 , 15 , 596 , true);
+INSERT INTO self_a VALUES (526 , 364 , 607 , 397 , true);
+INSERT INTO self_a VALUES (13 , 937 , 247 , 801 , false);
+INSERT INTO self_a VALUES (538 , 82 , 145 , 879 , false);
+INSERT INTO self_a VALUES (169 , 168 , 389 , 321 , true);
+INSERT INTO self_a VALUES (405 , 769 , 699 , 908 , true);
+INSERT INTO self_a VALUES (348 , 429 , 644 , 521 , false);
+INSERT INTO self_a VALUES (838 , 877 , 729 , 7 , false);
+INSERT INTO self_a VALUES (989 , 254 , 808 , 71 , true);
+INSERT INTO self_a VALUES (699 , 140 , 379 , 557 , true);
+INSERT INTO self_a VALUES (493 , 671 , 500 , 809 , true);
+INSERT INTO self_a VALUES (177 , 403 , 995 , 70 , true);
+INSERT INTO self_a VALUES (750 , 967 , 470 , 128 , true);
+INSERT INTO self_a VALUES (955 , 473 , 813 , 315 , true);
+INSERT INTO self_a VALUES (742 , 784 , 627 , 420 , false);
+INSERT INTO self_a VALUES (403 , 717 , 646 , 329 , true);
+INSERT INTO self_a VALUES (292 , 990 , 701 , 988 , false);
+INSERT INTO self_a VALUES (79 , 78 , 834 , 834 , false);
+INSERT INTO self_a VALUES (440 , 724 , 690 , 536 , false);
+INSERT INTO self_a VALUES (707 , 875 , 351 , 404 , true);
+INSERT INTO self_a VALUES (945 , 955 , 885 , 897 , false);
+INSERT INTO self_a VALUES (108 , 476 , 668 , 405 , false);
+INSERT INTO self_a VALUES (986 , 343 , 552 , 587 , true);
+INSERT INTO self_a VALUES (629 , 22 , 667 , 504 , true);
+INSERT INTO self_a VALUES (104 , 146 , 576 , 513 , true);
+INSERT INTO self_a VALUES (356 , 991 , 397 , 396 , true);
+INSERT INTO self_a VALUES (899 , 817 , 237 , 392 , true);
+INSERT INTO self_a VALUES (240 , 393 , 590 , 310 , false);
+INSERT INTO self_a VALUES (906 , 573 , 999 , 354 , false);
+INSERT INTO self_a VALUES (907 , 66 , 936 , 59 , false);
+INSERT INTO self_a VALUES (577 , 327 , 245 , 713 , false);
+INSERT INTO self_a VALUES (254 , 271 , 113 , 58 , true);
+INSERT INTO self_a VALUES (326 , 43 , 673 , 87 , true);
+INSERT INTO self_a VALUES (867 , 954 , 699 , 647 , false);
+INSERT INTO self_a VALUES (99 , 826 , 378 , 172 , false);
+INSERT INTO self_a VALUES (158 , 375 , 950 , 802 , false);
+INSERT INTO self_a VALUES (104 , 157 , 523 , 396 , true);
+INSERT INTO self_a VALUES (902 , 125 , 613 , 44 , false);
+INSERT INTO self_a VALUES (564 , 635 , 608 , 48 , true);
+INSERT INTO self_a VALUES (753 , 539 , 692 , 111 , true);
+INSERT INTO self_a VALUES (27 , 613 , 633 , 693 , true);
+INSERT INTO self_a VALUES (859 , 855 , 512 , 28 , false);
+INSERT INTO self_a VALUES (684 , 452 , 757 , 209 , false);
+INSERT INTO self_a VALUES (198 , 591 , 500 , 940 , false);
+INSERT INTO self_a VALUES (442 , 198 , 182 , 663 , true);
+INSERT INTO self_a VALUES (797 , 965 , 909 , 98 , false);
+INSERT INTO self_a VALUES (466 , 665 , 849 , 828 , true);
+INSERT INTO self_a VALUES (615 , 689 , 767 , 773 , false);
+INSERT INTO self_a VALUES (743 , 760 , 860 , 232 , true);
+INSERT INTO self_a VALUES (86 , 444 , 683 , 217 , true);
+INSERT INTO self_a VALUES (772 , 725 , 436 , 862 , true);
+INSERT INTO self_a VALUES (34 , 820 , 627 , 320 , true);
+INSERT INTO self_a VALUES (5 , 437 , 23 , 829 , false);
+INSERT INTO self_a VALUES (697 , 222 , 752 , 984 , true);
+INSERT INTO self_a VALUES (426 , 273 , 972 , 901 , false);
+INSERT INTO self_a VALUES (782 , 610 , 78 , 267 , true);
+INSERT INTO self_a VALUES (238 , 126 , 75 , 601 , true);
+INSERT INTO self_a VALUES (385 , 443 , 912 , 100 , true);
+INSERT INTO self_a VALUES (939 , 715 , 692 , 21 , true);
+INSERT INTO self_a VALUES (108 , 291 , 894 , 132 , false);
+INSERT INTO self_a VALUES (632 , 316 , 108 , 815 , true);
+INSERT INTO self_a VALUES (849 , 847 , 786 , 601 , false);
+INSERT INTO self_a VALUES (218 , 153 , 138 , 574 , true);
+INSERT INTO self_a VALUES (947 , 673 , 758 , 151 , true);
+INSERT INTO self_a VALUES (146 , 807 , 30 , 963 , false);
+INSERT INTO self_a VALUES (748 , 222 , 931 , 664 , true);
+INSERT INTO self_a VALUES (916 , 19 , 100 , 457 , false);
+INSERT INTO self_a VALUES (921 , 287 , 386 , 201 , true);
+INSERT INTO self_a VALUES (521 , 177 , 935 , 268 , true);
+INSERT INTO self_a VALUES (58 , 222 , 195 , 749 , true);
+INSERT INTO self_a VALUES (95 , 430 , 46 , 825 , true);
+INSERT INTO self_a VALUES (290 , 121 , 520 , 759 , false);
+INSERT INTO self_a VALUES (655 , 640 , 203 , 331 , false);
+INSERT INTO self_a VALUES (30 , 950 , 632 , 526 , true);
+INSERT INTO self_a VALUES (997 , 996 , 179 , 575 , true);
+INSERT INTO self_a VALUES (523 , 881 , 463 , 602 , false);
+INSERT INTO self_a VALUES (277 , 298 , 806 , 724 , true);
+INSERT INTO self_a VALUES (601 , 467 , 772 , 305 , false);
+INSERT INTO self_a VALUES (169 , 341 , 646 , 492 , false);
+INSERT INTO self_a VALUES (739 , 718 , 98 , 513 , true);
+INSERT INTO self_a VALUES (91 , 996 , 871 , 954 , true);
+INSERT INTO self_a VALUES (248 , 367 , 704 , 899 , true);
+INSERT INTO self_a VALUES (679 , 192 , 687 , 192 , true);
+INSERT INTO self_a VALUES (840 , 429 , 830 , 93 , false);
+INSERT INTO self_a VALUES (750 , 263 , 652 , 749 , true);
+INSERT INTO self_a VALUES (835 , 478 , 266 , 402 , true);
+INSERT INTO self_a VALUES (264 , 277 , 668 , 230 , true);
+INSERT INTO self_a VALUES (55 , 662 , 473 , 776 , true);
+INSERT INTO self_a VALUES (800 , 594 , 825 , 638 , true);
+INSERT INTO self_a VALUES (549 , 29 , 951 , 607 , false);
+INSERT INTO self_a VALUES (472 , 908 , 939 , 703 , true);
+INSERT INTO self_a VALUES (536 , 969 , 814 , 303 , true);
+INSERT INTO self_a VALUES (316 , 173 , 228 , 312 , false);
+INSERT INTO self_a VALUES (584 , 885 , 329 , 479 , false);
+INSERT INTO self_a VALUES (229 , 716 , 536 , 417 , false);
+INSERT INTO self_a VALUES (177 , 769 , 282 , 339 , true);
+INSERT INTO self_a VALUES (987 , 512 , 477 , 629 , false);
+INSERT INTO self_a VALUES (744 , 252 , 336 , 551 , false);
+INSERT INTO self_a VALUES (655 , 429 , 250 , 603 , true);
+INSERT INTO self_a VALUES (965 , 733 , 863 , 363 , false);
+INSERT INTO self_a VALUES (459 , 276 , 576 , 510 , true);
+INSERT INTO self_a VALUES (626 , 986 , 829 , 345 , false);
+INSERT INTO self_a VALUES (434 , 614 , 655 , 288 , true);
+INSERT INTO self_a VALUES (570 , 17 , 675 , 416 , true);
+INSERT INTO self_a VALUES (882 , 270 , 147 , 862 , false);
+INSERT INTO self_a VALUES (593 , 669 , 145 , 386 , false);
+INSERT INTO self_a VALUES (313 , 369 , 21 , 781 , true);
+INSERT INTO self_a VALUES (869 , 116 , 133 , 611 , true);
+INSERT INTO self_a VALUES (604 , 368 , 695 , 100 , true);
+INSERT INTO self_a VALUES (943 , 847 , 120 , 483 , true);
+INSERT INTO self_a VALUES (396 , 231 , 437 , 772 , false);
+INSERT INTO self_a VALUES (583 , 177 , 580 , 506 , true);
+INSERT INTO self_a VALUES (170 , 542 , 784 , 61 , false);
+INSERT INTO self_a VALUES (978 , 493 , 12 , 236 , false);
+INSERT INTO self_a VALUES (222 , 162 , 612 , 15 , false);
+INSERT INTO self_a VALUES (585 , 138 , 641 , 274 , true);
+INSERT INTO self_a VALUES (246 , 657 , 243 , 852 , true);
+INSERT INTO self_a VALUES (62 , 869 , 96 , 25 , false);
+INSERT INTO self_a VALUES (847 , 224 , 676 , 869 , false);
+INSERT INTO self_a VALUES (211 , 709 , 672 , 470 , true);
+INSERT INTO self_a VALUES (366 , 647 , 964 , 221 , false);
+INSERT INTO self_a VALUES (980 , 847 , 37 , 587 , false);
+INSERT INTO self_a VALUES (450 , 386 , 594 , 112 , false);
+INSERT INTO self_a VALUES (729 , 463 , 931 , 920 , false);
+INSERT INTO self_a VALUES (498 , 604 , 51 , 871 , false);
+INSERT INTO self_a VALUES (464 , 727 , 491 , 891 , false);
+INSERT INTO self_a VALUES (522 , 316 , 82 , 316 , true);
+INSERT INTO self_a VALUES (32 , 27 , 138 , 337 , false);
+INSERT INTO self_a VALUES (733 , 939 , 991 , 449 , true);
+INSERT INTO self_a VALUES (221 , 235 , 992 , 855 , false);
+INSERT INTO self_a VALUES (770 , 463 , 881 , 616 , false);
+INSERT INTO self_a VALUES (558 , 738 , 71 , 74 , false);
+INSERT INTO self_a VALUES (914 , 682 , 217 , 242 , false);
+INSERT INTO self_a VALUES (524 , 444 , 281 , 455 , false);
+INSERT INTO self_a VALUES (778 , 756 , 230 , 393 , false);
+INSERT INTO self_a VALUES (114 , 63 , 606 , 47 , true);
+INSERT INTO self_a VALUES (657 , 625 , 890 , 806 , false);
+INSERT INTO self_a VALUES (988 , 903 , 337 , 739 , true);
+INSERT INTO self_a VALUES (536 , 189 , 430 , 446 , true);
+INSERT INTO self_a VALUES (357 , 44 , 70 , 638 , false);
+INSERT INTO self_a VALUES (540 , 578 , 772 , 484 , true);
+INSERT INTO self_a VALUES (567 , 975 , 658 , 611 , true);
+INSERT INTO self_a VALUES (458 , 747 , 744 , 234 , false);
+INSERT INTO self_a VALUES (695 , 291 , 666 , 535 , false);
+INSERT INTO self_a VALUES (4 , 23 , 607 , 997 , true);
+INSERT INTO self_a VALUES (345 , 401 , 923 , 576 , true);
+INSERT INTO self_a VALUES (634 , 912 , 328 , 860 , true);
+INSERT INTO self_a VALUES (104 , 807 , 925 , 747 , true);
+INSERT INTO self_a VALUES (155 , 19 , 238 , 464 , true);
+INSERT INTO self_a VALUES (569 , 117 , 844 , 808 , false);
+INSERT INTO self_a VALUES (171 , 227 , 751 , 287 , true);
+INSERT INTO self_a VALUES (196 , 762 , 443 , 759 , true);
+INSERT INTO self_a VALUES (657 , 445 , 668 , 569 , false);
+INSERT INTO self_a VALUES (372 , 215 , 899 , 368 , true);
+INSERT INTO self_a VALUES (223 , 794 , 499 , 736 , false);
+INSERT INTO self_a VALUES (433 , 94 , 321 , 359 , true);
+INSERT INTO self_a VALUES (423 , 575 , 251 , 637 , false);
+INSERT INTO self_a VALUES (508 , 734 , 783 , 781 , true);
+INSERT INTO self_a VALUES (278 , 653 , 931 , 500 , false);
+INSERT INTO self_a VALUES (726 , 993 , 9 , 298 , true);
+INSERT INTO self_a VALUES (677 , 426 , 376 , 226 , false);
+INSERT INTO self_a VALUES (967 , 639 , 659 , 731 , false);
+INSERT INTO self_a VALUES (488 , 774 , 321 , 573 , false);
+INSERT INTO self_a VALUES (65 , 909 , 5 , 331 , true);
+INSERT INTO self_a VALUES (426 , 554 , 297 , 168 , true);
+INSERT INTO self_a VALUES (460 , 846 , 500 , 416 , true);
+INSERT INTO self_a VALUES (887 , 664 , 705 , 592 , true);
+INSERT INTO self_a VALUES (98 , 83 , 24 , 146 , false);
+INSERT INTO self_a VALUES (79 , 343 , 431 , 601 , false);
+INSERT INTO self_a VALUES (127 , 942 , 871 , 783 , true);
+INSERT INTO self_a VALUES (20 , 441 , 998 , 508 , false);
+INSERT INTO self_a VALUES (267 , 62 , 303 , 239 , true);
+INSERT INTO self_a VALUES (239 , 62 , 439 , 837 , true);
+INSERT INTO self_a VALUES (89 , 686 , 252 , 569 , false);
+INSERT INTO self_a VALUES (891 , 135 , 718 , 114 , true);
+INSERT INTO self_a VALUES (606 , 246 , 74 , 214 , false);
+INSERT INTO self_a VALUES (552 , 359 , 115 , 783 , false);
+INSERT INTO self_a VALUES (712 , 930 , 700 , 976 , false);
+INSERT INTO self_a VALUES (107 , 852 , 200 , 230 , true);
+INSERT INTO self_a VALUES (554 , 263 , 759 , 69 , false);
+INSERT INTO self_a VALUES (391 , 345 , 544 , 436 , false);
+INSERT INTO self_a VALUES (12 , 425 , 493 , 606 , false);
+INSERT INTO self_a VALUES (869 , 453 , 75 , 48 , true);
+INSERT INTO self_a VALUES (455 , 58 , 920 , 372 , true);
+INSERT INTO self_a VALUES (227 , 864 , 928 , 982 , false);
+INSERT INTO self_a VALUES (6 , 513 , 218 , 928 , false);
+INSERT INTO self_a VALUES (844 , 740 , 455 , 993 , false);
+INSERT INTO self_a VALUES (850 , 418 , 336 , 521 , false);
+INSERT INTO self_a VALUES (209 , 470 , 482 , 456 , true);
+INSERT INTO self_a VALUES (177 , 631 , 900 , 590 , true);
+INSERT INTO self_a VALUES (899 , 485 , 322 , 890 , true);
+INSERT INTO self_a VALUES (733 , 33 , 64 , 48 , true);
+INSERT INTO self_a VALUES (700 , 47 , 989 , 640 , false);
+INSERT INTO self_a VALUES (252 , 571 , 608 , 239 , false);
+INSERT INTO self_a VALUES (480 , 100 , 299 , 783 , false);
+INSERT INTO self_a VALUES (40 , 341 , 956 , 192 , false);
+INSERT INTO self_a VALUES (304 , 201 , 128 , 344 , true);
+INSERT INTO self_a VALUES (150 , 276 , 114 , 435 , false);
+INSERT INTO self_a VALUES (412 , 482 , 930 , 265 , false);
+INSERT INTO self_a VALUES (219 , 597 , 726 , 347 , true);
+INSERT INTO self_a VALUES (248 , 74 , 303 , 763 , true);
+INSERT INTO self_a VALUES (402 , 604 , 706 , 483 , true);
+INSERT INTO self_a VALUES (491 , 662 , 324 , 100 , false);
+INSERT INTO self_a VALUES (680 , 890 , 651 , 440 , true);
+INSERT INTO self_a VALUES (42 , 791 , 890 , 623 , true);
+INSERT INTO self_a VALUES (144 , 166 , 928 , 774 , false);
+INSERT INTO self_a VALUES (272 , 507 , 710 , 514 , true);
+
+INSERT INTO self_a VALUES (NULL, NULL, NULL, NULL);
+
+CREATE INDEX idx_self_a ON self_a USING BTREE (a , b , c);
+
+ANALYZE self_a;
+--
+-- Test single attribute self-contradictory
+--
+explain (costs off)
+SELECT * FROM self_a WHERE a > 10 AND a < 9;
+
+explain (costs off)
+SELECT * FROM self_a WHERE a >= 10 AND a < 10;
+
+explain (costs off)
+SELECT * FROM self_a WHERE a <= 10 AND a > 10;
+
+explain (costs off)
+SELECT * FROM self_a WHERE a <= 10 AND a >= 10;
+
+explain (costs off)
+SELECT * FROM self_a WHERE a >= 10 AND a < 10 AND a > 8 AND a <= 12;
+
+explain (costs off)
+SELECT * FROM self_a WHERE a > 10 AND a = 10;
+
+explain (costs off)
+SELECT * FROM self_a WHERE a >= 10 AND a = 10;
+
+explain (costs off)
+SELECT * FROM self_a WHERE a < 10 AND a = 10;
+
+explain (costs off)
+SELECT * FROM self_a WHERE a <= 10 AND a = 10;
+
+explain (costs off)
+SELECT * FROM self_a WHERE a = 10 AND a <> 10;
+
+explain (costs off)
+SELECT * FROM self_a WHERE a = 10 AND a <> 9;
+
+--
+-- Boolean type is a little tricky.
+--
+
+explain (costs off)
+SELECT * FROM self_a WHERE z IS TRUE AND z IS NOT TRUE;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z IS TRUE AND z IS FALSE;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z IS TRUE AND z IS NOT FALSE;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z IS TRUE AND z IS UNKNOWN;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z IS TRUE AND z IS NOT UNKNOWN;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z IS FALSE AND z IS NOT FALSE;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z IS FALSE AND z IS UNKNOWN;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z IS FALSE AND z IS NOT UNKNOWN;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z IS UNKNOWN AND z IS TRUE;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z IS UNKNOWN AND z IS NOT TRUE;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z IS UNKNOWN AND z IS NOT UNKNOWN;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z AND z IS NOT TRUE;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z AND z IS NOT FALSE;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z AND z IS FALSE;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z AND z IS TRUE;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z AND z IS UNKNOWN;
+
+explain (costs off)
+SELECT * FROM self_a WHERE NOT z AND z IS NOT UNKNOWN;
+
+explain (costs off)
+SELECT * FROM self_a WHERE NOT z AND z IS NOT TRUE;
+
+explain (costs off)
+SELECT * FROM self_a WHERE NOT z AND z IS NOT FALSE;
+
+explain (costs off)
+SELECT * FROM self_a WHERE NOT z AND z IS FALSE;
+
+explain (costs off)
+SELECT * FROM self_a WHERE NOT z AND z IS TRUE;
+
+explain (costs off)
+SELECT * FROM self_a WHERE NOT z AND z IS UNKNOWN;
+
+explain (costs off)
+SELECT * FROM self_a WHERE NOT z AND z IS NOT UNKNOWN;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z = TRUE AND NOT z;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z >= TRUE AND NOT z;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z >= FALSE AND NOT z;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z = TRUE AND z;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z = TRUE AND z IS TRUE;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z = TRUE AND z IS FALSE;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z = TRUE AND z IS NOT TRUE;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z = TRUE AND z IS NOT FALSE;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z = TRUE AND z IS UNKNOWN;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z = TRUE AND z IS NOT UNKNOWN;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z = TRUE AND z >= TRUE;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z = TRUE AND z > TRUE;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z = TRUE AND z <= TRUE;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z = TRUE AND z < TRUE;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z < FALSE;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z > TRUE;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z >= TRUE AND z IS UNKNOWN;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z >= TRUE AND z IS NOT TRUE;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z >= TRUE AND z IS NOT FALSE;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z >= TRUE AND z IS FALSE;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z > FALSE AND z IS UNKNOWN;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z > FALSE AND z IS NOT UNKNOWN;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z > FALSE AND NOT z;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z > FALSE AND z IS NOT TRUE;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z >= FALSE AND z IS NOT TRUE;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z > FALSE AND z IS NOT FALSE;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z > FALSE AND z IS FALSE;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z <> TRUE AND z;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z <> TRUE AND NOT z;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z <> TRUE AND z = true;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z <> TRUE AND z > false;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z <> TRUE AND z >= false;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z <> TRUE AND z >= true;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z <> FALSE AND NOT z;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z <> FALSE AND z >= false;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z <> FALSE AND z <= false;
+
+--
+-- Null test
+--
+
+explain (costs off)
+SELECT * FROM self_a WHERE a IS NULL AND a IS NOT NULL;
+
+explain (costs off)
+SELECT * FROM self_a WHERE a IS NOT NULL AND a > 10;
+
+explain (costs off)
+SELECT * FROM self_a WHERE a IS NULL AND a = 10;
+
+explain (costs off)
+SELECT * FROM self_a WHERE a IS NULL AND a > 10;
+
+explain (costs off)
+SELECT * FROM self_a WHERE a IS NULL AND a <> 10;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z IS NULL AND z;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z IS NULL AND NOT z;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z IS NULL AND z <> TRUE;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z IS NULL AND z IS TRUE;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z IS NULL AND z IS NOT TRUE;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z IS NULL AND z IS UNKNOWN;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z IS NULL AND z IS NOT UNKNOWN;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z IS NOT NULL AND NOT z;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z IS NOT NULL AND z <> TRUE;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z IS NOT NULL AND z IS TRUE;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z IS NOT NULL AND z IS NOT TRUE;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z IS NOT NULL AND z IS NOT UNKNOWN;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z IS NOT NULL AND z IS UNKNOWN;
+
+--
+-- Test weak restriction that have the sematic of same level will being eliminated and IS self contradictory or not
+--
+explain (costs off)
+SELECT * FROM self_a WHERE a > 4 AND a > 5;
+
+explain (costs off)
+SELECT * FROM self_a WHERE a > 4 AND a > 5 AND a < 5;
+
+explain (costs off)
+SELECT * FROM self_a WHERE a > 4 AND a >= 5;
+
+explain (costs off)
+SELECT * FROM self_a WHERE a > 4 AND a >= 5 AND a < 5;
+
+explain (costs off)
+SELECT * FROM self_a WHERE a > 4 AND a >= 4;
+
+explain (costs off)
+SELECT * FROM self_a WHERE a > 4 AND a >= 4 AND a < 4;
+
+explain (costs off)
+SELECT * FROM self_a WHERE a >= 4 AND a >= 5;
+
+explain (costs off)
+SELECT * FROM self_a WHERE a >= 4 AND a >= 5 AND a < 5;
+
+explain (costs off)
+SELECT * FROM self_a WHERE a >= 4 AND a > 5;
+
+explain (costs off)
+SELECT * FROM self_a WHERE a >= 4 AND a > 5 AND a < 5;
+
+explain (costs off)
+SELECT * FROM self_a WHERE a >= 4 AND a = 4;
+
+explain (costs off)
+SELECT * FROM self_a WHERE a >= 4 AND a = 4 AND a <> 4;
+
+explain (costs off)
+SELECT * FROM self_a WHERE a >= 3 AND a = 4;
+
+explain (costs off)
+SELECT * FROM self_a WHERE a >= 3 AND a = 4 AND a < 4;
+
+explain (costs off)
+SELECT * FROM self_a WHERE a > 3 AND a = 4;
+
+explain (costs off)
+SELECT * FROM self_a WHERE a <> 3 AND a = 4;
+
+explain (costs off)
+SELECT * FROM self_a WHERE a <> 3 AND a = 4 AND a > 4;
+
+--
+-- Test same type coercion will be accepted
+--
+explain (costs off)
+select * from self_a WHERE a = 1 AND a <>'1'::int;
+
+--
+-- Test different type coercion will be ignored
+--
+explain (costs off)
+SELECT * FROM self_a WHERE a = 1 AND a <>'1'::bigint;
+
+--
+-- Test specified collation will be ignored
+--
+explain (costs off)
+SELECT * FROM self_b WHERE a > 'c' AND a < 'b' COLLATE "pg_c_utf8";
+
+
+explain (costs off)
+SELECT * FROM self_b WHERE a > 'c' AND a < 'b';
+
+--
+-- Redundant clause will be eliminated
+--
+explain (costs off)
+select * from self_a WHERE a = 1 AND a = 1;
+
+explain (costs off)
+select * from self_a WHERE a > 10 AND a > 10;
+
+explain (costs off)
+select * from self_a WHERE a >= 10 AND a >= 10;
+
+explain (costs off)
+select * from self_a WHERE a < 4 AND a < 4;
+
+explain (costs off)
+select * from self_a WHERE a <= 4 AND a <= 4;
+
+--
+-- Test base or-clause
+--
+
+--
+-- Test or-clause self-contradictory
+--
+explain (costs off)
+SELECT * FROM self_a WHERE a > 10 AND a < 9 OR b > 8 AND b < 6;
+
+explain (costs off)
+SELECT * FROM self_a WHERE a > 10 AND a < 9 OR ((b > 8 AND b < 7 or b = 10) AND b < 6);
+
+--
+-- Test or-clause can be pruned
+--
+explain (costs off)
+SELECT * FROM self_a WHERE a < 9 AND a > 10 OR b < 8;
+
+SELECT * FROM self_a WHERE a < 9 AND a > 10 OR b < 8;
+
+--
+-- Test or-clause redundant clause will be eliminated
+--
+
+explain (costs off)
+SELECT * FROM self_a WHERE a < 14 AND a < 10 OR b < 8;
+
+SELECT * FROM self_a WHERE a < 14 AND a < 10 OR b < 8;
+
+--
+-- Test same level and-clause whether can be push down into or-clause to test self-contradictory and can be pruned
+--
+explain (costs off)
+SELECT * FROM self_a WHERE a > 10 AND b > 12 AND (a < 9 OR b < 11);
+
+explain (costs off)
+SELECT * FROM self_a WHERE a > 10 AND b > 12 AND (a < 9 AND b < 11 OR b <=16);
+
+SELECT * FROM self_a WHERE a > 10 AND b > 12 AND (a < 9 AND b < 11 OR b <=16);
+
+--
+-- Test mixed expr clause
+--
+
+explain (costs off)
+SELECT * FROM self_a WHERE NOT(a = 1 AND a <>1) AND a = 1;
+
+explain (costs off)
+SELECT * FROM self_a WHERE a IS NULL AND a IS NOT NULL OR a = 1;
+
+explain (costs off)
+SELECT * FROM self_a WHERE a IS NULL AND a IS NOT NULL OR a = 1 AND a > 2;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z IS TRUE AND z IS NOT TRUE OR a = 1 AND a > 2;
+
+explain (costs off)
+SELECT * FROM self_a WHERE z = TRUE AND z IS NOT TRUE OR z IS NULL AND z IS NOT NULL;
+
+explain (costs off)
+SELECT * FROM self_a WHERE a BETWEEN 10 AND 5;
+
+explain (costs off)
+SELECT * FROM self_a WHERE (a > 4::bigint AND a > 4 AND a < 4 OR b > 3 AND b < 2) OR (a < 20);
+
+SELECT * FROM self_a WHERE (a > 1 AND a <1 OR b < 10 ) AND z IS TRUE OR b < 20 or z IS null;
+
+--
+-- Test pruned and self-contradictory mixed case
+--
+
+explain (costs off)
+SELECT * FROM self_a WHERE (a > 10 AND a > 12 OR b > 8) AND b < 7 AND b < 15;
+
+explain (costs off)
+SELECT * FROM self_a WHERE a > 10 AND b > 12 AND (a > 10 AND a < 9 OR b < 11 OR a < 7);
+
+explain (costs off)
+SELECT * FROM self_a WHERE a > 10 AND b > 12 AND (((a < 9 OR b < 11) OR (b < 15 AND b < 17 OR a <12)) OR b >=8 AND a < 14);
+
+explain (costs off)
+SELECT * FROM self_a WHERE a <> 3 AND a <> 4 AND a <> 8 AND (b > 12 AND c < 80 OR c = 16 AND (a = 4 OR a = 8));
+
+explain (costs off)
+SELECT * FROM self_a WHERE a IS not null AND (b > 12 AND c < 80 OR c = 16 AND (a IS null OR a = 8));
+
+--
+-- Test self-contradictory join case
+--
+explain (costs off)
+SELECT * FROM self_a a LEFT JOIN self_a b ON a.a = b.a WHERE b.a > 300 AND a.a = 145;
+
+explain (costs off)
+select * from self_a a JOIN self_a b ON a.a =b.a WHERE a.a= 145 AND b.a < 79;
+
+--
+-- Test row comparison
+-- It's need to add define DEBUG_ROW_DECODE for debug
+--
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b) > (NULL , 3);
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , c) < (100 , null , 3);
+
+--Equal expression
+--a<100
+--or a=100 and b<null
+--or a=100 and b=null and c<3
+
+--After converted
+--a<100
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , c) < (100 , null , 3) AND a = 101;
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , c) > (1 , 2 , null);
+
+--Equal expression
+--a>1
+--or a=1 AND b>2
+--or a=1 AND b=2 AND c>null
+
+--After converted
+--a>1
+--or a=1 AND b>2
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , c) > (1 , 2 , null) AND a < 1;
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(NULL , b) > (3 , 3);
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , null , b) > (2 , 3 , 4);
+
+--Equal expression
+--a>2
+--or a=2 and null>3
+--or a=2 and null=3 and b>4
+
+--After converted
+--a>2
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , null , b) > (2 , 3 , 4) AND a = 2;
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , null) >= (2 , 3 , 4);
+
+--Equal expression
+--a>2
+--or a=2 and b>3
+--or a=2 and b=3 and null>=4
+
+--After converted
+--a>2
+--or a=2 and b>3
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , null) >= (2 , 3 , 4) AND a < 2;
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , null) > (2 , 3 , 4);
+
+--Equal expression
+--a>2
+--or a=2 and b>3
+--or a=2 and b=3 and null>4
+
+--After converted
+--a>2
+--or a=2 and b>3
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , c) >= (a , 3 , 4);
+
+--Equal expression
+--a>a
+--or a=a AND b>3
+--or a=a AND b=3 AND c>=4
+
+--After converted
+--a is not null and b>3
+--or a IS not null and b=3 AND c>=4
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , c) >= (a , 3 , 4) AND a IS NULL;
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , c) > (a , 3 , 4);
+
+--Equal expression
+--a>a
+--or a=a AND b>3
+--or a=a AND b=3 AND c>4
+
+--After converted
+--a is not null and b>3
+--or a IS not null and b=3 AND c>4
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , c) >= (2 , b , 4);
+
+--Equal expression
+--a>2
+--or a=2 and b>b
+--or a=2 AND b=b AND c >=4
+
+--After converted
+--a>2
+--or a=2 AND b IS not null AND c >=4
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , c) >= (2 , b , 4) AND a = 2 AND c < 4;
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , c) > (2 , b , 4);
+
+--Equal expression
+--a>2
+--or a=2 and b>b
+--or a=2 AND b=b AND c >4
+
+--After converted
+--a>2
+--or a=2 AND b IS not null AND c >4
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , c) >= (2 , 3 , c);
+
+--Equal expression
+--a>2
+--or a=2 AND b>3
+--or a=2 AND b=3 AND c>=c
+
+--After converted
+--a>2
+--or a=2 AND b>3
+--or a=2 AND b=3 AND c IS not null
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , c) >= (2 , 3 , c) AND a = 2 AND c = 3 AND c IS NULL;
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , c) > (2 , 3 , c);
+
+--Equal expression
+--a>2
+--or a=2 AND b>3
+--or a=2 AND b=3 AND c>c
+
+--After converted
+--a>2
+--or a=2 AND b>3
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , c) > (2 , b , c);
+
+--Equal expression
+--a>2
+--or a=2 AND b>b
+--or a=2 AND b=b AND c>c
+
+--After converted
+--a>2
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , c) > (2 , b , c) AND a = 2;
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , c) >= (2 , b , c);
+
+--Equal expression
+--a>2
+--or a=2 AND b>b
+--or a=2 AND b=b AND c>=c
+
+--After converted
+--a>2
+--or a=2 AND b=b AND c>=c
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , c) >= (2 , b , c) AND a = 2 AND b IS NULL;
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , c) > (a , b , c);
+
+--Equal expression
+--a>a
+--or a=a AND b>b
+--or a=a AND b=b AND c>c
+
+--After converted
+--false
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , c) >= (a , b , c);
+
+--Equal expression
+--a>a
+--or a=a AND b>b
+--or a=a AND b=b AND c>=c
+
+--After converted
+--a=a AND b=b AND c>=c
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , c) >= (a , b , c) AND a IS NULL;
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(2 , b , c) >= (2 , 3 , 4);
+
+--Equal expression
+--2>2
+--or 2=2 AND b>3
+--or 2=2 AND b=3 AND c>=4
+
+--After converted
+--b>3
+--or b=3 AND c>=4
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(2 , b , c) >= (2 , 3 , 4) AND c < 4 AND b = 3;
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(2 , b , c) > (2 , 3 , 4);
+
+--Equal expression
+--2>2
+--or 2=2 AND b>3
+--or 2=2 AND b=3 AND c>=4
+
+--After converted
+--b>3
+--or b=3 AND c>4
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , 3 , c) >= (2 , 3 , 4);
+
+--Equal expression
+--a>2
+--or a=2 AND 3>3
+--or a=2 AND 3=3 AND c>=4
+
+--After converted
+--a>2
+--or a=2 AND c>=4
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , 3 , c) >= (2 , 3 , 4) AND c < 4 AND a = 1;
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , 4) >= (2 , 3 , 4);
+
+--Equal expression
+--a>2
+--or a=2 AND b>3
+--or a=2 AND b=3 AND 4>=4
+
+--After converted
+--a>2
+--or a=2 AND b>3
+--or a=2 AND b=3
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , 4) >= (2 , 3 , 4) AND b = 3 AND a = 1;
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , 4) > (2 , 3 , 4);
+
+--Equal expression
+--a>2
+--or a=2 AND b>3
+--or a=2 AND b=3 AND 4>4
+
+--After converted
+--a>2
+--or a=2 AND b>3
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , 4) > (2 , 3 , 4) AND a = 2 AND b = 1;
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , 3 , 4) >= (2 , 3 , 4);
+
+--Equal expression
+--a>2
+--or a=2 AND 3>3
+--or a=2 AND 3=3 AND 4>=4
+
+--After converted
+--a>2
+--or a=2
+
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , 3 , 4) >= (2 , 3 , 4) AND a = 1;
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , 3 , 4) > (2 , 3 , 4);
+
+--Equal expression
+--a>2
+--or a=2 AND 3>3
+--or a=2 AND 3=3 AND 4>4
+
+--After converted
+--a>2
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , 3 , 4) > (2 , 3 , 4) AND a = 1;
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(2 , 3 , 4) >= (2 , 3 , 4);
+
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(2 , 3 , 4) > (2 , 3 , 4);
+
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , 3 , 4) > (a , 3 , 4);
+
+--Equal expression
+--a>a
+--or a=a AND 3>3
+--or a=a AND 3=3 AND 4>4
+
+--After converted
+--false
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , 3 , 4) >= (a , 3 , 4);
+
+--Equal expression
+--a>a
+--or a=a AND 3>3
+--or a=a AND 3=3 AND 4>=4
+
+--After converted
+--a IS NOT NULL
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , 3 , 4) >= (a , 3 , 4) AND a IS NULL;
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(4 , a , b) > (4 , a , b);
+
+--After converted
+--false
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(4 , a , b) >= (4 , a , b);
+
+--Equal expression
+--4>4
+--or 4=4 AND a>a
+--or 4=4 AND a=a AND b>=b
+
+--After converted
+--a IS NOT NULL and b IS NOT NULL
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(4 , a , b) >= (4 , a , b) AND a IS NULL;
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , 4 , b) >= (a , 4 , b);
+
+--Equal expression
+--a>a
+--or a=a AND 4>4
+--or a=a AND 4=4 AND b>=b
+
+--After converted
+--a IS NOT NULL and b IS NOT NULL
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(4 , a , 4) >= (4 , a , 4);
+
+--Equal expression
+--4>4
+--or 4=4 AND a>a
+--or 4=4 AND a=a AND 4>=4
+
+--After converted
+--a IS NOT NULL
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , a , a) >= (a , a , a);
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , a , a) > (a , a , a);
+
+--Test const are not equal
+
+--negative
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(1 , b , c) >= (2 , 3 , 4);
+
+--Equal expression
+--1>2
+--or 1=2 AND b>3
+--or 1=2 AND b=3 AND c>=4
+
+--After converted
+--false
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(1 , b , c) > (2 , 3 , 4);
+
+--Equal expression
+--1>2
+--or 1=2 AND b>3
+--or 1=2 AND b=3 AND c>4
+
+--After converted
+--false
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , 2 , c) >= (2 , 3 , 4);
+
+--Equal expression
+--a>2
+--or a=2 AND 2>3
+--or a=2 AND 2=3 AND c>=4
+
+--After converted
+--a>2
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , 2 , c) >= (2 , 3 , 4) AND a = 2;
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , 3) >= (2 , 3 , 4);
+
+--Equal expression
+--a>2
+--or a=2 AND b>3
+--or a=2 AND b=3 AND 3>=4
+
+--After converted
+--a>2
+--or a=2 AND b>3
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , 3) >= (2 , 3 , 4) AND a < 2;
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , 3 , c) >= (2 , 3 , 4 , 5);
+
+--Equal expression
+--a>2
+--or a=2 AND b>3
+--or a=2 AND b=3 AND 3>=4
+--or a=2 AND b=3 AND 3=4 and c>=5
+
+--After converted
+--a>2
+--or a=2 AND b>3
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , 3) >= (a , b , 4);
+
+--Equal expression
+--a>a
+--or a=a AND b>b
+--or a=a AND b=b AND 3>=4
+
+--After converted
+--false
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , 5 , b , 3) >= (a , 5 , b , 4);
+
+--Equal expression
+--a>a
+--or a=a AND 5>5
+--or a=a AND 5=5 and b>b
+--or a=a AND 5=5 and b=b and 3>=4
+
+--After converted
+--false
+
+--positive
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(5 , b , c) > (2 , 3 , 4);
+
+--Equal expression
+--5>2
+--or 5=2 AND b>3
+--or 5=2 AND b=3 AND c>4
+
+--After converted
+--true
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , 5 , c) >= (2 , 3 , 4);
+
+--Equal expression
+--a>2
+--or a=2 AND 5>3
+--or a=2 AND 5=3 AND c>=4
+
+--After converted
+--a>2
+--or a=2
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , 5 , c) >= (2 , 3 , 4) AND a = 1;
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , 5) >= (2 , 3 , 4);
+
+--Equal expression
+--a>2
+--or a=2 AND b>3
+--or a=2 AND b=3 AND 5>=4
+
+--After converted
+--a>2
+--or a=2 AND b>3
+--or a=2 AND b=3
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , 5) >= (2 , 3 , 4) AND a = 2 AND b < 3;
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b , 5 , c) >= (2 , 3 , 4 , 6);
+
+--Equal expression
+--a>2
+--or a=2 AND b>3
+--or a=2 AND b=3 AND 5>=4
+--or a=2 AND b=3 AND 5=4 and c>=6
+
+--After converted
+--a>2
+--or a=2 AND b>3
+--or a=2 AND b=3
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , 2 , b , 4 , 3 , c) >= (108 , 2 , b , 2 , 4 , 5);
+
+--Equal expression
+--a>108
+--or a=108 and 2>2
+--or a=108 and 2=2 and b>b
+--or a=108 and 2=2 and b=b and 4>2
+--or a=108 and 2=2 and b=b and 4=2 and 3>4
+--or a=108 and 2=2 and b=b and 4=2 and 3=4 and c>=5
+
+--After converted
+--a>108
+--or a=108 and b IS NOT NULL
+
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , 2 , b , 4 , 3 , c) >= (108 , 2 , b , 2 , 4 , 5) AND a = 108 AND b is NULL;
+
+--Only keep expr that is simple after converted.
+explain (costs off)
+SELECT * FROM self_a WHERE ROW(a , b, c) > (23, 34, 56) AND b = 34 AND c = 56;
+
+
+--Test row comparison under the or-expr is const true and the or-expr will be const true.
+explain (costs off)
+SELECT * FROM self_a WHERE (ROW(2,a,b) > (1,3,5) OR c < 345 AND a = 89) AND a < 150 OR c = 178;
+
+--
+-- Test scalar array operation expr
+--
+
+explain (costs off)
+SELECT * FROM self_a WHERE a <> ALL (array[2 , 3 , 4]) AND a = 2;
+
+explain (costs off)
+SELECT * FROM self_a WHERE a <> ALL (array[2 , 3 , 4]) AND a < 20;
+
+SELECT COUNT(*) FROM self_a WHERE a <> ALL (array[2 , 3 , 4]) AND a < 20;
+
+explain (costs off)
+SELECT * FROM self_a WHERE a <> ALL (array[2 , 3 , 4]) AND (a = 2 or a = 4);
+
+explain (costs off)
+SELECT * FROM self_a WHERE a <> ALL (array[2 , 2]) AND a = 2;
+
+explain (costs off)
+SELECT * FROM self_a WHERE a <> ANY (array[2 , 2]) AND a = 2;
+
+explain (costs off)
+SELECT * FROM self_a WHERE a < ALL (array[20 , 30 , 40]) AND a = 27;
+
+explain (costs off)
+SELECT * FROM self_a WHERE a < ALL (array[20 , 30 , 40]) AND a > 25;
+
+explain (costs off)
+SELECT * FROM self_a WHERE a < ALL (array[20 , 20]) AND a >= 25;
+
+explain (costs off)
+SELECT * FROM self_a WHERE a < ANY (array[20 , 30 , 40]) AND a >= 25;
+
+SELECT COUNT(*) FROM self_a WHERE a < ANY (array[20 , 30 , 40]) AND a >= 25;
+
+explain (costs off)
+SELECT * FROM self_a WHERE a < ANY (array[20 , 30 , 40]) AND a > 40;
+
+explain (costs off)
+SELECT * FROM self_a WHERE a < ANY (array[20 , 20]) AND a > 20;
+
+explain (costs off)
+SELECT * FROM self_a WHERE a = ALL (array[2 , 3]);
+
+explain (costs off)
+SELECT * FROM self_a WHERE a = ALL (array[54, NULL]);
+
+explain (costs off)
+SELECT * FROM self_a WHERE a = ALL (array[2 , 2]) AND a <> 2;
+
+explain (costs off)
+SELECT * FROM self_a WHERE a = ALL (array[27 , 27]) AND (a <> 27 OR a =27);
+
+explain (costs off)
+SELECT * FROM self_a WHERE a = ANY (array[2]) AND a <> 2;
+
+explain (costs off)
+SELECT * FROM self_a WHERE a = ANY (array[2 , 2]) AND a <> 2;
+
+explain (costs off)
+SELECT * FROM self_a WHERE a = ANY (array[2 , 3 , 4]) AND a < 2;
+
+explain (costs off)
+SELECT * FROM self_a WHERE a IN (2 , 3 , 4) AND a IN (5);
+
+explain (costs off)
+SELECT * FROM self_a WHERE a < ANY (array[1 , 2]) AND a > ANY (array[2 , 3]);
+
+explain (costs off)
+SELECT * FROM self_a WHERE a > ALL (array[2 , 3]) AND a <=3;
+
+explain (costs off)
+SELECT * FROM self_a WHERE a > ANY (array[2 , 3]) AND a <=3;
+
+explain (costs off)
+SELECT * FROM self_a WHERE a > ANY (array[2 , 3]) AND a <=2;
+
+explain (costs off)
+SELECT * FROM self_a WHERE a IN (58 , 32 , 4) AND a IN (1 , 32 , 6);
+
+explain (costs off)
+SELECT * FROM self_a WHERE a IN (58 , 32 , 4) AND a IN (1 , 3 , 6);
+
+explain (costs off)
+SELECT * FROM self_a WHERE a IN (1 , 2 , 3) AND a IN (1 , 3 , 6) AND a > 1;
+
+explain (costs off)
+SELECT * FROM self_a WHERE a > ANY (array[2 , 3]) AND a <=2 OR a = ANY (array[2 , 3]) AND a > 4;
+
+-- Test push scalar array expr down.
+
+explain (costs off)
+SELECT * FROM self_a WHERE a IN (89, 12, 219) AND (b > 50 OR c < 300 AND a IN (89, 121, 319));
+
+explain (costs off)
+SELECT * FROM self_a WHERE a IN (89, 12, 219) AND (b > 50 OR (c < 345 AND c < 78 OR a IN (89, 121, 319)));
+
+--
+-- Test push scalar array expr that operator is <> down.
+--
+
+explain (costs off)
+SELECT * FROM self_a WHERE a not in (89, 12, 219) AND (b > 50 OR c < 345 AND a = 89);
+
+explain (costs off)
+SELECT * FROM self_a WHERE a not in (89, 12, 219) AND (b > 50 OR (c < 345 AND c < 78 OR a = 89));
+
+explain (costs off)
+SELECT * FROM self_a WHERE a not in (89, 12, 219) AND (b > 50 and a = 12 OR (c < 345 AND c < 78 and a = 219 OR a = 89));
+
+
+--Test using binary search.
+explain (costs off)
+SELECT * FROM self_a WHERE a not in (89, 12, 219, 78, 69) AND (b > 50 and a = 12 OR (c < 345 AND c < 78 and a = 219 OR a = 89));
\ No newline at end of file
--
2.43.0.windows.1
view thread (7+ messages) latest in thread
reply
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Reply to all the recipients using the --to and --cc options:
reply via email
To: [email protected]
Cc: [email protected], [email protected]
Subject: Re: Self contradictory examining on rel's baserestrictinfo
In-Reply-To: <TYCPR01MB6093E2A06F3F8CF8DF17B5CE852E2@TYCPR01MB6093.jpnprd01.prod.outlook.com>
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox